图片内是4个不同形状、颜色、位置的工件,上方还贴着二维码,我想通过Halcon的一些算子将它们的一些基本信息检测出来。
一、建模
为了方便查找这些工件的基本轮廓,我将这些不同形状的工件分别建模,而在建模的过程中,由于二维码会干扰到我们的区域查找。所以,最好利用没有二维码的那一面进行建模,才能达到理想的效果。
我选择的建模对象分别如下(由于查找的对象是工件的轮廓,固颜色并不重要):
以下是具体的处理工程(两种形状工件的处理工程大同小异):
rgb1_to_gray (Image1, GrayImage) //将RGB图像转化为灰度图像
disp_message (WindowHandle, '请画一个矩形将工件选取:', 'window', 24, 24, 'black', 'true') //在图片设定的位置显示一句话
draw_rectangle1 (WindowHandle, Row11, Column11, Row2, Column2) //画一个矩形将大致的工件范围确定,以方便后续的查找和处理
gen_rectangle1 (Rectangle, Row11, Column11, Row2, Column2) //显示上面画的矩形
reduce_domain (GrayImage, Rectangle, ImageReduced) //将这个矩形转化成一个区域
threshold (ImageReduced, Region, 87, 255) //在ImageReduced区域内查找阈值为87到255之间的区域
connection (Region, ConnectedRegions) //将Region内的区域分离
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 200000, 600000) //将ConnectedRegions区域内面积在200000到600000之间的区域选取出来
dev_display (GrayImage)
dev_display (SelectedRegions)
gen_contour_region_xld (SelectedRegions, Contours, 'border_holes') //将SelectedRegions区域转化为轮廓模型(采用中断边缘模式,否则矩形工件内的中空区域无法被查找)
create_scaled_shape_model_xld (Contours, 'auto', rad(0), rad(360), 'auto', 0.9, 1.1, 'auto', 'auto', 'ignore_local_polarity', 5, ModelID_rectangle) //将Contours轮廓建立成一个模型句柄
find_shape_model (GrayImage, ModelID_rectangle, rad(0), rad(360), 0.5, 1, 0.5, 'least_squares', 0, 0.9, Row1, Column1, Angle, Score) //在GrayImage图片内查找ModelID_rectangle模型
dev_display (GrayImage)
dev_display_shape_matching_results (ModelID_rectangle, 'red', Row1, Column1, Angle, 1, 1, 0) //显示查找到的ModelID_rectangle模型
gen_arrow_contour_xld (Arrow, Row1, Column1, Row1-150*sin(Angle), Column1+150*cos(Angle), 40, 40) //在查找到的中心点处画一个十字
write_shape_model (ModelID_rectangle, models + 'ModelID_rectangle.shm') //将ModelID_rectangle模型句柄输出出来
转化的灰度值图片如下:
选取阈值为87到255之间的区域如下:
这里值得注意的是:在举行工件里面,由于摄像头的角度问题,可以发现中空内圈的形状发生一定程度的变形,这时,假设我们将其囊括进阈值选取的区域,在之后的模型查找容易出错,所以需要选择变形不明显的外圈。
选取面积为200000到600000之间的区域如下:
此举主要是为了排除不必要的区域,防止其并入模型当中,影响模型的建立以及查找。
二、形状识别
形状的识别我们可以通过区域的圆度和直角度进行区分,想要知道区域的圆度和直角度,就需要进行以下算子的处理:
gen_rectangle1 (Rectangle, 65, 300, 1900, 2120)
reduce_domain (Image1, Rectangle, ImageReduced)
rgb1_to_gray (ImageReduced, GrayImage)
threshold (GrayImage, Region, 55, 160) //在GrayImage图片内选取阈值为55到160的区域
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 20000, 999999) //将ConnectedRegions内的面积在20000到999999之间的区域选取出来
fill_up (SelectedRegions, RegionFillUp) //填充SelectedRegions区域
shape_trans (RegionFillUp, RegionTrans, 'convex') //将RegionFillUp区域化成标准的形状区域
area_center (RegionTrans, Area3, Row3, Column3) //查找RegionTrans区域的中心点坐标
dev_display (GrayImage)
dev_display (RegionTrans)
select_shape (RegionTrans, SelectedRegionsRectangle, 'rectangularity', 'and', 0.85, 1.0) //将RegionTrans区域内直角度0.85以上的区域选取出来
select_shape (RegionTrans, SelectedRegionsCircle, 'roundness', 'and', 0.85, 1.0) //将RegionTrans区域内圆度0.85以上的区域选取出来
当RegionTrans区域的直角度大于0.85,我们可以判定其为矩形区域;同理,当其圆度大于0.85,我们就判定其为圆形区域。
三、数量识别
为了检测出工作区域内摆放了多少个工件,也为了方便接下来的操作,我们进行下面的算子运算:
count_obj (RegionTrans, Number) //计算RegionTrans内区域的数量
for a := 1 to Number by 1
select_obj (RegionTrans, ObjectSelected, a) //按顺序选取RegionTrans内的区域
dev_display (Image1)
dev_display (ObjectSelected)
disp_message (WindowHandle, Number + '个矩形工件', 'image', 24, 24, 'black', 'true')
四、颜色识别
由于每种颜色的饱和度都是不一样的,所以,将图像处理成饱和度图像,再通过阈值界定颜色的种类,能够达到理想的颜色区分效果。
decompose3 (Image1, Image11, Image2, Image3) //将Image1图片分离出三基色图像
trans_from_rgb (Image11, Image2, Image3, ImageResult_H, ImageResult_S, ImageResult_V, 'hsv') //将三基色图像转化成hsv图像,其中的h图像就是我们需要的饱和度图像
dev_display (ImageResult_H)
color_threshold := [90,150,210,255] //设定颜色的阈值区间,90到150之间的区域为绿色;210到255之间的区域为红色
workpiece_color := [1,2]
reduce_domain (ImageResult_H, ObjectSelected, ImageReduced2)
for color_number := 0 to 1 by 1
threshold (ImageReduced2, Region2, color_threshold[color_number * 2], color_threshold[color_number * 2 + 1]) //用绿色的阈值区间对ImageReduced2区域进行扫描,假设该扫描区域存在,则继续进行操作;否则,用红色的阈值区间再进行扫描
connection (Region2, ConnectedRegions2)
fill_up (ConnectedRegions2, RegionFillUp1)
select_shape (RegionFillUp1, SelectedRegions2, 'area', 'and', 300000, 500000)
area_center (SelectedRegions2, Area5, Row5, Column5)
dev_display (ImageResult_H)
dev_display (SelectedRegions2)
if(Area5 != [])
retangle_data[0] := color_number //假设SelectedRegions2区域存在,则把该区域的颜色标记放进retangle_data数组中(0代表绿色,1代表红色)
endif
endfor
三基色图像如下:
饱和度图像如下:
可以发现,绿色工件经过饱和度处理,变得非常灰蒙;而红色工件经过处理,变得非常光亮。这样的阈值差异是非常明显的,非常适合区域查找从而进行颜色识别。
五、定位情况、中心点坐标及旋转角度
rgb1_to_gray (Image1, GrayImage2)
dilation_rectangle1 (ObjectSelected, RegionDilation, 100, 100) //将ObjectSelected区域扩大100个像素
reduce_domain (GrayImage2, RegionDilation, ImageReduced3)
find_shape_model (ImageReduced3, ModelID_rectangle, rad(0), rad(360), 0.5, 1, 0.5, 'least_squares', 0, 0.9, Row6, Column6, Angle, Score) //在ImageReduced3区域内查找ModelID_rectangle模板句柄
if(Score > 0.8)
dev_display_shape_matching_results (ModelID_rectangle, 'red', Row6, Column6, Angle, 1, 1, 0) //如果匹配的分数大于0.8,则显示ModelID_rectangle模型句柄
gen_arrow_contour_xld (Cross2, Row6, Column6, Row6 - 150*sin(Angle), Column6 + 150*cos(Angle), 40, 40) //根据旋转角度画一个箭头
retangle_data[1] := Row6 //将中心点坐标存进retangle_data数组
retangle_data[2] := Column6
tuple_deg (Angle, Deg) //把Π形式的角度化成度数
retangle_data[3] := Deg //把旋转角度存进retangle_data数组
retangle_data[4] := 1 //1代表定位成功,2代表定位失败
else
retangle_data[1] := 0
retangle_data[2] := 0
retangle_data[3] := 0
retangle_data[4] := 2
endif
六、二维码识别
dev_display (ImageReduced3)
create_data_code_2d_model ('QR Code', [], [], DataCodeHandle) //建立QR Code类型的二维码模型句柄
find_data_code_2d (ImageReduced3, SymbolXLDs, DataCodeHandle, [], [], ResultHandles, DecodedDataStrings) //在ImageReduced3区域查找二维码的位置并显示,解析二维码的内容
if(DecodedDataStrings != [])
retangle_data[5] := DecodedDataStrings //将识别出来的二维码内容存进retangle_data数组
else
retangle_data[5] := 0
endif
七、显示结果
工件的信息解析如下:
剩余工件同理。