Halcon例程學習之瓶口缺陷檢測
阿新 • • 發佈:2018-11-16
* 這個例子檢查瓶口缺陷, * 首先找到瓶口,找瓶口的方法就通過自動閾值,然後進行圓擬合 *邊緣檢測,找到邊緣之後縮小圓,找到瓶口這一個圓帶狀影象 *把圓帶拉抻變換成長方形,這樣其實是為了使用平均值濾波,把視窗的設定為【500,3】大小,這樣就可以把垂直方向的差異提取出來 *然後再通過dyn_threshold找出差異位置,計算連通域,然後再找出連通域高度大於9的,如果有,就認為包含缺陷,如果沒有就不包含缺陷 *然後給定一個動態的閾值來檢測缺陷,最後顯示缺陷 *總結,這個例子主要是看瓶口徑向一致性的檢查,正常的瓶口徑向一致性很好,但是有破損的則不然,所以這是一個很好的思路 * tuning parameters *均值濾波視窗寬度 SmoothX := 501 *動態閾值操作的容差值,但是下面直接使用的55這個值,沒使用變數 ThresholdOffset := 55 *找到的瑕疵高度最小值 MinDefectSize := 9 * * 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 *讀取影象到Image read_image (Image, 'bottles/bottle_mouth_' + Index$'.02') * * Part 1: 檢測瓶子口 auto_threshold (Image, Regions, 2) *通過自動閾值,選擇最黑的區域 select_obj (Regions, DarkRegion, 1) opening_circle (DarkRegion, RegionOpening, 3.5) closing_circle (RegionOpening, RegionClosing, 25.5) *填充區域 fill_up (RegionClosing, RegionFillUp) *找到邊界 boundary (RegionFillUp, RegionBorder, 'outer') *膨脹邊界 dilation_circle (RegionBorder, RegionDilation, 3.5) *取影象的邊緣,其實取的是Image 和RegionDilation的相同的部分 reduce_domain (Image, RegionDilation, ImageReduced) * *通過為提取的邊緣擬合一個圓來查詢瓶中心 *canny邊緣檢測 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) *選擇長度最長的那一個 *sort_index(Length)[|Length| - 1] 是取最大的長度的index,因為select_obj的index引數是從1開始的,所以需要加1 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) *膨脹圓 dilation_circle (Circle, RegionDilation, 5) *腐蝕圓 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: 通過動態閾值打到缺陷位置 * Note the strong smoothing in x-direction in the transformed image. *scale_image_max應該是指正則化,找到影象最亮和最暗,然後把影象畫素拉成0-255 scale_image_max (ImagePolar, ImageScaleMax) *使用平均平滑影象,後面兩個引數應該是平均視窗的大小,但是為什麼長度設定為501高為3呢,可能是因為垂直方向上差異大,想要找出垂直方向差異 mean_image (ImageScaleMax, ImageMean, SmoothX, 3) *使用本地的影象動態閾值,然後分割imageSacleMax,Offset越大,找到的區域越小,因為容差大了,大於這個容差的就少了 dyn_threshold (ImageScaleMax, ImageMean, Regions1, ThresholdOffset, 'not_equal') *計算連通區域 connection (Regions1, Connection) *選擇高度在9~9999之間的連通區域 select_shape (Connection, SelectedRegions, 'height', 'and', MinDefectSize, 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') *XYTransRegion儲存的是影象中的瑕疵 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