对应示例程序:
inspect_frame_width.hdev
目标: 根据内外两个轮廓的点向距离,检查手机外壳的摄像头框架是否满足要求
思路为:
1. 读取原始图像,进行阈值分割和亚像素边缘检测
2. 利用算子union_adjacent_contours_xld将相近的边缘进行连接
3. 根据边缘长度进行细化,得到待定边缘
4. 将得到的边缘按照从小到大的顺序进行排序,内边缘的长度最小,外边缘的长度最大
5. 利用算子distance_contours_xld计算内外边缘的距离,并根据阈值,筛选出不符合要求的边缘部分
6. 对内外边缘分别进行平滑,并计算对应的距离,利用平滑阈值,进行筛选,得到平滑度不符合要求的内外边缘部分
7. 根据阈值,进行显示,包括内外边缘之间的距离太窄,太宽,以及边缘的平滑度不够
图像:
代码:
*这个程序演示了如何计算两个轮廓的点向距离,以检查手机外壳的摄像头框架。
*利用算子distance_contours_xld计算内外轮廓的距离,用算子segment_contour_attrib_xld提取缺陷进行可视化。
* Set the thresholds for the allowed distances in pixels
*阈值设置
MinWidth := 30 //最小宽
MaxWidth := 35 //最大宽
SmoothnessTolerance := .2 //平滑度阈值
*
* Initialize visualization //进行可视化的前期准备
dev_update_off ()
dev_close_window ()
read_image (Image, 'plastic_parts/phone_camera_frame_01')
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle) //打开适应图像大小的窗口
set_display_font (WindowHandle, 14, 'mono', 'true', 'false') //设置字体格式
Colors := ['white','green','yellow','orange','red'] //可视化用的字符串
Legend := 'Legend:'
Legend[1] := 'Extracted contours'
Legend[2] := 'Frame too narrow'
Legend[3] := 'Frame too wide'
Legend[4] := 'Contour defect'
*
* Main loop:
* Inspect the camera frame
*
NumImages := 2
for I := 1 to NumImages by 1
read_image (Image, 'plastic_parts/phone_camera_frame_' + I$'02') //读入图像
*
* Extract frame edges 提取边缘
*
* Select the frame region
threshold (Image, Region, 100, 255) //阈值分割
dilation_rectangle1 (Region, RegionDilation, 15, 15) //矩形膨胀
reduce_domain (Image, RegionDilation, ImageReduced) //裁剪ROI区域
* Extract edges in the reduced image domain
edges_sub_pix (ImageReduced, Edges, 'canny', 0.7, 10, 60) //亚像素边缘检测
union_adjacent_contours_xld (Edges, UnionContours, 7, 7, 'attr_keep') //将端点距离很近的轮廓连接起来
select_shape_xld (UnionContours, SelectedContours, 'contlength', 'and', 700, 99999) //根据轮廓长度筛选目标轮廓
* Select the inner and the outer contour
length_xld (SelectedContours, Length) //计算轮廓的长度
tuple_sort_index (Length, Indices) //对轮廓长度进行排序(从小到大),并返回对应的索引
//指定0 和 3是否合适??? 是否应该根据轮廓的数量进行适应性修改
select_obj (SelectedContours, InnerContour, Indices[0] + 1) //内轮廓 长度最小
select_obj (SelectedContours, OuterContour, Indices[3] + 1) //外轮廓 长度最大
*
* Calculate the distances between the inner and outer contour.
* The distances are stored as an attribute to the output contour.
*计算内外轮廓之间的距离。
*这些距离存储为输出轮廓的属性。
distance_contours_xld (InnerContour, OuterContour, OuterContourWithWidth, 'point_to_segment')
* Get the contour parts that lie outside of the tolerances
*获取超出阈值范围的轮廓部分
*0到最小阈值的部分
segment_contour_attrib_xld (OuterContourWithWidth, OuterContourPartToNarrow, 'distance', 'or', 0, MinWidth)
*最大阈值到10000的部分
segment_contour_attrib_xld (OuterContourWithWidth, OuterContourPartToWide, 'distance', 'or', MaxWidth, 10000)
*
* Check, if the contours are sufficiently smooth by
* comparing each contour with a smoothed version of itself
*XLD轮廓平滑 计算原始轮廓和平滑后轮廓的距离
smooth_contours_xld (OuterContour, OuterContourSmooth, 11)
smooth_contours_xld (InnerContour, InnerContourSmooth, 11)
distance_contours_xld (OuterContour, OuterContourSmooth, OuterContourWithDistance, 'point_to_segment')
distance_contours_xld (InnerContour, InnerContourSmooth, InnerContourWithDistance, 'point_to_segment')
* Get the contour parts that lie outside of the tolerances
*筛选出不符合平滑度要求的轮廓
segment_contour_attrib_xld (OuterContourWithDistance, OuterContourDefect, 'distance', 'or', SmoothnessTolerance, 100)
segment_contour_attrib_xld (InnerContourWithDistance, InnerContourDefect, 'distance', 'or', SmoothnessTolerance, 100)
*
* Get pointwise distances for debugging
*获取距离
//返回XLD轮廓包括的一些属性值
get_contour_attrib_xld (OuterContourWithWidth, 'distance', FrameWidth) //内外轮廓的距离
get_contour_attrib_xld (OuterContourWithDistance, 'distance', InnerDistances) //内轮廓和平滑内轮廓的距离
get_contour_attrib_xld (InnerContourWithDistance, 'distance', OuterDistances) //外轮廓和平滑外轮廓的距离
*
* Display results
dev_display (Image)
disp_message (WindowHandle, 'Inspect frame of phone camera (image ' + I + '/' + NumImages + ')', 'window', 12, 12, 'black', 'true')
//统计各Obj的数量
count_obj (OuterContourPartToNarrow, NumTooNarrow)
count_obj (OuterContourPartToWide, NumTooWide)
count_obj (OuterContourDefect, NumInnerDefects)
count_obj (InnerContourDefect, NumOuterDefects)
//进行显示
if (NumTooNarrow + NumTooWide + NumInnerDefects + NumOuterDefects == 0)
OK := 1
disp_message (WindowHandle, 'Frame OK', 'window', 50, 12, 'forest green', 'true')
else
OK := 0
disp_message (WindowHandle, 'Frame not OK', 'window', 50, 12, 'red', 'true')
endif
*
dev_set_line_width (1)
dev_set_color (Colors[1])
dev_display (OuterContour)
dev_display (InnerContour)
dev_set_line_width (5)
dev_set_color (Colors[2])
dev_display (OuterContourPartToNarrow)
dev_set_color (Colors[3])
dev_display (OuterContourPartToWide)
dev_set_color (Colors[4])
dev_display (OuterContourDefect)
dev_set_color (Colors[4])
dev_display (InnerContourDefect)
disp_message (WindowHandle, Legend, 'window', 500, 12, Colors, 'false')
if (I < NumImages)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
endif
endfor
用到的几个算子:
edges_sub_pix --亚像素边缘检测。
union_adjacent_contours_xld – 将端点距离很近的轮廓连接起来。
distance_contours_xld-- 计算轮廓之间的距离
segment_contour_attrib_xld–筛选出满足要求的轮廓
smooth_contours_xld–对XLD轮廓进行平滑
get_contour_attrib_xld –获取XLD轮廓包含的信息