Halcon模板匹配學習:determine_rotation_almost_rotationally_symmetric_objects

determine_rotation_almost_rotationally_symmetric_objects

確定_旋轉_幾乎_旋轉_對稱_對象

 

*此示例顯示如何結合使用基於形狀的匹配和極座標變換來穩健地確定幾乎旋轉對稱的對象的方向。

*旋轉對稱導致問題,即無法通過簡單的基於形狀的匹配可靠地確定對象的方向。
*相反,基於形狀的匹配對於任何旋轉都會返回高分,因爲重要邊緣(非旋轉對稱)的影響太小,並且由於噪聲,透視圖,照明,相機變形等。
*
*我們通過兩步法解決了這個問題:
* 1.大致確定對象位置
*(但方向任意):
*在此示例中,這是基於形狀的匹配完成的,因爲它是最通用的方法,同時說明了匹配幾乎旋轉對稱的對象時的困難。
* 2.確定方向:
*這是通過將對象轉換爲極座標並匹配定義對象方向的非對稱部分來完成的。
*請注意,此步驟至關重要,可以高精度確定旋轉對稱中心。
*在此示例中,這是通過非常準確地爲步驟1選擇模型區域來完成的。
*
*初始化參數Initialize parameters 
*
*互動式Interactive:
*如果將此參數設置爲1(true),將要求用戶用鼠標交互選擇步驟2(極座標中的匹配)的模型邊緣。
*請注意,結果的質量很大程度上取決於用戶定義的模型區域。

Interactive := 0
* Tolerance: Half height of the search region in the
*            polar transformed image for step 2

*公差:步驟2的極座標變換圖像中搜索區域的一半高度
Tolerance := 2.5
* MinScoreMain: MinScore for shape-based matching in step 1
MinScoreMain := 0.7
* MinScorePolar: MinScore for shape-based matching in step 2
MinScorePolar := 0.4
* ContrastMain: Contrast for shape-based matching in step 1
ContrastMain := 30
* ContrastPolar: Contrast for shape-based matching in step 2
ContrastPolar := 20
* Matching parameters for both steps
Greediness := 0.5
MinContrast := 10

* **********************************************************
* Generate model region for shape-based matching in step 1
* **********************************************************

* Read model image
dev_update_off ()
read_image (Image, 'plastic_parts/cistern_valve_diaphragms_01')


* Estimate center of rotation symmetry.估計旋轉中心的對稱性。
* It is important, that the center of the model
* is equal to the rotation center of the object.*重要的是,模型的中心必須等於對象的旋轉中心。
threshold (Image, Region, 128, 255)//使用閾值分割圖像,得到灰度值在最小到最大之間的那些像素區域
boundary (Region, RegionBorder, 'inner')//參數爲inner時 ,提取區域的內邊界,邊界的寬是一個像素
dilation_circle (RegionBorder, RegionDilation, 3.5)//膨脹操作,將變換得到的RegionBorder區域擴大3.5邊緣,並倒圓角
reduce_domain (Image, RegionDilation, ImageReduced)//Image是輸入圖像;RegionDilation是輸入區域;ImageReduced輸出對象,爲相交的圖像區域,縮小圖像的亞像素輪廓
edges_sub_pix (ImageReduced, Edges, 'canny', 1, 20, 40)//edges_sub_pix亞像素邊緣提取,canny算子邊緣檢測,alpha=1參數指定值越小越平滑,低閾值low=20,高閾值high=40
fit_circle_contour_xld (Edges, 'geohuber', -1, 0, 0, 3, 2, RowFittedCircle, ColumnFittedCircle, Radius, StartPhi, EndPhi, PointOrder)//用於圓擬合XLD輪廓,輸出圓心Row、Column、Radius

* Generate model region and create model 生成模型區域並創建模型
RegionRadius := Radius + 10
Clip := RegionRadius + 50
gen_circle (ModelRegion, RowFittedCircle, ColumnFittedCircle, RegionRadius)//生成一個或多個由中心和半徑描述的圓
reduce_domain (Image, ModelRegion, ModelImage)//輸出圖像的相交區域
create_shape_model (ModelImage, 'auto', 0, rad(360), 'auto', 'auto', 'use_polarity', ContrastMain, MinContrast, ModelID)//生成模型ModleID
* Correct the origin of the shape model, such that
* the model center is equal to the center of the
* fitted circle which is more accurate than the
* center of the circle region.*校正形狀模型的原點,以使模型中心等於擬合圓的中心,比圓區域的中心更精確。
area_center (ModelRegion, AreaModelRegion, RowModelRegion, ColumnModelRegion)//獲取區域的中心行列座標,區域面積
set_shape_model_origin (ModelID, RowFittedCircle - RowModelRegion, ColumnFittedCircle - ColumnModelRegion)//設置模板的原始座標(不調用該算子默認爲0,0;)
find_shape_model (Image, ModelID, -0.39, 0.78, 0.5, 1, 0.5, 'least_squares', 0, 0.9, R, C, A, S)//查找圖像Image與模板ModelID匹配的圖像部分
* **********************************************************

* Init main window and display intro screen 初始化主窗口並顯示簡介屏幕

dev_update_off ()
dev_close_window ()
dev_open_window_fit_image (Image, 0, 0, -1, 500, WindowHandle)

get_window_extents (WindowHandle, WindowRow, WindowColumn, WindowWidth, WindowHeight)
get_image_size (Image, ImageWidth, ImageHeight)
Aspect := real(ImageWidth) / ImageHeight//相當於double,佔用8個字節。
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')

* Display main model and intro text*顯示主要模型和介紹文字
gen_cross_contour_xld (ModelCenter, RowFittedCircle, ColumnFittedCircle, 12, 0.0)//生成十字形
get_shape_model_contours (ModelContours, ModelID, 1)//找到模板的輪廓
hom_mat2d_identity (HomMat2DIdentity)//創建一個初始化矩陣
hom_mat2d_translate (HomMat2DIdentity, RowFittedCircle, ColumnFittedCircle, HomMat2DTranslate)//生成平移仿射變換矩陣
affine_trans_contour_xld (ModelContours, ModelAffineTrans, HomMat2DTranslate)//執行仿射變換
display_model (Image, ModelRegion, ModelCenter, ModelAffineTrans)//顯示放射變換後圖像
display_intro_text (WindowHandle)//顯示介紹文字
disp_continue_message (WindowHandle, 'black', 'true')
stop ()

* Select asymmetric edges for step 2 *爲步驟2選擇非對稱邊


AsymModelReady := 0
while (not AsymModelReady)
    * Zoom into object for better visualization *放大對象以獲得更好的可視化
    dev_set_part (RowFittedCircle - Clip, ColumnFittedCircle - Clip * Aspect, RowFittedCircle + Clip, ColumnFittedCircle + Clip * Aspect)
    * Display main model*顯示主要模型
    display_model (Image, ModelRegion, ModelCenter, ModelAffineTrans)
    * 
    * Generate model region for step 2 *生成步驟2的模型區域
    * (Interactively or automatically) *(交互式或自動)
    dev_set_color ('blue')//設置顯示顏色
    if (Interactive)
        * Let the user choose the asymmetric edges interactively *讓用戶交互選擇不對稱邊
        show_instructions (Image, ModelContours, WindowWidth, RowFittedCircle, ColumnFittedCircle, Clip, WindowHandlePolar)
        draw_refinement_region (AsymEdgesRegion, WindowHandle)
        display_model (Image, ModelRegion, ModelCenter, ModelAffineTrans)
        display_marked_edges (Image, AsymEdgesRegion, ContrastPolar)
        confirm_model (WindowHandle, RowFittedCircle, ColumnFittedCircle, Clip, AsymModelReady)
        dev_set_window (WindowHandlePolar)
        dev_close_window ()
    else
        * Use pre-defined model
        gen_rectangle1 (AsymEdgesRegion, 315, 694, 343, 711)
        AsymModelReady := 1
        * 
        * Display selected region for step 2
        * 
        display_model (Image, ModelRegion, ModelCenter, ModelAffineTrans)
        display_marked_edges (Image, AsymEdgesRegion, ContrastPolar)
        display_info_text (WindowHandle)
        disp_continue_message (WindowHandle, 'black', 'true')
        stop ()
    endif
endwhile


* **********************************************************
* Generate shape model in polar transformed image 在極座標變換的圖像中生成形狀模型
* **********************************************************

* Calculate parameters for polar transform

distance_pr (AsymEdgesRegion, RowFittedCircle, ColumnFittedCircle, RadiusInner, RadiusOuter)//獲得點到區域最大最小距離
area_center (AsymEdgesRegion, Area, RowAsymEdgesRegion, ColumnAsymEdgesRegion)
angle_lx (RowFittedCircle, ColumnFittedCircle, RowAsymEdgesRegion, ColumnAsymEdgesRegion, RefAngle)//獲得直線和X軸的夾角
PolarWidth := round(RadiusOuter * rad(360))
PolarHeight := round(RadiusOuter - RadiusInner)
* Estimate width of model region after polar transform
polar_trans_region (AsymEdgesRegion, PolarTransAsymEdgesRegion, RowFittedCircle, ColumnFittedCircle, RefAngle + rad(180), RefAngle + rad(540), RadiusInner, RadiusOuter, PolarWidth, PolarHeight, 'bilinear')//對區域極座標轉換
smallest_rectangle1 (PolarTransAsymEdgesRegion, Row1, Column1, Row2, Column2)//最小外接矩形
RegionWidth := Column2 - Column1 + 1
* Extend the polar transform by the width of the transformed model region
* to make sure, that the asymmetric part is completely visible even
* if it is near the border of the transformed image.
AngleOverlap := RegionWidth * rad(360) / PolarWidth
PolarStartAngle := RefAngle - AngleOverlap / 2
PolarEndAngle := RefAngle + rad(360) + AngleOverlap / 2
PolarAngleRangeExtended := PolarEndAngle - PolarStartAngle
PolarWidthExtended := round(RadiusOuter * PolarAngleRangeExtended)

* Perform polar transform for model image and model region
polar_trans_image_ext (Image, PolarTransModelImage, RowFittedCircle, ColumnFittedCircle, PolarStartAngle, PolarEndAngle, RadiusInner, RadiusOuter, PolarWidthExtended, PolarHeight, 'bilinear')//對圖像極座標轉換
polar_trans_region (AsymEdgesRegion, PolarTransModelRegion, RowFittedCircle, ColumnFittedCircle, PolarStartAngle, PolarStartAngle + AngleOverlap, RadiusInner, RadiusOuter, RegionWidth, PolarHeight, 'bilinear')//對區域極座標轉換

* Create shape model for the asymmetric part in polar transformed image
shape_trans (PolarTransModelRegion, RegionTrans, 'convex')//對區域形狀標轉換
reduce_domain (PolarTransModelImage, RegionTrans, PolarModelImage)
create_shape_model (PolarModelImage, 1, 0, 0, 'auto', 'auto', 'use_polarity', ContrastPolar, MinContrast, ModelIDPolar)
get_shape_model_contours (PolarModelContours, ModelIDPolar, 1)//獲得模板輪廓
* Determine reference position
find_shape_model (PolarModelImage, ModelIDPolar, 0, 0, MinScorePolar, 1, 0.0, 'least_squares', 0, Greediness, RowRefPolar, ColumnRefPolar, AngleRefPolar, ScoreRefPolar)//查找模板

* **********************************************************
* Main loop
* **********************************************************

* Init display
dev_set_part (0, 0, ImageHeight - 1, ImageWidth - 1)
dev_set_line_width (1)
dev_open_window (0, WindowWidth + 12, 1, 1, 'black', WindowHandlePolar)
set_display_font (WindowHandlePolar, 14, 'mono', 'true', 'false')

NumImages := 16
for Index := 1 to NumImages by 1
    read_image (Image, 'plastic_parts//cistern_valve_diaphragms_' + Index$'02')
    * ****************************************
    * Step 1 : First find main model roughly
    * ****************************************
    find_shape_model (Image, ModelID, 0, rad(360), MinScoreMain, 0, 0.0, 'least_squares', 0, Greediness, Row, Column, Angle, Score)
    NumMatches := |Row|
    if (NumMatches > 0)
        * **************************************************
        * Step 2: Refine search in polar transformed image
        * **************************************************
        * Init result variables
        gen_empty_obj (PolarResultImages)
        gen_empty_obj (RefinedContours)
        FinalAngle := []
        RowsPolar := []
        ColumnsPolar := []
        AnglesPolar := []
        RefinementFailed := []
        for J := 0 to NumMatches - 1 by 1
            * **************************************************
            * Refinement in polar transformed image
            * ***************************************************
            * Use more than 360° to make sure, that objects at the border are
            * also completely visible.
            polar_trans_image_ext (Image, PolarTransImage, Row[J], Column[J], PolarStartAngle, PolarEndAngle, RadiusInner, RadiusOuter, PolarWidthExtended, PolarHeight, 'bilinear')
            * Only search along the reference row
            rectangle1_domain (PolarTransImage, SearchImageReduced, RowRefPolar - Tolerance, 0, RowRefPolar + Tolerance, PolarWidthExtended - 1)
            find_shape_model (SearchImageReduced, ModelIDPolar, 0, 0, MinScorePolar, 1, 0.0, 'least_squares', 0, Greediness, RowPolar, ColumnPolar, AnglePolar, ScorePolar)
            * Evaluate results
            if (|ColumnPolar| > 0)
                * Calculate rotation angle from matching position
                * in polar transformed image.
                * (The Column represents the angle)
                * 
                FinalAngle[J] := (ColumnPolar - ColumnRefPolar) / (PolarWidthExtended - 1) * PolarAngleRangeExtended
                * 
                * Prepare visualization of polar transform
                RowsPolar[J] := RowPolar + J * PolarHeight
                ColumnsPolar[J] := ColumnPolar
                AnglesPolar[J] := AnglePolar
                * Transform polar matching result back to original image
                vector_angle_to_rigid (0, 0, 0, RowPolar, ColumnPolar, AnglePolar, HomMat2D)
                affine_trans_contour_xld (PolarModelContours, ContoursAffineTrans, HomMat2D)
                polar_trans_contour_xld_inv (ContoursAffineTrans, XYTransContour, Row[J], Column[J], PolarStartAngle, PolarEndAngle, RadiusInner, RadiusOuter, PolarWidthExtended, PolarHeight, ImageWidth, ImageHeight)
                concat_obj (RefinedContours, XYTransContour, RefinedContours)
                * 
            else
                * No match in polar image, keep first result
                FinalAngle[J] := Angle[J]
                * 
                RowsPolar[J] := RowRefPolar + J * PolarHeight
                ColumnsPolar[J] := -999
                AnglesPolar[J] := 0
                RefinementFailed := [RefinementFailed,J + 1]
            endif
            * Build a stack of polar transformed images for visualization
            concat_obj (PolarResultImages, PolarTransImage, PolarResultImages)
        endfor
        Title := 'Image ' + Index + '/' + NumImages
        display_results (Image, PolarResultImages, RefinedContours, Row, Column, Angle, RowsPolar, ColumnsPolar, AnglesPolar, FinalAngle, ColumnRefPolar, RowRefPolar, PolarWidthExtended, PolarHeight, PolarAngleRangeExtended, RefinementFailed, ModelID, ModelIDPolar, Title, WindowHandle, WindowHandlePolar)
    else
        disp_message (WindowHandle, 'No match', 'window', 12, 12, 'black', 'true')
    endif
    if (Index < NumImages)
        disp_continue_message (WindowHandle, 'black', 'true')
        stop ()
    endif
endfor 


參考博客:

Halcon圖像變量 - Z大山 - 博客園 https://www.cnblogs.com/zhengzc/p/11340371.html

Halcon二維仿射變換實例探究 - xh6300 - 博客園 https://www.cnblogs.com/xh6300/p/7442164.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章