VPLC系列机器视觉运动控制一体机快速入门(三)

发布时间:2024-09-29  

今天,正运动技术为大家分享一下VPLC系列机器视觉运动控制一体机快速入门(三)——基于形状匹配的视觉定位。

运动控制

上期课程,我们讲述了机器视觉方案实施的基础即相机的基本使用内容,我们通过上期课程已经能实现使用ZDevelop软件获取图像进行处理。

本期课程我们和大家一起分享机器视觉方案中常用的基于形状匹配的视觉定位功能。



运动控制


视觉定位是指在视觉检测中通过学习特定的模板或某些固定的特征,在检测区域内搜索满足条件的特征,并返回特征在图像坐标中的位置信息,如坐标位置X、坐标位置Y、角度。



运动控制


形状匹配是基于边缘方向梯度的匹配,它是提取ROI中的边缘特征结合灰度信息创建模板,然后在检测区域ROI范围内搜索与模板的轮廓特征满足一定相似程度的产品特征,并返回对应位置信息。



运动控制

形状匹配特点

1.适应性强:可适应光照和图像的灰度变化。

2.兼容性强:可以支持搜索缺失局部边缘、有噪声干扰、有轻微变形和失焦的目标。

3.多目标搜索:支持同时搜索同一模板下的多个匹配目标。

4.支持旋转和缩放:在目标图像存在旋转或缩放的情况下仍然能匹配到目标,但是需要在设定的旋转和缩放比例范围内。

模板选择

使用形状匹配功能的前提是检测目标要有唯一且固定的特征。

1.在选择模板时,需要确保特征是检测目标唯一存在的特征,否则无法与其他检测目标区分。

2.尽量选择图像清晰形状完整的标准产品作为模板,避免掺入噪点等干扰因素。

3.尽量避免选择对称的特征作为模板。



运动控制


如图,闪电是目标1唯一的特征,可以将目标1和目标2进行区分。



运动控制


1 目标定位



运动控制


在目标轮廓特征清晰且定位精度要求不高时,可直接使用形状匹配输出的位置结果做定位项目。

2 产品计数



运动控制


对具有相同形状特征的产品进行计数统计。

3 位置跟随



运动控制


当需要检测的目标位置不固定时,一些检测功能的ROI位置无法确定如检测直线、检测圆形等,我们可以利用检测目标周边有固定距离的特征进行位置跟随。



运动控制


运动控制

形状匹配流程图

实例演示

1

新建项目→新建HMI文件→新建main.bas文件,用于编写界面响应函数→新建global_variable.bas文件用于存放全局变量并开启HMI自动运行任务→新建InitLocator.bas文件用于初始化测量参数→新建camera.bas文件用于实现相机采集功能→新建draw.bas文件用于更新绘制图形刷新界面→文件添加到项目。



运动控制


2

设计主界面。



运动控制


3

在global_variable.bas文件中定义全局变量。

'''''全局变量大部分使用数组结构'''''

''注:basic编程中很多函数会以TABLE(系统的数据结构)做为参数

''在这里table均是做为中间变量

''table 0-20 作为匹配时使用到的中间变量

''table 50-70 作为roi绘制时的中间变量使用

''table 21-22,表示鼠标按键控件坐标系

''table 31-35,表示控件坐标转换后对应的图像坐标

''table 111-114,表示定位器区域roi参数,属于控件坐标系

''table 121-124,表示橡皮擦区域roi参数,属于控件坐标系

'***********定义程序任务相关变量**********************

'主任务状态

'0 - 未初始化

'1 - 停止

'2 - 运行中

'3 - 正在停止

GLOBAL DIM main_task_state

main_task_state = 1

'运行任务开关

GLOBAL DIM run_switch

run_switch = 0

'采集任务开关

'0 - 停止采集

'1 - 请求采集

GLOBAL DIM grab_switch

grab_switch = 0

'定位检测主任务id - 10

GLOBAL DIM main_task_id

main_task_id = 10

'相机连续采集线程id - 7

GLOBAL DIM grab_task_id

grab_task_id = 7

'***********结束定义程序任务相关变量******************

'***********定义相机采集相关变量**********************

'相机种类,'',此处使用海康相机-'mvision'

GLOBAL DIM CAMERA_TYPE(100)

'CAMERA_TYPE = 'mindvision;basler;mvision;huaray;basler;zmotion'

CAMERA_TYPE = 'mvision'

'相机个数

GLOBAL cam_num

cam_num = 0

'相机模式,-1 连续采集,0-触发采集

GLOBAL cam_mode

cam_mode = 0

'***********结束定义相机采集相关变量******************

'定义返回主界面标志,1-已返回,0-未返回

GLOBAL DIM d_is_rtn_loc

d_is_rtn_loc = 1

'***********定义模板相关变量*************************

'定义创建模板标志位,1-已创建模板,0-未创建模板

GLOBAL DIM d_is_creModel

d_is_creModel = 0

'学习模板参数,starAngle、endAngle、minScale、maxScale、thresh、numlevel、reduce、angleStep、scaleStep

GLOBAL DIM d_mod_param(9)

'***********结束定义模板相关变量**********************

'***********定义编辑模板相关变量*********************

'定义编辑模板标志,0-表示不编辑模板,1-表示编辑模板

GLOBAL DIM d_edit_m

d_edit_m = 0

'定义使用橡皮擦功能标志,0-表示恢复擦除的区域,1-表示擦除区域

GLOBAL DIM d_isMask_m

d_isMask_m = 1

'定义橡皮擦的roi参数,依次是矩形左上角和右下角图像坐标x、y、x、y

GLOBAL DIM d_locator_roi(4),d_eraser_roi(4)

'定义正方形橡皮擦尺寸宽度

GLOBAL DIM d_eraser_size

d_eraser_size = 5

'定义界面控件上橡皮擦的矩形区域

GLOBAL DIM c_rect(4)

'定义鼠标状态标志,0-表示鼠标处于松开状态,1-表示鼠标处于按下状态

GLOBAL DIM d_mouse_s

d_mouse_s = 0

'***********结束定义编辑模板相关变量******************

'***********定义匹配检测相关变量*********************

'匹配检测参数,minScore、matchNum、minDist、thresh、accuracy、speed、polor

GLOBAL DIM d_match_param(7)

'定义学习模板的roi参数和橡皮擦的roi参数,依次是矩形左上角和右下角图像坐标x、y、x、y

GLOBAL DIM d_locator_roi(4),d_eraser_roi(4)

'匹配结果,score、x、y、angle、scale, 目前对于多目标匹配也只存第一个目标

GLOBAL DIM d_match_rst(5)

GLOBAL DIM d_match_time '定义匹配定位消耗的时间变量

d_match_time = 0

'***********结束定义匹配检测相关变量******************

'定义程序执行过程中缓存中间图片和结果图片的变量

GLOBAL ZVOBJECT grabImg

GLOBAL ZVOBJECT subImg,copy_subImg,colorSubImg, s_mod

GLOBAL ZVOBJECT modRe

RUN'Hmi1.hmi',1

4

在InitLocator.bas文件中初始化测量参数。

end

GLOBAL SUB init_meas_param() '初始化测量参数

'初始化定位器roi参数

d_locator_roi(0) = 240 '左上角x

d_locator_roi(1) = 180 '左上角y

d_locator_roi(2) = 400 '右下角x

d_locator_roi(3) = 300 '右下角y

'初始化模板参数

d_mod_param(0) = -180 '起始角度

d_mod_param(1) = 180 '终止角度

d_mod_param(2) = 1 '最小缩放

d_mod_param(3) = 1 '最大缩放

d_mod_param(4) = 80 '阈值

d_mod_param(5) = 0 '默认金字塔层数

d_mod_param(6) = 0 '默认约简特征点

d_mod_param(7) = 0 '默认角度步长

d_mod_param(8) = 0 '默认缩放步长

'初始化匹配测量参数

d_match_param(0) = 50 '最小分数

d_match_param(1) = 1 '匹配个数

d_match_param(2) = 0 '默认最小间距

d_match_param(3) = 40 '最小阈值

d_match_param(4) = 0 '精度

d_match_param(5) = 9 '速度

d_match_param(6) = 0 '极性

'初始化匹配定位结果

d_match_rst(0) = 0 '分数

d_match_rst(1) = 0 '位置X

d_match_rst(2) = 0 '位置Y

d_match_rst(3) = 0 '角度

d_match_rst(4) = 0 '比例

'初始化匹配定位消耗时间

d_match_time = 0

END SUB

5

关联主界面值显示控件变量。



运动控制


6

在main.bas文件中添加主界面初始化函数。

'HMI界面初始化函数,上电执行一次

GLOBAL SUB hmi_init()

grab_switch = 0 '初始化采集任务开关,不开启采集任务

main_task_state = 1 '初始化定位检测主任务状态为停止状态1

ZV_LATCHSETSIZE(0, HMI_CONTROLSIZEX(10, 2), HMI_CONTROLSIZEY(10, 2)) '设置锁存的大小

init_meas_param() '初始化测量参数

ZV_IMGGENCONST(subImg,40,30,1,0,0) '初始化模板子图像

'初始化一些全局参数

ZVOBJECT contlist1, tsContlist1, mat_rigid1

ZVOBJECT contlist2, tsContlist2, mat_rigid2

ZV_READIMAGE(grabImg,'1.bmp',1) '读取.../flash目录下的show.bmp的灰度图像,存放到grabImg变量中

ZV_LATCH(grabImg,0) '显示到锁存通道0中,作为显示区域背景图片

END SUB

7

在camera.bas文件中添加主界面中采集相关按钮响应的函数并关联动作函数。



运动控制


end

'主界面按下扫描相机按钮时响应的函数

GLOBAL SUB cam_scan_all()

ZV_SETSYSINT('LogLevel', 7) '设置控制器信息

ZV_SETSYSSTR('DataDir','')

CAM_SCAN(CAMERA_TYPE) '扫描相机,CAMERA_TYPE='mvision'

cam_num = CAM_COUNT() '获取扫描到的相机数量

if (0 = cam_num) then '如果相机数量=0,打印提示信息

? '未找到相机'

return '退出子函数,不往下执行

endif

?'cam_num = ' cam_num '如果扫描到相机,打印相机数量

cam_mode = 0 '设置软触发采集

CAM_SEL(0) '选择扫描到的第一个相机进行操作

CAM_SETEXPOSURE(100000) '设置相机曝光时间为100000us

CAM_SETMODE(cam_mode) '设置软件触发模式

CAM_START(0) '开启相机

END SUB

'主界面按下单次采集按钮执行的函数

GLOBAL SUB btn_grab()

if cam_num = 0 then

?'请先扫描相机!'

return

endif

CAM_SETPARAM('TriggerSoftware', 0)

CAM_GET(grabImg, 0)

ZV_LATCH(grabImg, 0)

ZV_IMGINFO(grabImg,3000) '获取grabImg变量缓存的图片的基本信息,并存放到起始地址为3000的table数组中

end sub

'主界面按下连续采集按钮响应的函数

GLOBAL SUB btn_cgrab()

if grab_switch =1 then

?'正在连续运行中,请勿重复操作!'

return

endif

if cam_num = 0 then

?'请先扫描相机!'

return

endif

grab_switch = 1

if (1 = grab_switch) then

if (0 = PROC_STATUS(grab_task_id)) then

RUNTASK grab_task_id, grab_task

endif

endif

end sub

'采集任务实现函数

grab_task:

while(1)

if (0 = grab_switch) then

exit while

endif

CAM_START(0) '开启相机

CAM_SETPARAM('TriggerSoftware', 0)

CAM_GET(grabImg, 0)

ZV_LATCH(grabImg, 0)

wend

END

'主界面按下停止采集按钮响应的函数

GLOBAL SUB btn_stopCgrab()

if grab_switch =0 then

?'未开启连续采集!'

return

endif

grab_switch = 0

end sub



运动控制


8

点击[元件]→[新建窗口],新建学习模板窗口,设计窗口布局。



运动控制


注意:需要设置窗口垄断属性。

9

在draw.bas文件中添加主界面【学习模板】按钮响应的函数并关联动作函数。



运动控制

'主界面按下学习模板按钮时响应的函数

GLOBAL SUB btn_sel_loc()

ZV_LATCHSETSIZE(0, HMI_CONTROLSIZEX(11, 60), HMI_CONTROLSIZEY(11, 60)) '设置创建模板窗口锁存通道0的锁存大小

SET_COLOR(RGB(0,255,0)) '指定draw指令使用的颜色

ZV_LATCHCLEAR(0) '将锁存通道0清空

ZV_LATCH(grabImg, 0) '显示采集图像显示到锁存通道0中

ZV_LATCH(colorSubImg, 1) '显示模板图像显示到锁存通道1中

'图像roi坐标转控件roi

is_redraw = 0

d_is_rtn_loc = 0

TABLE(111, d_locator_roi(0), d_locator_roi(1),d_locator_roi(2),d_locator_roi(3))

ZV_POSFROMIMG(0, 2, 111, 111) '图像坐标转换到HMI控件坐标

HMI_SHOWWINDOW(11)

END SUB


运动控制


10

在draw.bas文件中添加模板区域更新绘制函数。

'根据鼠标操作更新定位器的区域即学习模板的有效区域

GLOBAL SUB update_locator()

if mouse_scan(21) = 1 then '扫描鼠标按下操作

is_set_roi_m_down = 1

sr_mpos_x = table(21)

sr_mpos_y = table(22)

hit_pos = ZV_HMIADJRECT(sr_mpos_x, sr_mpos_y, 111, -1) '只有按下时可以改变击中位置

is_redraw = 1

endif

if mouse_scan(21) = -1 then '扫描鼠标松开操作

is_set_roi_m_down = 0

sr_mpos_x = table(21)

sr_mpos_y = table(22)

ZV_HMIADJRECT(sr_mpos_x, sr_mpos_y, 111, hit_pos)

is_redraw = 1

endif

if (is_set_roi_m_down and MOUSE_state(21)) then

sr_mpos_x = table(21)

sr_mpos_y = table(22)

ZV_HMIADJRECT(sr_mpos_x, sr_mpos_y, 111, hit_pos)

is_redraw = 1

endif

if (1 = is_redraw) then

'控件roi坐标转图像roi坐标

is_redraw = 0

ZV_POSTOIMG(0, 2, 111, 50) 'TABLE(50)作为中间变量临时使用

d_locator_roi(0) = TABLE(50)

d_locator_roi(1) = TABLE(51)

d_locator_roi(2) = TABLE(52)

d_locator_roi(3) = TABLE(53)

SET_REDRAW

endif

END SUB

'根据更新的鼠标位置坐标绘制定位器roi

GLOBAL SUB draw_locator()

DRAWRECT(TABLE(111), TABLE(112), TABLE(113), TABLE(114))

local cx,cy

cx = (TABLE(111) + TABLE(113)) / 2

cy = (TABLE(112) + TABLE(114)) / 2

DRAWLINE(cx-5, cy, cx+5, cy) '中心十字线

DRAWLINE(cx, cy-5, cx, cy+5)

END SUB

11

在main.bas文件中添加【截取模板】按钮响应的函数并关联动作函数。



运动控制

'创建模板界面按下截取模板按钮后响应的函数

global sub btn_getSubImg()

LOCAL mod_w,mod_h

ZV_IMGGETSUB(grabImg, subImg, d_locator_roi(0), d_locator_roi(1), d_locator_roi(2)-d_locator_roi(0)+1, d_locator_roi(3)-d_locator_roi(1)+1)

ZV_IMGINFO(subImg,0)

mod_w = TABLE(0)

mod_h = TABLE(1)

ZV_REGENRECT(modRe,0,0,mod_w, mod_h)

ZV_LATCHCLEAR(1)

ZV_LATCH(subImg, 1)

end sub


运动控制


12

点击[元件]→[新建窗口],新建编辑模板窗口,设计窗口布局。



运动控制


注意:需要设置窗口垄断属性。

13

在draw.bas文件中添加创建模板界面【橡皮擦】按钮响应的函数并关联动作函数。



运动控制

'创建模板界面按下橡皮擦按钮时响应的函数

GLOBAL SUB btn_sel_erase()

ZV_LATCHSETSIZE(1, HMI_CONTROLSIZEX(12, 1), HMI_CONTROLSIZEY(12, 1)) '设置锁存的大小

SET_COLOR(RGB(0,255,0)) '设置绘制时画笔使用的颜色

ZV_LATCHCLEAR(1) '清空锁存

ZV_IMGCOPY(subImg, copy_subImg) '复制模板子图像到copy_subImg图像变量中

ZV_REGION(copy_subImg, modRe, 1, 0) '在模板图像上绘制modRe图像的非有效区域,绘制颜色为黑色,用于掩模

ZV_LATCH(copy_subImg, 1) '显示复制的模板图

HMI_SHOWWINDOW(12) '打开编辑模板窗口

end sub


运动控制


14

在draw.bas文件中添加橡皮擦更新绘制函数。

'根据鼠标操作更新橡皮擦擦除/恢复区域的位置

GLOBAL SUB update_eraser()

DIM c_size_eraser '橡皮擦在控件上对应的尺寸

DIM eraser_pos_x,eraser_pos_y

d_mouse_s = MOUSE_STATE(21) '鼠标处于按下状态时

eraser_pos_x = TABLE(21)

eraser_pos_y = TABLE(22)

c_size_eraser = ZV_LENFROMIMG(0, d_eraser_size) '将橡皮擦的图像尺寸转换成控件尺寸

c_rect(0, eraser_pos_x - c_size_eraser, eraser_pos_y - c_size_eraser, eraser_pos_x + c_size_eraser, eraser_pos_y + c_size_eraser)

'绘制以(eraser_pos_x,eraser_pos_y)为中心,2*c_size_eraser为边长的正方形橡皮擦区域

DIM hmi_w,hmi_h

if (eraser_pos_x >= c_size_eraser) and (eraser_pos_y >= c_size_eraser) and (eraser_pos_x <= HMI_CONTROLSIZEX(12, 1) - c_size_eraser)and (eraser_pos_y <= HMI_CONTROLSIZEy(12, 1) - c_size_eraser) THEN

SET_REDRAW(0,0, HMI_CONTROLSIZEX(12, 1), HMI_CONTROLSIZEY(12, 1))'重新绘制编辑模板窗口上的锁存通道0区域

endif

if d_mouse_s = 1 and d_edit_m = 1 then '如果鼠标处于按下状态且编辑模板标志=1时

btn_pro_eraser() '执行处理橡皮擦函数

endif

END SUB

'处理橡皮擦函数

global sub btn_pro_eraser()

ZVOBJECT tmp_re

TABLE(121, c_rect(0), c_rect(1))

ZV_POSTOIMG(1, 1, 121, 121)

ZV_REGENRECT(tmp_re, TABLE(121), TABLE(122), 2 * d_eraser_size + 1, 2 * d_eraser_size + 1)

if (d_isMask_m = 1) then '屏蔽

ZV_REDIFF(modRe, tmp_re, modRe) '计算modRe和tmp_re的差集并存放到modRe中

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>