性能优化——使用多线程加速Halcon深度学习算子

性能优化——使用多线程加速Halcon深度学习算子,第1张

可以用Halcon建立深度学习模型,并用到实际项目中。

流程大概是使用免费的 Halcon Deeplearing Label Tool制作模型后,导出成 hdl 文件,并在应用程序中用 ApplyDlClassifier 应用模型。

经过测试, ApplyDlClassifer 在第一次运行时,无论数据集有多大,执行时间在500ms左右(AMD 5800X + Nvidia P2200),能够明显感受到卡顿,而在第二次运行时,就感受不到卡顿。所以我考虑,在应用程序启动时,使用线程对模型进行预热。

预热听着高深,其实就是读取模型( ReadDlClassifier ) 并送入一张空白图。

下面演示我的做法:

21 封装一个自己的Application类

22 我将Halcon算子封装成一个单例类,并使用 getAlgorithmGlobalData 获得这个单例对象。 slotDoModelWarmUp 是这个单例类一个槽函数。

23 在 slotDoModelWarmUp 中开多线程,对模型进行预热。

我将Halcon深度学习算子要用到的变量封装成一个 context 结构体,放在单例类中。为了节约开销,我使用引用,直接获取这个单例对象。这样,在向线程中传参数时,需要一个 std::ref 。

线程函数如下:

classifierHandle 是一个引用变量,这使得我可以直接 *** 控单例类中的数据成员,而不是使用拷贝。

经过测试,在AMD 5800X + Nvidia P2200下,推理速度达到了1166ms。

从Halcon到VC++

read_image(&Image,"文件名");//读入的为灰度图像

//获取图像指针,注意输出变量的类型

char lpcsType[MAX_STRING];

Hlong Pointer,Width, Height;

get_image_pointer1(Image, &Pointer, lpcsType, &Width, &Height);

//Halcon与VC++中的图像之间,存在着上下翻转

BYTE lpByte;

BYTE ImageG;

int bytewidth;

bytewidth = ((long) Width 3 + 3 ) / 4 4 ;

ImageG = NULL ;

ImageG = new BYTE[ bytewidth (long) Height ];

lpByte = (BYTE ) Pointer; //注意结合图像像素存储的类型进行定义

int i,j;

for( j = (long)Height-1; j>=0; j--)

{ //(注意tuple中图像数据的存放和VC中的差别)

for( i = 0; i < (long)WidthGray; i++)

{

(ImageG + j bytewidth + i 3 + 0 ) = lpByte ;

(ImageG + j bytewidth + i 3 + 1 ) = lpByte ;

(ImageG + j bytewidth + i 3 + 2 ) = lpByte ;

lpByte++;

}

}

BITMAPINFO RotateBmpInfo;

BYTE bitBuffer;

bitBuffer = NULL;

bitBuffer = new BYTE[sizeof(BITMAPINFO)];

RotateBmpInfo = (BITMAPINFO )bitBuffer;

RotateBmpInfo->bmiHeaderbiSize = sizeof(BITMAPINFOHEADER);

RotateBmpInfo->bmiHeaderbiHeight = Height;

RotateBmpInfo->bmiHeaderbiWidth = Width;

RotateBmpInfo->bmiHeaderbiPlanes = 1;

RotateBmpInfo->bmiHeaderbiBitCount = 24;

RotateBmpInfo->bmiHeaderbiCompression = BI_RGB;

RotateBmpInfo->bmiHeaderbiSizeImage = Height bytewidth;

RotateBmpInfo->bmiHeaderbiXPelsPerMeter= 0;

RotateBmpInfo->bmiHeaderbiYPelsPerMeter= 0;

RotateBmpInfo->bmiHeaderbiClrUsed = 0;

RotateBmpInfo->bmiHeaderbiClrImportant = 0;

CWnd m_pWnd ;

m_pWnd = AfxGetApp()->GetMainWnd();

CDC pDC = m_pWnd->GetDC();

::StretchDIBits(

pDC->GetSafeHdc(),

Width + 10,

Height + 10,

Width, //显示窗口宽度

Height, //显示窗口高度

0,

0,

Width, //图像宽度

Height, //图像高度

ImageG,

RotateBmpInfo,

DIB_RGB_COLORS,

SRCCOPY);

m_pWnd->ReleaseDC(pDC);

delete [] ImageG ;

delete [] bitBuffer ;

2 从VC++到Halcon

unsigned char Pointer;

int width, height;

Pointer = new unsigned char[width height];

int i, j;

for (i=0; i<height; i++)

{

for (j=0; j<width; j++)

{

Pointer[iwidth+j] = j % 255;

}

}

Hobject Image;

gen_image1_extern(&Image, "byte", (HTuple)width, (HTuple)height, (long)Pointer, NULL);

注:

a) gen_image1_extern函数中的变量width,height必须为HTuple类型,Pointer指针为unsigned char类型,输入时转换为long型。

b) width, height必须与Pointer指向的图像数据的长宽一致。

c) Pointer指针在gen_image1_extern函数调用之前分配了内存,之后不要马上释放,否则会出错。应该在确保不再使用Image变量之后再释放。halcon内部会自动释放Image,感觉没有释放Pointer(还需要进一步验证)。

d) 显示图像时,可能存在着图像的上下翻转,可以按照1中的方法,将图像数据翻转后再调用gen_image1_extern,或者使用halcon中的函数mirror_image()进行翻转。

3 在VC界面中建立图像窗口

Hlong lWWindowID;

HTuple WindowHandle;

lWWindowID = (Hlong)m_hWnd; //要显示的控件的句柄

set_window_attr("border_width",0); //设置窗口属性

set_window_attr("background_color","light gray"); //设置窗口背景颜色

set_check("~father");

open_window(0,0,m_Width,m_Height,lWWindowID,"visible","",&WindowHandle); //创建窗口

set_check("father");

set_part(WindowHandle,0,0,m_Width-1,m_Height-1); //对窗口上显示图像和区域的一些设置

set_draw(WindowHandle,"margin");

set_colored(WindowHandle,12);

disp_obj(Image,WindowHandle); //显示图像Image(Hobject类型)

4 从HTuple类型读取数据

//HTuple有一个元素

HTuple aa = 120;

double dd = aa[0]D(); // dd=120000

int ii = aa[0]I(); //ii=120

long ll = aa[0]L(); //ll=120

Hlong hh = aa[0]L();//hh=120

long num = aaNum(); //num =1;

aa = "120"; //HTuple为字符串时,如果赋值不是字符串,不能调用S()函数

const char cc;

cc = aa[0]S(); //cc[0]='1',cc[1]='2',cc[2]='0'

//当aa为多元素的数组时

aa[1] = 230;

num = aaNum(); //num =2;

ii = aa[1]I(); //ii=230 //其他获取数据的方法与上面类似

halcon的模板匹配可以归为三类:

1、基于灰度:灰度,互相关ncc

2、基于形状:形状,组件

3、基于描述符:描述匹配

应用场合:定位对象内部的灰度值没有大的变化,没有缺失部分,没有干扰图像和噪声的场合。

1创建模板:create_template()

2寻找模板:best_match()

3释放模板:clear_template()

应用场合:搜索对象有轻微的变形,大量的纹理,图像模糊等场合,速度快,精度低。

1创建模板:create_ncc_model()

2寻找模板:find_ncc_model(),find_ncc_models()

3释放模板:clear_ncc_model()

4get_ncc_model_region (ModelRegion, ModelID)

smallest_rectangle2 (ModelRegion, Row3, Column3, Phi, Length1, Length2)

应用场合:组件匹配是形状匹配的扩展,但不支持大小缩放匹配,一般用于多个对象(工件)定位的场合。

算法步骤:

1获取组件模型里的初始控件 gen_initial_components()

参数:

ModelImage [Input] 初始组件的

InitialComponents [Output] 初始组件的轮廓区域

ContrastLow [Input] 对比度下限

ContrastHigh [Input] 对比度上限

MinSize [Input] 初始组件的最小尺寸

Mode[Input] 自动分段的类型

GenericName [Input] 可选控制参数的名称

GenericValue [Input] 可选控制参数的值

2根据图像模型,初始组件,训练来训练组件和组件相互关系 train_model_components()

3创建组件模型 create_trained_component_model()

4寻找组件模型 find_component_model()

5释放组件模型 clear_component_model()

应用场合:定位对象内部的灰度值可以有变化,但对象轮廓一定要清晰平滑。

1创建形状模型:create_shape_model()

2寻找形状模型:find_shpae_model()

3释放形状模型:clear_shape_model()

应用场合:搜索对象有轻微的变形。

1创建模板:create_local_deformable_model()

2寻找模板:find_local_deformable_model()

3释放模板:clear_deformable_model()

应用场合:搜索对象有轻微的变形,透视的场合,根据一些描述点的位置和灰度值来进行匹配。

1创建模板:create_calib_descriptor_model()

2寻找模板:find_calib_descriptor_model()

3释放模板:clear_descriptor_model()

UNX的一些小技巧! tip1 您可以双击在资源条中的导航器或调色板标签,以使它们跳出去并可单独放置。 tip2 当作草图时,点线显示与其它对象对齐,虚线显示可能的约束。 使用 mb2 来锁定所建议的约束。 tip3 在制图中 - 没有活动的对话框时,您可以拖动尺寸来移动其原点并自动判断其指引线侧。 tip4 您可以按住 mb2 并拖动来旋转视图。 使用 shift+mb2 (或 mb2+mb3)来平移。 使用 ctrl+mb1 (或 mb1+mb2) 来放大/缩小。 甚至滑轨式鼠标都可用来缩放! tip5 在草图轮廓,您可以通过按/拖 mb1 来从画直线切换到划弧。 移动光标通过各象限来获取所需要的弧。 tip6 在制图中,您可以在线性尺寸上用 shift-拖动来创建狭窄型尺寸。 tip7 可以在任何时候双击动态工作坐标系来将其激活! 一旦被激活,您可以使用捕捉点来拖动原点,或者您可以沿轴方向来拖动,或者您可以旋转。 您也可以双击一条轴使方向逆反。 tip8 在草图约束中,在选择要约束的曲线之后,系统将显示可用约束的列表。 已经应用的约束将显示为灰色。 您还可以从 mb3 d出菜单上选择约束。 tip9 在制图中,动画图纸创建可以通过将先前生成的图纸模板拖动到资源条的模型中来获得。 tip10 您可以选择将资源条放在屏幕一侧 - 左侧或右侧。 走到预设置->用户界面-资源条来改变它。 tip11 在草图约束,在应用约束之后使用 ctrl-mb1 以保持选择了的对象。 这允许您很容易地应用多个约束,例如:平行和等长度同时使用。 tip12 在制图中,双击任何尺寸或注释来编辑其内容。 您也可以从 mb3 d出菜单来选择其它 *** 作。 tip13 通过与最大化的 unigraphics 一起运行,您可以方便地访问导航器和调色板,只需移动鼠标到屏幕的该侧即可。 您也可以在标签上点击来激活它们。 现在试一下! tip14 在草图,一些约束总是被显示,包括重合、在曲线上的点、中点、相切和同心的。 其它的可以通过打开“显示更多约束”来显示。 如果相关几何体太小,约束不显示。 要看到任何比例的所有约束,关闭设置“动态约束显示”。 要关闭所有约束,使用在草图约束工具条上的“不显示约束”的命令。 tip15 现在当您打开包括图纸的部件时可以选择特定的。 tip16 您可以引导组件如何装配,使其在拖动组件到图形窗时易于与组件匹配。 只要在选择装配条件之后使用在装配对话框中的 mb3 d出菜单即可。 tip17 在草图中,您可以通过拖动尺寸原点来将其直接地移动到新位置。 双击尺寸来编辑其值或名称。 尺寸输入字段将显示如所示。 表达式可以被键入到该值字段。 tip18 您知道图纸上的圆视图边界现在具有不同的显示表示吗? tip19 当平移工作坐标系时通过向下按住 alt 键,您可以执行精确定位。 tip20 屏幕一侧包括导航器和调色板的区域被称为资源条。 试一试将鼠标移到它上面看看会发生什么。 tip21 如果您在设置/用户界面/资源条指定主页的 url,浏览窗口将在资源条出现,让您容易访问该网页

以上就是关于性能优化——使用多线程加速Halcon深度学习算子全部的内容,包括:性能优化——使用多线程加速Halcon深度学习算子、如何用C++调用halcon函数 (最好能详细点,谢谢)、halcon模板匹配总结等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/9779446.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-01
下一篇 2023-05-01

发表评论

登录后才能评论

评论列表(0条)

保存