嵌入式
返回首页

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

2024-09-26 来源:elecfans

此前,我们依次讲解了软硬件介绍及计数实例、相机的基本使用、基于形状匹配的视觉定位以及BLOB有无检测等。


今天,正运动技术为大家分享一下VPLC系列机器视觉运动控制一体机快速入门(五),和大家一起分享机器视觉常用的检测功能---测量尺寸。


运动控制


测量尺寸:在机器视觉中常用的测量尺寸的原理就是使用两个直线测量器,分别检测出产品两条尺寸边缘的点拟合成直线后取两条直线的距离。

尺寸测量本质是基于边缘检测的测量,它需要先检测出亮暗过渡满足一定阈值的边缘点,然后再提取边缘点数据进行处理计算后输出最终的结果。


测量尺寸特点


1.准确度高

选择合适的硬件选型方案可以达到很高的检测精度。常用远心镜头减少畸变,增大景深,减小测量误差。

2.图像干扰少

单纯的测量尺寸项目常用背光的打光方式,突出产品边缘尺寸,过滤表面干扰因素。

3.实现简单

测量尺寸的算法是基于边缘检测的算法,易于实现。

4.需要位置跟随

测量尺寸的测量器本身不具有定位功能,如果检测产品位置不固定将无法确定测量器对应的位置,此时需要依赖匹配等定位功能做位置跟随。

标定


标定是指将机器视觉处理的像素结果(单位:像素)转换成现实中使用到的实际结果(单位:毫米),或者是将机器视觉中使用的图像坐标转换成世界坐标。

我们在实际测量尺寸时,使用的尺寸单位一般是国际标准单位如米,厘米,毫米等。因此机器视觉测量尺寸项目中需要将获取到的像素尺寸转换成实际尺寸(毫米)输出到用户端,供用户直接使用。


测量尺寸标定方法


1.测量标定

使用已知尺寸的标准模块如圆、小方块、或刻度尺等,在图像中检测到像素尺寸后将已知实际尺寸值除以像素值即可得出像素比例值(单位:mm/pixel)。测量尺寸项目中常用测量标定方法。



运动控制

2.坐标标定

输入几组图像坐标(至少9组),然后再输入图像坐标对应的世界坐标,经过公式计算得出矩阵变换系数,即可实现将图像坐标转换到实际坐标。在测量精度要求比较高的测量尺寸项目可以考虑使用坐标标定,具体实现内容我们在下一期课程再做详细说明。



运动控制


1.打开ZDevelop软件:打开项目“基于形状匹配的视觉定位”→在global_variable.bas文件中定义测量尺寸需要用到的全局变量。


'----------------------------分割线-----------------------------------------

'直线1测量参数数组,依次为中心cx、cy、w、h、angle、interp、sub_num、sub_width、filter_size、thresh、polor、select,都是图像坐标

GLOBAL DIM d_meas_param1(12) 'd开头表示数据结构

'直线2测量参数数组,依次为中心cx、cy、w、h、angle、interp、sub_num、sub_width、filter_size、thresh、polor、select,都是图像坐标

GLOBAL DIM d_meas_param2(12) 'd开头表示数据结构

'定义常用颜色变量,用于绘制图形

GLOBAL C_RED, C_GREEN, C_BLUE, C_YELLOW

C_RED = RGB(255, 0, 0)

C_GREEN = RGB( 0,255, 0)

C_BLUE = RGB( 0, 0,255)

C_YELLOW= RGB(255,255, 0)

'创建模板时保存的直线1基准区域位置向量1,x、y、angle

GLOBAL DIM d_meas_base_v1(3)

d_meas_base_v1(0) = 0

d_meas_base_v1(1) = 0

d_meas_base_v1(2) = 0

''创建模板时保存的直线2基准区域位置向量2,x、y、angle

GLOBAL DIM d_meas_base_v2(3)

d_meas_base_v2(0) = 0

d_meas_base_v2(1) = 0

d_meas_base_v2(2) = 0

'直线1测量结果,依次为结果点stx、sty、endx、endy

GLOBAL DIM d_meas_rst1(4)

'直线2测量结果,依次为结果点stx、sty、endx、endy

GLOBAL DIM d_meas_rst2(4)

'定义显示在界面上的长度变量

GLOBAL DIM d_show_rst

''创建模板时保存的模板基准点,score、x、y、angle、scale

GLOBAL DIM d_match_base_rst(5)

global dim d_meas_param(12)

'定义测量标定时使用到的变量

GLOBAL PixLength,WorldLength,CalibParam

2.补充设计主界面。



运动控制


3.新建主界面按下【测量设置】按钮时弹出的测量参数设置窗口“Set_Select”,并设计界面布局。



运动控制


4.在main.bas文件中添加主界面按下【测量设置】按钮时响应的函数并关联动作函数名。

'主界面按下测量设置按钮时响应的函数

GLOBAL SUB Goto_Meas()

HMI_SHOWWINDOW(13)

END SUB



运动控制


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

'---------------------分割线------------------

'初始化测量参数1

d_meas_param1(0) = 320.0 'roi中心x

d_meas_param1(1) = 240.0 'roi中心y

d_meas_param1(2) = 160 'roi宽

d_meas_param1(3) = 120.0 'roi高

d_meas_param1(4) = 0.0 'roi角度

d_meas_param1(5) = 1 '插值方式

d_meas_param1(6) = 20 '子区域的个数

d_meas_param1(7) = 5 '子区域的尺寸

d_meas_param1(8) = 3 '滤波尺寸

d_meas_param1(9) = 50 '阈值

d_meas_param1(10) = 0 '极性

d_meas_param1(11) = 0 '选择边缘位置

'初始化测量参数2

d_meas_param2(0) = 320.0 'roi中心x

d_meas_param2(1) = 240.0 'roi中心y

d_meas_param2(2) = 160 'roi宽

d_meas_param2(3) = 120.0 'roi高

d_meas_param2(4) = 0.0 'roi角度

d_meas_param2(5) = 1 '插值方式

d_meas_param2(6) = 20 '子区域的个数

d_meas_param2(7) = 5 '子区域的尺寸

d_meas_param2(8) = 3 '滤波尺寸

d_meas_param2(9) = 50 '阈值

d_meas_param2(10) = 0 '极性

d_meas_param2(11) = 0 '选择边缘位置

'初始化界面上显示的结果值

d_meas_rst1(0) = 0

d_meas_rst1(1) = 0

d_meas_rst1(2) = 0

d_meas_rst1(3) = 0

d_meas_rst2(0) = 0

d_meas_rst2(1) = 0

d_meas_rst2(2) = 0

d_meas_rst2(3) = 0

d_show_rst = 0

'初始化标定参数和像素比例

CalibParam = 0

WorldLength = 0

PixLength = 0

6.新建在“Set_Select”窗口界面按下【选择测量器区域1】按钮时弹出的“Set_Roi1”窗口,用于创建第一条尺寸边缘的直线测量器并设置检测直线的参数。



运动控制


7.在draw.bas文件中添加在“Set_Select”窗口界面按下【选择测量器区域1】按钮时响应的函数并关联动作函数名。

'-----------------分割线-------------------------

'测量器绘制

DIM is_redraw

is_redraw = 0

DIM set_roi_open_init

set_roi_open_init = 0

DIM sr_mpos_x, sr_mpos_y, hit_pos

'''''''''''''''''''''''''''''''''''

'按下选择测量器区域1按钮时响应的函数

GLOBAL SUB btn_sel_roi1()

ZV_LATCHCLEAR(1) '清除锁存

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

ZV_LATCH(grabImg, 1) '显示图像在锁存上

SET_COLOR(RGB(0,255,0))

'图像roi转控件roi

is_redraw = 0

TABLE(11, d_meas_param1(0), d_meas_param1(1))

ZV_POSFROMIMG(1, 1, 11, 11) '图像坐标转换到HMI控件坐标

TABLE(13) = ZV_LENFROMIMG(1, d_meas_param1(2))

TABLE(14) = ZV_LENFROMIMG(1, d_meas_param1(3))

TABLE(15) = d_meas_param1(4)

HMI_SHOWWINDOW(14)

END SUB



运动控制


8.在draw.bas文件中添加Roi1根据鼠标操作更新ROI位置的函数以及实时绘制Roi1的函数。

'根据鼠标操作更新Roi1的位置

GLOBAL SUB update_roi1()

if mouse_scan(21) = 1 then '

扫描按下操作

hit_pos = ZV_HMIADJRECT2(table(21), table(22), 11, -1) '只有按下时可以改变击中位置

?TABLE(21),TABLE(22)

is_redraw = 1

endif

if mouse_scan(21) = -1 then '

扫描松开操作

if TABLE(21)<(table(11)-table(13) or=''>(TABLE(11)+TABLE(13)/2) or TABLE(22)<(table(12)-table(14) or=''>(TABLE(12)+TABLE(14)/2) then

hit_pos=-1

endif

ZV_HMIADJRECT2(table(21), table(22), 11, hit_pos)

?*TABLE(11,4)

is_redraw = 1

endif

if (MOUSE_state(21)) then

ZV_HMIADJRECT2(table(21), table(22), 11, hit_pos)

is_redraw = 1

endif

if (1 = is_redraw) then

is_redraw = 0

ZV_POSTOIMG(1, 1, 11, 31)

d_meas_param1(0) = TABLE(31)

d_meas_param1(1) = TABLE(32)

d_meas_param1(2) = ZV_LENTOIMG(1, TABLE(13))

d_meas_param1(3) = ZV_LENTOIMG(1, TABLE(14))

d_meas_param1(4) = TABLE(15)

'如果选择了补正源,就保存roi基准

if(TABLE(110) = 1) then

set_base_roi()

endif

SET_REDRAW

endif

END SUB

'设置测量区域的基准roi

GLoBAL SUB set_base_roi()

d_meas_base_v1(0) = d_meas_param1(0)

d_meas_base_v1(1) = d_meas_param1(1)

d_meas_base_v1(2) = d_meas_param1(4)

d_meas_base_v2(0) = d_meas_param2(0)

d_meas_base_v2(1) = d_meas_param2(1)

d_meas_base_v2(2) = d_meas_param2(4)

END SUB

'更新Roi1位置后实时绘制图形

GLOBAL SUB draw_roi1()

SET_COLOR(C_BLUE)

TABLE(16, d_meas_param1(6), d_meas_param1(7)) '设置子区域个数和宽度两个参数

ZV_HMIRECT2(11, 300)

DRAWLINE(TABLE(300), TABLE(301), TABLE(302), TABLE(303)) '外矩形

DRAWLINE(TABLE(302), TABLE(303), TABLE(304), TABLE(305))

DRAWLINE(TABLE(304), TABLE(305), TABLE(306), TABLE(307))

DRAWLINE(TABLE(306), TABLE(307), TABLE(300), TABLE(301))

DRAWLINE(TABLE(308), TABLE(309), TABLE(310), TABLE(311)) '方向箭头

DRAWLINE(TABLE(312), TABLE(313), TABLE(310), TABLE(311))

DRAWLINE(TABLE(314), TABLE(315), TABLE(310), TABLE(311))

if (0 = TABLE(316)) then return

SET_COLOR(C_GREEN)

DIM idx

for idx = 0 to TABLE(316)-1

DRAWLINE(TABLE(317+idx*4), TABLE(318+idx*4), TABLE(319+idx*4), TABLE(320+idx*4))

next

END SUB

9.在draw.bas文件中添加在“Set_Roi1”窗口界面按下【确定】按钮时响应的函数并关联动作函数名。

'设置Roi1窗口按下确定按钮时响应的函数

GLOBAL SUB btn_meas_confirm1()

HMI_CLOSEWINDOW(14)

END SUB



运动控制


10.新建在“Set_Select”窗口界面按下【选择测量器区域2】按钮时弹出的“Set_Roi2”窗口,用于创建第二条尺寸边缘的直线测量器并设置检测直线的参数。



运动控制


11.在draw.bas文件中添加在“Set_Select”窗口界面按下【选择测量器区域2】按钮时响应的函数并关联动作函数名。

'按下选择测量器区域2按钮时响应的函数

GLOBAL SUB btn_sel_roi2()

ZV_LATCHCLEAR(1) '清除锁存

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

ZV_LATCH(grabImg, 1) '显示图像在锁存上

SET_COLOR(RGB(0,255,0))

'图像roi坐标转控件roi

is_redraw = 0

TABLE(11, d_meas_param2(0), d_meas_param2(1))

ZV_POSFROMIMG(1, 1, 11, 11) '图像坐标转换到HMI控件坐标

TABLE(13) = ZV_LENFROMIMG(1, d_meas_param2(2))

TABLE(14) = ZV_LENFROMIMG(1, d_meas_param2(3))

TABLE(15) = d_meas_param2(4)

HMI_SHOWWINDOW(15)

END SUB



运动控制


12.在draw.bas文件中添加Roi2根据鼠标操作更新ROI位置的函数以及实时绘制Roi1的函数。

'根据鼠标操作更新Roi2的位置

GLOBAL SUB update_roi2()

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

hit_pos = ZV_HMIADJRECT2(table(21), table(22), 11, -1) '只有按下时可以改变击中位置

is_redraw = 1

endif

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

ZV_HMIADJRECT2(table(21), table(22), 11, hit_pos)

is_redraw = 1

endif

if (MOUSE_state(21)) then

ZV_HMIADJRECT2(table(21), table(22), 11, hit_pos)

is_redraw = 1

endif

if (1 = is_redraw) then

is_redraw = 0

ZV_POSTOIMG(1, 1, 11, 31)

d_meas_param2(0) = TABLE(31)

d_meas_param2(1) = TABLE(32)

d_meas_param2(2) = ZV_LENTOIMG(1, TABLE(13))

d_meas_param2(3) = ZV_LENTOIMG(1, TABLE(14))

d_meas_param2(4) = TABLE(15)

'如果选择补正源,就保存roi基准位置

if(TABLE(110) = 1) then

set_base_roi()

endif

SET_REDRAW

endif

END SUB

'更新Roi2位置后实时绘制图形

GLOBAL SUB draw_roi2()

SET_COLOR(C_BLUE)

TABLE(16, d_meas_param2(6), d_meas_param2(7)) '设置子区域个数和宽度两个参数

ZV_HMIRECT2(11, 300) '计算控件的矩形roi相应的顶点和箭头锚点

DRAWLINE(TABLE(300), TABLE(301), TABLE(302), TABLE(303)) '外矩形

DRAWLINE(TABLE(302), TABLE(303), TABLE(304), TABLE(305))

DRAWLINE(TABLE(304), TABLE(305), TABLE(306), TABLE(307))

DRAWLINE(TABLE(306), TABLE(307), TABLE(300), TABLE(301))

DRAWLINE(TABLE(308), TABLE(309), TABLE(310), TABLE(311)) '方向箭头

DRAWLINE(TABLE(312), TABLE(313), TABLE(310), TABLE(311))

DRAWLINE(TABLE(314), TABLE(315), TABLE(310), TABLE(311))

if (0 = TABLE(316)) then return

SET_COLOR(C_GREEN)

DIM idx

for idx = 0 to TABLE(316)-1

DRAWLINE(TABLE(317+idx*4), TABLE(318+idx*4), TABLE(319+idx*4), TABLE(320+idx*4))

next

END SUB

13.在draw.bas文件中添加在“Set_Roi2”窗口界面按下【确定】按钮时响应的函数并关联动作函数名。

'设置Roi2窗口按下确定按钮时响应的函数

GLOBAL SUB btn_meas_confirm2()

HMI_CLOSEWINDOW(15)

END SUB



运动控制


14.新建meas.bas文件用于存放计算两条直线的距离函数和标定函数等测量相关函数,并在文件中添加实现函数。

'计算两条直线的距离宽度

global sub length1()

LOCAL dist,dist1,dist2

local dis_tmp,dst_tmp1

'计算直线2的起始点到直线1之间的距离

dist = ZV_DISTPL(d_meas_rst2(0),d_meas_rst2(1),d_meas_rst1(0),d_meas_rst1(1),d_meas_rst1(2),d_meas_rst1(3))

'计算直线2的终点到直线1之间的距离

dist1 = ZV_DISTPL(d_meas_rst2(2),d_meas_rst2(3),d_meas_rst1(0),d_meas_rst1(1),d_meas_rst1(2),d_meas_rst1(3))

'计算直线2的中点位置坐标

dis_tmp=(d_meas_rst2(0)+d_meas_rst2(2))/2

dst_tmp1=(d_meas_rst2(1)+d_meas_rst2(3))/2

'计算直线2的中点到直线1之间的距离

dist2 = ZV_DISTPL(dis_tmp,dst_tmp1,d_meas_rst1(0),d_meas_rst1(1),d_meas_rst1(2),d_meas_rst1(3))

TABLE(500)=(dist+dist1+dist2)/3 '两直线之间的距离

PixLength=TABLE(500)

?TABLE(500)

end sub

'计算实际尺寸值

global sub length2()

'实际尺寸=像素尺寸*像素比例

TABLE(501)=TABLE(500)*CalibParam

end sub

'计算像素比例,即实际值/像素值

global sub calculation()

CalibParam=WorldLength/TABLE(500)

end sub

15.在main.bas文件中添加“Set_Select”窗口界面按下【测试】按钮时响应的函数并关联动作函数名。

'测量设置界面按下测试按钮时响应的函数

GLOBAL SUB btn_mea_test()

'选择补正源时先执行定位检测

if(TABLE(110) = 1) then

btn_loc_test()

endif

ZVOBJECT mr1,mr2,mr3,mr4,rst1,rst2,rst3,rst4,colorImg

ZVOBJECT contlist, tsContlist, mat_rigid

LOCAL show_rst

'测量区域roi补正

if(TABLE(110) = 1 AND d_is_creModel = 1) then '如果使用补正源已经开启且模板已经创建

'计算刚性变换矩阵

ZV_GETRIGIDVECTOR(mat_rigid, d_match_base_rst(1), d_match_base_rst(2), d_match_base_rst(3), d_match_rst(1), d_match_rst(2), d_match_rst(3))

'使用变换矩阵mat_rigid对输入Roi1基准向量进行补正,补正后的向量存入开始索引为0的TABLE中

ZV_VECTORCORRECT(mat_rigid, d_meas_base_v1(0), d_meas_base_v1(1),d_meas_base_v1(2), 0)

d_meas_param1(0) = TABLE(0)

d_meas_param1(1) = TABLE(1)

d_meas_param1(4) = TABLE(2)

'使用变换矩阵mat_rigid对输入Roi2基准向量进行补正,补正后的向量存入开始索引为0的TABLE中

ZV_VECTORCORRECT(mat_rigid, d_meas_base_v2(0), d_meas_base_v2(1),d_meas_base_v2(2), 0)

d_meas_param2(0) = TABLE(0)

d_meas_param2(1) = TABLE(1)

d_meas_param2(4) = TABLE(2)

endif

'测量区域1

'生成直线1测量的旋转区域

ZV_MRGENLINE(mr1, d_meas_param1(0), d_meas_param1(1), d_meas_param1(2), d_meas_param1(3), d_meas_param1(4), 1, d_meas_param1(6), d_meas_param1(7))

'设置直线1的检测参数,包括滤波器尺寸,阈值,边缘极性,边缘位置

ZV_MRSETADV(mr1, d_meas_param1(8), d_meas_param1(9), d_meas_param1(10), d_meas_param1(11))

'测量区域2

'生成直线2测量的旋转区域

ZV_MRGENLINE(mr2, d_meas_param2(0), d_meas_param2(1), d_meas_param2(2), d_meas_param2(3), d_meas_param2(4), 1, d_meas_param2(6), d_meas_param2(7))

'设置直线2的检测参数,包括滤波器尺寸,阈值,边缘极性,边缘位置

ZV_MRSETADV(mr2, d_meas_param2(8), d_meas_param2(9), d_meas_param2(10), d_meas_param2(11))

'将矩形测量区域测量到的目标直线1端点存储到起始索引为61的TABLE

ZV_MRLINE(mr1, grabImg, rst1, 61)

d_meas_rst1(0) = TABLE(61)

d_meas_rst1(1) = TABLE(62)

d_meas_rst1(2) = TABLE(63)

d_meas_rst1(3) = TABLE(64)

'将矩形测量区域测量到的目标直线2端点存储到起始索引为71的TABLE

ZV_MRLINE(mr2, grabImg, rst2, 71)

ZV_MATINFO(rst2, 0) 'table(0)作为临时变量

d_meas_rst2(0) = TABLE(71)

d_meas_rst2(1) = TABLE(72)

d_meas_rst2(2) = TABLE(73)

d_meas_rst2(3) = TABLE(74)

'计算两条直线的距离宽度

length1()

d_show_rst=TABLE(500)

if(CalibParam>0) then

'计算实际长度

length2()

d_show_rst=TABLE(501)

endif

'绘制结果线

ZV_GRAYTORGB(grabImg, colorImg)

ZV_LINE(colorImg, TABLE(61), TABLE(62), TABLE(63), TABLE(64), C_GREEN)

ZV_LINE(colorImg, TABLE(65), TABLE(66), TABLE(67), TABLE(68), C_GREEN)

ZV_LINE(colorImg, TABLE(71), TABLE(72), TABLE(73), TABLE(74), C_GREEN)

ZV_LINE(colorImg, TABLE(75), TABLE(76), TABLE(77), TABLE(78), C_GREEN)

ZV_LATCH(colorImg,0)

END SUB



运动控制


在main.bas文件中添加“Set_Select”窗口界面按下【测试】按钮时仿真的效果图。



运动控制


测试按钮效果图

16.设置“Set_Select”窗口界面【计算】按钮关联动作函数名。



运动控制


在“Set_Select”窗口界面按下【计算】按钮时仿真的效果图。



运动控制


计算按钮效果图

17.在“Set_Select”窗口界面中关联界面控件变量。



运动控制


18.在main.bas文件中添加“Set_Select”窗口界面按下【返回主界面】按钮时响应的函数并关联动作函数名。

'按下返回主界面按钮时响应的函数

GLOBAL SUB Goto_Main()

HMI_CLOSEWINDOW(13)

END SUB


运动控制


19.在main.bas文件中修改主界面按下【单次执行】按钮时响应的函数并关联动作函数名。

'主界面按下单次执行按钮时响应的函数

GLOBAL SUB btn_test()

'采集一帧图像

btn_grab

'执行测量测试部分代码

btn_mea_test()

END SUB


运动控制


在主界面按下【单次执行】按钮时仿真的效果图。



运动控制


20.在main.bas文件中修改主界面按下【连续执行】按钮时响应的函数中执行的任务函数内容。

main_task:

while(1)

if (0 = run_switch) then

exit while

endif

'以下执行相关定位操作

btn_grab()

btn_mea_test()

wend

END

在主界面按下【连续执行】按钮时仿真仿真执行的效果图。



运动控制


连续运行效果图1



运动控制


连续运行效果图2


在不同位置以不同角度放置时,均能检测到对应尺寸。


进入嵌入式查看更多内容>>
相关视频
  • PX4固件二次开发课程

  • RISC-V嵌入式系统开发

  • NuttX Workshop 2024

  • 自己动手写操作系统

  • SOC系统级芯片设计实验

  • 自己动手做一台计算机

精选电路图
  • PIC单片机控制的遥控防盗报警器电路

  • 红外线探测报警器

  • 短波AM发射器电路设计图

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 开关电源的基本组成及工作原理

  • 用NE555制作定时器

    相关电子头条文章