inspect_bottle_mouth.hdev
* tuning parameters SmoothX := 501 ThresholdOffset := 25 MinDefectSize := 50 * * initialization PolarResolution := 640 RingSize := 70 get_system ('store_empty_region', StoreEmptyRegion) set_system ('store_empty_region', 'false') read_image (Image, 'bottles/bottle_mouth_01') dev_update_off () dev_close_window () dev_close_window () dev_open_window_fit_image (Image, 0, 0, 640, 512, WindowHandle1) set_display_font (WindowHandle1, 16, 'mono', 'true', 'false') dev_display (Image) dev_set_draw ('margin') dev_set_line_width (3) dev_open_window_fit_size (0, 648, RingSize, PolarResolution, 150, 512, WindowHandle) dev_set_draw ('margin') dev_set_line_width (3) dev_set_color ('red') * * Main loop * * Detect defects in bottle necks for Index := 1 to 16 by 1 read_image (Image, 'bottles/bottle_mouth_' + Index$'.02') * * Part 1: Use basic morphology to detect bottle *自动阈值分割图像 auto_threshold (Image, Regions, 2) *选择第一的区域,没明白 select_obj (Regions, DarkRegion, 1) *用3.5的圆做开运算(先腐蚀后膨胀),消除小物体 opening_circle (DarkRegion, RegionOpening, 3.5) *用25.5的圆做闭运算(先膨胀后腐蚀),排除小型黑洞,可以把里面的小圆滤除掉,只保留大圆 closing_circle (RegionOpening, RegionClosing, 25.5) *填补区域的漏洞,让区域更完整 fill_up (RegionClosing, RegionFillUp) *向外扩散一个区域后,计算区域内的轮廓,(计算轮廓啥意思?) boundary (RegionFillUp, RegionBorder, 'outer') *内外各以3.5的像素扩大区域 dilation_circle (RegionBorder, RegionDilation, 3.5) *选择了上面扩大后的区域,提取这个区域(不是裁剪) reduce_domain (Image, RegionDilation, ImageReduced) * * Find the bottle center by fitting a circle to extracted edges *使用累计直方图计算两个阀值。凡是大于高阀值的一定是边缘; 凡是小于低阀值的一定不是边缘; *如果检测结果大于低阀值但又小于高阀值,那就要看这个像素的邻接像素中有没有超过高阀值的边缘像素:如果有的话那么它就是边缘了,否则他就不是边缘; *但我仍然有疑惑 edges_sub_pix (ImageReduced, Edges, 'canny', 0.5,20, 40) *利用直线和圆去分割原有的轮廓,导致更容易拟合 segment_contours_xld (Edges, ContoursSplit, 'lines_circles', 5, 4, 2) *利用上面分割的结果,用直线或者圆弧拟合轮廓 union_cocircular_contours_xld (ContoursSplit, UnionContours, 0.9, 0.5, 0.5, 200, 50, 50, 'true', 1) length_xld (UnionContours, Length) select_obj (UnionContours, LongestContour, sort_index(Length)[|Length| - 1] + 1) *用一个完整圆拟合上面那个轮廓,返回圆心坐标和半径 fit_circle_contour_xld (LongestContour, 'ahuber', -1, 0, 0, 3, 2, Row, Column, Radius, StartPhi, EndPhi, PointOrder) * * Part 2: Transform the ring-shaped bottle neck region to a rectangle *根据圆心坐标和半径产生一个圆 gen_circle (Circle, Row, Column, Radius) *向外以5的像素扩大区域 dilation_circle (Circle, RegionDilation, 5) *向内以(70-5=65)的像素扩大区域 erosion_circle (Circle, RegionErosion, RingSize - 5) *得到一个圆环,两个圆之间的区域 difference (RegionDilation, RegionErosion, RegionDifference) *提取上面的圆环区域(不是裁剪) reduce_domain (Image, RegionDifference, ImageReduced) *极坐标变换算子,圆形图变方形图 *参数(输入图像,输出图像,圆心横坐标,圆心纵坐标 *,要映射到输出图像第一列的射线角度,要映射到输出图像最后一列的射线角度 *,要映射到输出图像第一行的圆的半径,要映射到输出图像最后一行的圆的半径 *,输出图的宽,输出图的高,类插值方法) polar_trans_image_ext (ImageReduced, ImagePolar, Row, Column, 0, rad(360), Radius - RingSize, Radius, PolarResolution, RingSize, 'nearest_neighbor') * * Part 3: Find defects with a dynamic threshold * Note the strong smoothing in x-direction in the transformed image. *将图像中像素最小和最大之间的像素值均匀映射到0-255之间,增强对比度。 scale_image_max (ImagePolar, ImageScaleMax) *均值滤波 mean_image (ImageScaleMax, ImageMean, SmoothX, 3) *动态阈值分割 dyn_threshold (ImageScaleMax, ImageMean, Regions1, 55, 'not_equal') *将分割后的各区域分隔开 connection (Regions1, Connection) *根据高度选择9个像素以上的区域 select_shape (Connection, SelectedRegions, 'height', 'and', 9, 99999) * ignore noise regions *封闭的矩形框,边界被平滑 closing_rectangle1 (SelectedRegions, RegionClosing1, 10, 20) union1 (RegionClosing1, RegionUnion) * re-transform defect regions for visualization *极坐标反变换 polar_trans_region_inv (RegionUnion, XYTransRegion, Row, Column, 0, rad(360), Radius - RingSize, Radius, PolarResolution, RingSize, 1280, 1024, 'nearest_neighbor') * * Part 4: Display results * display original image with results dev_set_window (WindowHandle1) dev_display (Image) dev_set_color ('blue') dev_display (RegionDifference) dev_set_color ('red') dev_display (XYTransRegion) * display polar transformed inspected region with results * The image and resulting region are rotated by 90 degrees * only for visualization purposes! (I.e. to fit better on the screen) * The rotation is NOT necessary for the detection algorithm. dev_set_window (WindowHandle) rotate_image (ImagePolar, ImageRotate, 90, 'constant') dev_display (ImageRotate) count_obj (RegionUnion, Number) if (Number > 0) mirror_region (RegionUnion, RegionMirror, 'diagonal', PolarResolution) mirror_region (RegionMirror, RegionMirror, 'row', PolarResolution) dev_display (RegionMirror) disp_message (WindowHandle1, 'Not OK', 'window', -1, -1, 'red', 'false') else disp_message (WindowHandle1, 'OK', 'window', -1, -1, 'forest green', 'false') endif if (Index < 16) disp_continue_message (WindowHandle1, 'black', 'true') stop () endif endfor * Reset system parameters set_system ('store_empty_region', StoreEmptyRegion)
本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:


