Halcon Review Topics-Chapter Two-Template Matching

Chapter 2 Template Matching

The main point of this chapter is in the code block. The code block is only used to show the usage and cannot be copied, because the // is used to illustrate the usage, and the comment symbol in the Halcon syntax is * not //, copying and running directly will cause an error.

The learning method of template matching is to press ctrl+e in Halcon, find examples, master the processing flow of each application scenario, and then actually fight.

Template matching is relatively simple. In general, it is to obtain a template picture first, then create a matching model, and compare the input according to the model to obtain the target object.

Template matching generally has gray matching, contour matching, correlation matching, component matching, feature descriptor matching and other methods.According to input and output, it is divided into one-to-many and many-to-many matching methods, that is, template: object=1 :n and n:n are two kinds.

In template matching, a method of displaying results is often used: affine transformation. Generally speaking, affine transformation is to display the results. After each matching is completed, the template position needs to be transferred to the target position. General operations Including: translation, rotation and zoom.

In Halcon, all operators at the beginning of disp_ indicate display.

The first section correlation matching

The output result of correlation matching is a value of 0-1, and the closer the value is to 1, the higher the degree of similarity.

Use scenes are often: when the lighting is uneven, the target has a change in light and shade, and the object has a texture change.

1.1 Correlation matching standard process

read_image (Image, 'cap_exposure/cap_exposure_03')
dev_close_window ()
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_update_off ()
gen_circle (Circle, 246, 336, 150)
area_center (Circle, Area, RowRef, ColumnRef)
reduce_domain (Image, Circle, ImageReduced)
//创建相关性匹配的模型,输入的单通道图片是你手里的模版图片,上边是生成了一个圆形图片
//create_ncc_model(输入单通道图片,金字塔层数,模板的最小旋转角度,旋转最大角度,匹配方法,输出模板模型句柄)
create_ncc_model (ImageReduced, 'auto', 0, 0, 'auto', 'use_polarity', ModelID)
// 设置绘制区域和颜色,每次设置以最后一次为准
dev_set_draw ('margin')
dev_display (Image)
dev_set_color ('yellow')
dev_display (Circle)
disp_message (WindowHandle, 'Trained NCC model', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
Rows := []
Cols := []
for J := 1 to 10 by 1
    read_image (Image, 'cap_exposure/cap_exposure_' + J$'02')
// 使用ncc模型进行匹配操作
// find_ncc_model(输入图片,模型句柄,模版最小旋转角度,模版旋转角度范围,匹配得分最小值,匹配得到的个数(0全要),最大的重叠度(0-1),是否采用亚像素精度,使用模型中金字塔第几层的模版,匹配结果的行列坐标和水平角度还有得分)
    find_ncc_model (Image, ModelID, 0, 0, 0.5, 1, 0.5, 'true', 0, Row, Column, Angle, Score)
// 仿射变换,是把原来生成的圆圈的中心点RowRef和ColumnRef移动到Row和Column处,得到一个放射矩阵HomMat2D,把这个放射矩阵放到区域图片上,就能随着目标的变化而得到新的区域
	vector_angle_to_rigid(RowRef,ColumnRef,0,Row,Column,0,HomMat2D)
// 应用到区域,输入圆圈,新的区域,放射矩阵,差值算法
	affine_trans_region(Circle,RegionAffineTrans,HomMat2D,'nearest_neighbor')
// 往数组中追加数值的格式<数组名> := [数组名,value]
// Rows := [Row]是用Row来覆盖数组原有值
    Rows := [Rows,Row]
    Cols := [Cols,Column]
    dev_display (Image)
    dev_display_ncc_matching_results (ModelID, 'green', Row, Column, Angle, 0)
    disp_message (WindowHandle, 'Found NCC model', 'window', 12, 12, 'black', 'true')
    if (J < 10)
        disp_continue_message (WindowHandle, 'black', 'true')
    endif
    stop ()
endfor
// 计算标准差,就是看看离散程度,标准差=sqrt(方差)
StdDevRows := deviation(Rows)
StdDevCols := deviation(Cols)
//清除模型
clear_ncc_model (ModelID)

1.2 Correlation matching with displayed results

dev_close_window ()
read_image (ImageRef, 'pcb_focus/pcb_focus_telecentric_061')
get_image_size (ImageRef, Width, Height)
dev_open_window_fit_image (ImageRef, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
dev_update_off ()
dev_set_draw ('margin')
dev_set_color ('green')
dev_set_line_width (1)
* 
* Create ncc model
gen_rectangle1 (ModelRegion, 81.5, 148.5, 419.5, 633.5)
reduce_domain (ImageRef, ModelRegion, TemplateImage)
dev_clear_window ()
dev_display (TemplateImage)
disp_message (WindowHandle, 'Creating the ncc model may take a few seconds ... ', 'window', 12, 12, 'black', 'true')
create_ncc_model (TemplateImage, 'auto', -rad(5), rad(10), 'auto', 'use_polarity', ModelID)

area_center (ModelRegion, Area, ModelRow, ModelColumn)
Rows := []
Columns := []
for Index := 1 to 121 by 1
    read_image (Image, 'pcb_focus/pcb_focus_telecentric_' + Index$'03' + '.png')
    find_ncc_model (Image, ModelID, -rad(5), rad(10), 0.5, 1, 0.5, 'true', 0, Row, Column, Angle, Score)
    Rows := [Rows,Row]
    Columns := [Columns,Column]
    dev_display (Image)
    dev_display_ncc_matching_results (ModelID, 'green', Row, Column, Angle, 0)
    disp_message (WindowHandle, 'Finding ncc model in image:  ' + Index$'03', 'window', 12, 12, 'white', 'false')
    flush_buffer (WindowHandle)
endfor
* 
set_window_param (WindowHandle, 'flush', 'true')
* 
* Display results
dev_display (Image)
wait_seconds (1)
gen_contour_polygon_xld (Contour, Rows, Columns)
// 拟合直线,暂时不关注
fit_line_contour_xld (Contour, 'tukey', -1, 0, 5, 2, RowBegin, ColBegin, RowEnd, ColEnd, Nr, Nc, Dist)
gen_contour_polygon_xld (Regression, [RowBegin,RowEnd], [ColBegin,ColEnd])
* Resize window so that pixels appear square
Ratio := (394 - 389 + 1) / real(252 - 250 + 1)
dev_resize_window_fit_size (0, 0, Height * Ratio, Height, 640, 480)
dev_set_part (250, 389, 252, 394)
dev_display (ImageRef)
dev_set_color ('green')
dev_display (Contour)
dev_set_color ('yellow')
dev_display (Regression)
disp_message (WindowHandle, ['Deviation of ncc matches in (x,y)-direction','while defocusing lens'], 'image', 249.75, 389, 'white', 'false')
disp_message (WindowHandle, '  Deviation (green), Tukey\'s robust regression (yellow) in pixel', 'image', 251.75, 389.25, 'white', 'false')
* 
* Close all handles
clear_ncc_model (ModelID)

Section 2 contour shape matching

Contour matching is contour shape matching, also called shape matching.In daily life, contour shape matching is the most used matching method.In short, it uses contours to find targets.This matching method has high requirements for lighting.

The process of contour shape matching is generally as follows:

2.1 The standard process of contour matching

  The following program is a contour matching method based on blob analysis

// 更新状态
dev_update_pc ('off')
dev_update_window ('off')
dev_update_var ('off')
//读取图片
read_image (Image, 'green-dot')
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
// 设置绘制区域和显示图片
dev_set_color ('red')
dev_display (Image)
// 二值化
threshold (Image, Region, 0, 128)
// 区域连接连通,独立分割
connection (Region, ConnectedRegions)
// 根据面积选择目标区域
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 10000, 20000)
// 填充区域
fill_up (SelectedRegions, RegionFillUp)
// 膨胀操作
dilation_circle (RegionFillUp, RegionDilation, 5.5)
// 抠图
reduce_domain (Image, RegionDilation, ImageReduced)


// 创建可比例缩放的形状模版,注意ncc模版创建时没有scaled即等比缩放性,显然这个形状匹配模版具有缩放性
/*
create_scaled_shape_model(Template : : NumLevels, AngleStart, AngleExtent, AngleStep, ScaleMin, ScaleMax, ScaleStep, Optimization, Metric, Contrast, MinContrast : ModelID)
*/
/* 
参数(Template模版图片,NumbLevels模板金字塔层数,AngleStart模板最小旋转角度,AngleExtent模版旋转范围,AngleStep旋转步长,ScaleMin最小缩放比例,ScaleMax最大缩放比例,ScaleStep缩放步长,Optimization优化方法,Metric匹配标准,Contrast对比度,MinContrast最小对比度,ModelID生成的形状模版模型句柄)
*/
// 对比度小一点可能比较容易找到,但是容易带来干扰
// 这个算子会直接把模型坐标放到0,0角度调整到0
create_scaled_shape_model (ImageReduced, 5, rad(-45), rad(90), 'auto', 0.8, 1.0, 'auto', 'none', 'ignore_global_polarity', 40, 10, ModelID)

// 获得形状模版金字塔中的第1层的轮廓模板,上述的形状模版是有多个形状构成,这里的轮廓也是对应的轮廓,由于这个是在上述模型上得到的所以,这个轮廓也是在坐标0,0处,角度也是0
//参数列表中的1,表示Pyramid level for which the contour representation should be returned.
get_shape_model_contours (Model, ModelID, 1)

// 获得模版图片的中心点,注意不是形状模版模型也不是形状模版轮廓模型,这一步是为了把上述的形状轮廓模型仿射变换到原来的位置
area_center (RegionFillUp, Area, RowRef, ColumnRef)

// 获得放射矩阵,由于我们已知模版模型是在0,0角度0的位置,所以直接写0就行了
vector_angle_to_rigid (0, 0, 0, RowRef, ColumnRef, 0, HomMat2D)

// 仿射变换,利用上述的放射矩阵
affine_trans_contour_xld (Model, ModelTrans, HomMat2D)

// 到这里已经完成了把轮廓形状模型模版放射变换到指定位置了
dev_display (Image)
dev_display (ModelTrans)
read_image (ImageSearch, 'green-dots')
dev_display (ImageSearch)
//在输入图片中开始搜索匹配的区域
// 同样的道理,加上了scaled就表示支持模版的缩放,即使目标区域比模版大或者小也可以找到
// find_scaled_shape_model(Image输入图片, ModelID模型句柄, AngleStart旋转初始角度, AngleExtent角度范围, ScaleMin最小缩放比例, ScaleMax最大缩放比例, MinScore匹配最小得分, NumMatches匹配个数, MaxOverlap重叠率, SubPixel亚像素级精度, NumLevels模版金字塔第几层, Greediness贪心度,匹配结果的行列坐标,缩放比例和得分值:Row, Column, Angle, Scale, Score)
find_scaled_shape_model (ImageSearch, ModelID, rad(-45), rad(90), 0.8, 1.0, 0.5, 0, 0.5, 'least_squares', 5, 0.8, Row, Column, Angle, Scale, Score)
// 接下来的仿射变换,都是为了能够在各个匹配结果上,绘制一个bndbox,让我们更方便的查看具体结果
// 方法就是把我们得到的轮廓形状模版模型,根据每个匹配结果的中心坐标,旋转角度,缩放比例来仿射变换我们的模版模型,从而准确的框出来结果.
for I := 0 to |Score| - 1 by 1
// 生成恒等放射矩阵
    hom_mat2d_identity (HomMat2DIdentity)
// 生成平移放射矩阵,坐标就是平移到目标的xy坐标值
    hom_mat2d_translate (HomMat2DIdentity, Row[I], Column[I], HomMat2DTranslate)
// 生成旋转放射矩阵,旋转也是旋转到目标的角度值
    hom_mat2d_rotate (HomMat2DTranslate, Angle[I], Row[I], Column[I], HomMat2DRotate)
// 生成缩放放射矩阵,缩放比例到目标的比例值
    hom_mat2d_scale (HomMat2DRotate, Scale[I], Scale[I], Row[I], Column[I], HomMat2DScale)
// 把上述得到的形状轮廓模版模型,通过放射矩阵,准确的移动到第I个匹配结果上去
    affine_trans_contour_xld (Model, ModelTrans, HomMat2DScale)
    dev_display (ModelTrans)
endfor
clear_shape_model (ModelID)

2.2 Save the template

Introduce how to save templates

In fact, only one operator is important, namely write_shape_model()

dev_update_off ()
dev_close_window ()

read_image (Image, 'green-dot')
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
dev_display (Image)

set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_set_draw ('margin')
dev_set_color ('green')
dev_set_line_width (3)
Message := 'This example shows how to create a shape model'
Message[1] := 'for scale invariant matching and how to save'
Message[2] := 'it in a file.'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()

// 这里使用的是blob分析
threshold (Image, Region, 0, 128)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 10000, 20000)
fill_up (SelectedRegions, RegionFillUp)
dilation_circle (RegionFillUp, RegionDilation, 5.5)
dev_display (Image)
dev_display (RegionDilation)
disp_message (WindowHandle, 'Template region', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()

reduce_domain (Image, RegionDilation, ImageReduced)
// 创建一个对形状模型的检查参数,相当于提前检查一下这个模版是否可以做模版
// 参数(输入图片,输出图片金字塔,输出金字塔区域,输入图片金字塔总层数,contrast对比度)
inspect_shape_model (ImageReduced, ModelImages, ModelRegions, 1, 40)
create_scaled_shape_model (ImageReduced, 5, rad(-45), rad(90), 0, 0.8, 1.0, 0, ['none','no_pregeneration'], 'ignore_global_polarity', 40, 10, ModelID)
dev_display (Image)
dev_display (ModelRegions)
disp_message (WindowHandle, 'Regions of the shape model', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()

// 保存创建好的模型,写成.shm文件
write_shape_model (ModelID, 'green-dot.shm')
Message := 'The shape model has been saved in the file'
Message[1] := '\'green-dot.shm\'.'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
disp_end_of_program_message (WindowHandle, 'black', 'true')

clear_shape_model (ModelID)

2.3 Read the template

Introduce how to read the template file from the saved template file

dev_update_window ('off')

read_image (ModelImage, 'rings_and_nuts')
get_image_pointer1 (ModelImage, Pointer, Type, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'white', WindowHandle)
dev_set_part (0, 0, Height - 1, Width - 1)
dev_display (ModelImage)

dev_set_color ('cyan')
dev_set_draw ('margin')
dev_set_line_width (2)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()

Row := 324
Column := 279
Radius := 60
gen_circle (ROI1, Row, Column, Radius)
gen_circle (ROI2, Row, Column, 0.5 * Radius)
difference (ROI1, ROI2, ModelROI)
reduce_domain (ModelImage, ModelROI, ImageROI)
create_scaled_shape_model (ImageROI, 'auto', -rad(30), rad(60), 'auto', 0.6, 1.4, 'auto', 'none', 'use_polarity', 60, 10, ModelID)
inspect_shape_model (ImageROI, ShapeModelImage, ShapeModelRegion, 1, 30)
dev_clear_window ()
dev_display (ShapeModelRegion)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()

// 保存模型
ModelFile := 'model_nut.sbm'
write_shape_model (ModelID, ModelFile)

// 保存模型对应图片
ModelRegionFile := 'model_region_nut.png'
// write_image(输入图片,图片格式,填充颜色默认0,文件名)
write_image (ImageROI, 'png', 0, ModelRegionFile)

clear_shape_model (ModelID)

// 读取模型
read_shape_model (ModelFile, ReusedModelID)

// 获取模型一系列参数
get_shape_model_contours (ReusedShapeModel, ReusedModelID, 1)
get_shape_model_origin (ReusedModelID, ReusedRefPointRow, ReusedRefPointCol)
get_shape_model_params (ReusedModelID, NumLevels, AngleStart, AngleExtent, AngleStep, ScaleMin, ScaleMax, ScaleStep, Metric, MinContrast)

read_image (ImageModelRegion, 'model_region_nut.png')
// 获得区域
get_domain (ImageModelRegion, DomainModelRegion)
dev_display (ImageModelRegion)
dev_display (DomainModelRegion)
stop ()

read_image (SearchImage, 'rings_and_nuts')
dev_display (SearchImage)
find_scaled_shape_model (SearchImage, ReusedModelID, AngleStart, AngleExtent, ScaleMin, ScaleMax, 0.65, 0, 0, 'least_squares', 0, 0.8, RowCheck, ColumnCheck, AngleCheck, ScaleCheck, Score)
for i := 0 to |Score| - 1 by 1
    vector_angle_to_rigid (ReusedRefPointRow, ReusedRefPointCol, 0, RowCheck[i], ColumnCheck[i], AngleCheck[i], MovementOfObject)
    hom_mat2d_scale (MovementOfObject, ScaleCheck[i], ScaleCheck[i], RowCheck[i], ColumnCheck[i], MoveAndScalingOfObject)
    affine_trans_contour_xld (ReusedShapeModel, ModelAtNewPosition, MoveAndScalingOfObject)
    dev_display (ModelAtNewPosition)
endfor
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
clear_shape_model (ModelID)

dev_update_window ('on')

2.4 Image pointer and zoom outline

//1⃣️预处理
dev_update_window ('off')
open_framegrabber ('File', 1, 1, 0, 0, 0, 0, 'default', -1, 'default', -1, 'default', 'pendulum/pendulum.seq', 'default', -1, 1, FGHandle)
grab_image (ModelImage, FGHandle)
// 获得图像指针
get_image_pointer1 (ModelImage, Pointer, Type, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
// 把图像进行放缩变换,参数就是(图像左上角坐标,右下角坐标)
dev_set_part (0, 0, Height - 1, Width - 1)
dev_display (ModelImage)
dev_set_color ('cyan')
dev_set_draw ('margin')
dev_set_line_width (2)
stop ()

//2⃣️ blob分析得到标签区域
threshold (ModelImage, BrightRegions, 200, 255)
connection (BrightRegions, ConnectedRegions)
fill_up (ConnectedRegions, FilledRegions)
dev_display (ModelImage)
dev_display (FilledRegions)
stop ()
select_shape (FilledRegions, Card, 'area', 'and', 1800, 1900)
// 目标图像进行放缩
dev_set_part (round(0.2 * Height), round(0.1 * Width) - 1, round(0.7 * Height) - 1, round(0.6 * Width) - 1)
dev_display (ModelImage)
dev_display (Card)
stop ()
reduce_domain (ModelImage, Card, ImageCard)
stop ()

//3⃣️ blob分析提取标签的logo区域
dev_set_color ('blue')
threshold (ImageCard, DarkRegions, 0, 230)
// 把独立的区域都分割开,生成新区域ConnectRegions
connection (DarkRegions, ConnectedRegions)
select_shape (ConnectedRegions, Characters, 'area', 'and', 150, 450)
// 把Characters中的区域联合起来,成一个新区域CharacterRegion
union1 (Characters, CharacterRegion)
dev_display (ModelImage)
dev_display (CharacterRegion)
stop ()
// 抠图log的时候把边缘进行膨胀操作,防止误差
dilation_circle (CharacterRegion, ROI, 1.5)
dev_display (ModelImage)
dev_display (ROI)
stop ()

// 4⃣️完成模版图片的获得,接下来进行创建模版模型
dev_set_part (0, 0, Height - 1, Width - 1)
dev_display (ModelImage)
reduce_domain (ModelImage, ROI, ImageROI)
/ //查看获得的形状模版金字塔
inspect_shape_model (ImageROI, ShapeModelImages, ShapeModelRegions, 5, 25)
//选择pyramid第几层为模版图片
select_obj (ShapeModelRegions, ShapeModelRegion, 1)
dev_display (ShapeModelRegion)
/
// 注意这个创建模版并不是可缩放的
create_shape_model (ImageROI, 3, 0, rad(360), 'auto', 'none', 'use_polarity', 30, 10, ModelID)
// 获得匹配模版轮廓
get_shape_model_contours (ShapeModel, ModelID, 1)
stop ()


//5⃣️开始匹配
for i := 1 to 30 by 1
    grab_image (SearchImage, FGHandle)
// 进行模版匹配
    find_shape_model (SearchImage, ModelID, 0, rad(360), 0.7, 1, 0.5, 'least_squares', 0, 0.5, RowCheck, ColumnCheck, AngleCheck, Score)
    if (|Score| > 0)
// 快速获得放射矩阵,参数坐标角度,目标坐标角度,输出放射矩阵
        vector_angle_to_rigid (0, 0, 0, RowCheck, ColumnCheck, AngleCheck, MovementOfObject)
        affine_trans_contour_xld (ShapeModel, ModelAtNewPosition, MovementOfObject)
        dev_display (SearchImage)
        dev_display (ModelAtNewPosition)
    endif
endfor
stop ()

dev_update_window ('on')
clear_shape_model (ModelID)
close_framegrabber (FGHandle)

2.5 Irregular contour matching

Generally speaking, if the object to be matched is a regular graph, it can be obtained through the assistant. Even when scaling is needed, it can also be scaled and matched by an operator with scale, but when it comes to irregular graphs , Often use blob analysis to cut out or directly use irregular contour matching methods

Prepare a model for unequal proportion matching , you can use the irregular contour matching method

//find_aniso_shape_model.hdev
dev_update_off ()
dev_close_window ()
set_system ('int2_bits', 10)
read_image (Image, 'smd/smd_capacitors_01')
get_image_size (Image, Width, Height)
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
dev_display (Image)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
Message := 'This program shows how to use shape-based matching'
Message[1] := 'to find SMD capacitors that exhibit independent'
Message[2] := 'size changes in the row and column direction in'
Message[3] := 'images with a depth of 10 bits.'
Message[4] := 'First a synthetic model for the SMD capacitors'
Message[5] := 'is created. In the next step the created model'
Message[6] := 'is used to find the SMD capacitors.'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
dev_set_color ('green')
dev_set_line_width (3)

// 生成一个亚像素轮廓
gen_contour_polygon_rounded_xld (Contour, [50,100,100,50,50], [50,50,150,150,50], [6,6,6,6,6], 1)
// 形成一个空的图片,里面啥也米有
gen_image_const (Image, 'byte', 200, 150)
// 根据轮廓和图片生成grayValue=128的图片,图片大小是轮廓大小,注意生成的图片像素全是128
paint_xld (Contour, Image, ImageModel, 128)
/create_aniso_shape_model(Template输入模版图片, 
			NumLevels金字塔层数,
			AngleStart,AngleExtent角度范围,
			AngleStep,ScaleRMin行方向缩放比例,
			ScaleRMax行方向缩放比例最大值,
			ScaleRStep行方向缩放比例变化步长,
			ScaleCMin,ScaleCMax,ScaleCStep列方向,
			Optimization优化方法,
			Metric度量标准,
			Contrast对比度,
			MinContrast,ModelID)
/
create_aniso_shape_model (ImageModel, 'auto', -rad(10), rad(20), 'auto', 0.9, 1.7, 'auto', 0.9, 1.1, 'auto', 'none', 'use_polarity', 'auto', 20, ModelID)

get_shape_model_contours (ModelContours, ModelID, 1)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')

for J := 1 to 4 by 1
    read_image (Image, 'smd/smd_capacitors_' + J$'02d')
    dev_display (Image)
    count_seconds (S1)
    find_aniso_shape_model (Image, ModelID, -rad(10), rad(20), 0.9, 1.7, 0.9, 1.1, 0.7, 0, 0.5, 'least_squares', 0, 0.8, Row, Column, Angle, ScaleR, ScaleC, Score)
    count_seconds (S2)
    Time := (S2 - S1) * 1000
    Num := |Score|

    disp_message (WindowHandle, Num$'d' + ' models found in ' + Time$'5.2f' + ' ms', 'window', 12, 12, 'black', 'true')
    MeanColumn := mean(Column)
    for I := 0 to Num - 1 by 1
        hom_mat2d_identity (HomMat2D)
        hom_mat2d_scale (HomMat2D, ScaleR[I], ScaleC[I], 0, 0, HomMat2D)
        hom_mat2d_rotate (HomMat2D, Angle[I], 0, 0, HomMat2D)
        hom_mat2d_translate (HomMat2D, Row[I], Column[I], HomMat2D)
        affine_trans_contour_xld (ModelContours, ContoursTrans, HomMat2D)
        dev_display (ContoursTrans)

        ScaleRowStr := 'ScaleRow=' + ScaleR[I]$'5.3f'
        ScaleColStr := 'ScaleCol=' + ScaleC[I]$'5.3f'
        get_string_extents (WindowHandle, ScaleRowStr, AscentStr, DescentStr, WidthStr, HeightStr)
        if (Column[I] <= MeanColumn)
            disp_message (WindowHandle, [ScaleRowStr,ScaleColStr], 'image', Row[I] - 20, Column[I] - 60 - WidthStr, 'green', 'false')
        else
            disp_message (WindowHandle, [ScaleRowStr,ScaleColStr], 'image', Row[I] - 20, Column[I] + 60, 'green', 'false')
        endif
    endfor

    if (J < 4)
        disp_continue_message (WindowHandle, 'black', 'true')
        stop ()
    endif
endfor
clear_shape_model (ModelID)

set_system ('int2_bits', -1)

 

2.6 Contour reading

Read xld outline from DXF file

dev_update_pc ('off')
dev_update_window ('off')
dev_update_var ('off')
dev_close_window ()
dev_open_window (0, 0, 646, 482, 'black', WindowHandle)
dev_set_part (0, 0, 481, 645)
dev_set_draw ('margin')
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_set_line_width (3)

Colors := ['red','green','cyan']

gen_empty_obj (Models)
IndexS := []
IndexE := []

ModelIDs := []

for J := 1 to 3 by 1
    dev_clear_window ()
// 参数(输出读取的contours,文件路径,输入dxf文件控制参数名,控制参数值,Dxf文件被读取的状态信息)
    read_contour_xld_dxf (Contours, 'metal-part-' + J$'02', [], [], DxfStatus)
// 自定义函数,这个不在赘述,比较简单,就是把上边的contours变成一个图像
    gen_model_image_of_bright_object_with_holes (Contours, Image, 3.38, 646, 482)
    dev_display (Image)
    dev_set_color ('green')
    set_tposition (WindowHandle, 20, 20)
    write_string (WindowHandle, 'Generating shape model ' + J$'d')
    get_domain (Image, Domain)
    area_center (Domain, Area, Row, Column)

    inspect_shape_model (Image, ModelImages, ModelRegions, 1, 30)

    connection (ModelRegions, ConnectedRegions)
    select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 20, 100000)
    union1 (SelectedRegions, ModelRegions)
    gen_contours_skeleton_xld (ModelRegions, ModelContours, 1, 'filter')
    dev_set_color ('red')
    dev_display (ModelContours)
    create_shape_model (Image, 5, rad(0), rad(360), 'auto', 'pregeneration', 'use_polarity', 30, 10, ModelID)
    get_shape_model_contours (ModelCont, ModelID, 1)
    select_shape_xld (ModelCont, ModelContours, 'contlength', 'and', 20, 1000)

    count_obj (ModelContours, NumModel)
    count_obj (Models, NumModels)
    concat_obj (Models, ModelContours, Models)
    IndexS := [IndexS,NumModels + 1]
    IndexE := [IndexE,NumModels + NumModel]
    ModelIDs := [ModelIDs,ModelID]
endfor
disp_message (WindowHandle, ['Press left button to start','and stop the demo'], 'image', 50, 20, 'yellow', 'false')
get_mbutton (WindowHandle, Row1, Column1, Button1)
wait_seconds (0.5)
dev_set_color ('red')
Button := 0
ImgNo := 1
while (Button != 1)
    read_image (Image, 'metal-parts/metal-parts-' + ImgNo$'02d')
    count_seconds (S1)
    find_shape_models (Image, ModelIDs, rad(0), rad(360), 0.6, 0, 0.5, 'least_squares', 4, 0.3, Row, Column, Angle, Score, Model)
    count_seconds (S2)
    Time := (S2 - S1) * 1000.
    dev_display (Image)
    Num := |Score|
    for J := 0 to Num - 1 by 1
        * Select the correct XLD contours from the Models object.
        copy_obj (Models, ModelSelected, IndexS[Model[J]], IndexE[Model[J]] - IndexS[Model[J]] + 1)
        * Compute the transformation from the model object to
        * the current instance.
        vector_angle_to_rigid (0, 0, 0, Row[J], Column[J], Angle[J], HomMat2D)
        affine_trans_contour_xld (ModelSelected, ModelTrans, HomMat2D)
        dev_set_color (Colors[Model[J]])
        dev_display (ModelTrans)
    endfor
    if (Num == 1)
        disp_message (WindowHandle, Num$'1d' + ' object  found in ' + Time$'4.2f' + 'ms', 'image', 20, 20, 'yellow', 'false')
    else
        disp_message (WindowHandle, Num$'1d' + ' objects found in ' + Time$'4.2f' + ' ms', 'image', 20, 20, 'yellow', 'false')
    endif
    ImgNo := ImgNo + 1
    if (ImgNo > 15)
        ImgNo := 1
    endif
    dev_error_var (Error, 1)
    dev_set_check ('~give_error')
    get_mposition (WindowHandle, R, C, Button)
    dev_error_var (Error, 0)
    dev_set_check ('give_error')
    if (Error != H_MSG_TRUE)
        Button := 0
    endif
endwhile
for J := 0 to |ModelIDs| - 1 by 1
    clear_shape_model (ModelIDs[J])
endfor

The third section many-to-many component matching

In the scenario of template: object = n: n, area arrays and regular arrays are often needed for auxiliary operations

Tuple array: The following Model is used to store the array of the picture area , and the subscript starts from 1

Regular array: An array of regular control variables. The subscripts start from 0. For example, the subscripts of IndexS and IndexE and ModelIDs below all start from 0.

 

dev_update_pc ('off')
dev_update_window ('off')
dev_update_var ('off')
dev_close_window ()
dev_open_window (0, 0, 646, 482, 'black', WindowHandle)
dev_set_part (0, 0, 481, 645)
set_display_font (WindowHandle, 20, 'mono', 'true', 'false')
dev_set_draw ('margin')
dev_set_line_width (3)

Colors := ['red','green','cyan']

Row1 := [135,150,185]
Column1 := [250,170,220]
Row2 := [375,310,335]
Column2 := [355,395,375]

// 生成空的区域Models 这里的Models就像一个容器一样,用来存储轮廓
gen_empty_obj (Models)
IndexS := []
IndexE := []
ModelIDs := []

// 创建模版,存储模版
for J := 1 to 3 by 1
    read_image (Image, 'metal-parts/metal-part-model-' + J$'02d')
    dev_display (Image)
    dev_set_color ('green')
// 设置显示窗口和位置
    set_tposition (WindowHandle, 20, 20)
// 写字符串
    write_string (WindowHandle, 'Generating shape model ' + J$'d')
    gen_rectangle1 (Rectangle, 	Row1[J - 1], Column1[J - 1], Row2[J - 1], Column2[J - 1])
    area_center (Rectangle, Area, Row, Column)
    reduce_domain (Image, Rectangle, ImageReduced)
    inspect_shape_model (Image, ModelImages, ModelRegions, 1, 30)
// 连接相同连通域,独立不同区域
    connection (ModelRegions, ConnectedRegions)
// 面积过滤
    select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 20, 100000)
    union1 (SelectedRegions, ModelRegions)
// 把一个骨架转换成xld轮廓(输入轮廓骨架,输出轮廓,轮廓上点的最小数量,轮廓滤波模式)
    gen_contours_skeleton_xld (ModelRegions, ModelContours, 1, 'filter')
    dev_set_color ('red')
    dev_display (ModelContours)
    create_shape_model (ImageReduced, 5, rad(0), rad(360), 'auto', 'pregeneration', 'use_polarity', 30, 7, ModelID)
// 生成轮廓模型,注意模型位置是0,0,角度0
    get_shape_model_contours (ModelCont, ModelID, 1)
// 筛选轮廓,根据周长
    select_shape_xld (ModelCont, ModelContours, 'contlength', 'and', 20, 1000)
// 计算tuple数组中的元素个数(输入数组,输出个数)
// 计算ModelContours元素个数,给NumModel
    count_obj (ModelContours, NumModel)
// 计算Models元素个数,给NumModels
    count_obj (Models, NumModels)
// 追加轮廓(输入轮廓,输入轮廓,输出轮廓)
// 把ModelContours追加到Models
// concat_obj()无论是图像连接还是区域连接都是用这个追加. 相当于是个区域数组,它面向的对象时图形变量
// 注意这里的ModelContours包含了多个轮廓比如大小不同的轮廓,这些轮廓按1234排好顺序,第一个进入Models的轮廓模型放在Models的第一个工件空间,每次依次进入 
// 这里是把每个轮廓模版真实的追加到了Models,由于Models长度是在这一步之前求的,所以长度变量NumModels是0
    concat_obj (Models, ModelContours, Models)
// 追加元素到数组,这样的数组,面向的是控制变量
// 由于一开始Models即多轮廓组相组合的一个变量内没有放任何轮廓组,所以长度是0,所以要在索引标签IndexS上先+1,防止从0开始索引
    IndexS := [IndexS,NumModels + 1]
// 由于要把MoldeContours即轮廓模型逐个放到模型组Models内,所以把每个ModelContours包含的轮廓个数也放到索引处,可以看我拍的图片
    IndexE := [IndexE,NumModels + NumModel]
// 这里就是利用句柄把每个轮廓模块追加进了模块组Models
    ModelIDs := [ModelIDs,ModelID]
endfor

// 设置匹配识别时的显示颜色窗口参数等
dev_set_color ('yellow')
set_tposition (WindowHandle, 50, 20)
write_string (WindowHandle, 'Press left button to start')
set_tposition (WindowHandle, 80, 20)
write_string (WindowHandle, 'and stop the demo.')
get_mbutton (WindowHandle, Row3, Column3, Button1)
wait_seconds (0.5)
dev_set_color ('red')
Button := 0
ImgNo := 1
// 开始寻找匹配
while (Button != 1)
    read_image (Image, 'metal-parts/metal-parts-' + ImgNo$'02d')
// 计算时间
    count_seconds (S1)
// 注意这个函数多了个s,其实都一样,只不过这里的模型句柄,是上边我们追加得到的一个句柄组,另外输出的是匹配结果的索引值,就是你匹配到是第几个模型的实例,这里是Model即索引值,注意这里Model是索引的第几个轮廓模版模型,而不是某个模型的第几个轮廓
    find_shape_models (Image, ModelIDs, rad(0), rad(360), 0.5, 0, 0.5, 'least_squares', 0, 0.8, Row, Column, Angle, Score, Model)
    count_seconds (S2)
    Time := (S2 - S1) * 1000
    dev_display (Image)
// 求匹配结果的个数,这个||是求长度的,不是绝对值
    Num := |Score|
// 这个循环就是用来显示的,上边已经得到了匹配的RowColumAngleScore等信息
    for J := 0 to Num - 1 by 1
// copy_obj拷贝一个目标到另一个变量里
// copy_obj(Objects : ObjectsSelected : Index, NumObj : )
// 参数(输入目标,输出结果,输入目标索引值从1开始,从索引值开始拷贝的个数)
// 这里就是把Models里每个模版中的每个小轮廓,从IndexS开始到IndexE结束这些个小轮廓拷贝出来,因为Models小轮廓的坐标是从1开始的,可以看下面的图片, 
// 拷贝这些小轮廓就是为了接下来做仿射变换
// 这里indexS[Model[J]]是从第J个轮廓模版模型的第一个小轮廓在Models中的下标开始 
// 这里的indexE就是为了获得模型组中的模型的轮廓个数
        copy_obj (Models, ModelSelected, IndexS[Model[J]], IndexE[Model[J]] - IndexS[Model[J]] + 1)
// 仿射变换
        vector_angle_to_rigid (0, 0, 0, Row[J], Column[J], Angle[J], HomMat2D)
        affine_trans_contour_xld (ModelSelected, ModelTrans, HomMat2D)
        dev_set_color (Colors[Model[J]])
        dev_display (ModelTrans)
    endfor
// 写一些字符串
    dev_set_color ('yellow')
    set_tposition (WindowHandle, 20, 20)
    if (Num == 1)
        write_string (WindowHandle, Num$'1d' + ' object found in ' + Time$'4.2f' + 'ms')
    else
        write_string (WindowHandle, Num$'1d' + ' objects found in ' + Time$'4.2f' + 'ms')
    endif
    ImgNo := ImgNo + 1
    if (ImgNo > 15)
        ImgNo := 1
    endif
    dev_error_var (Error, 1)
    dev_set_check ('~give_error')
    get_mposition (WindowHandle, R, C, Button)
    dev_error_var (Error, 0)
    dev_set_check ('give_error')
    if (Error != H_MSG_TRUE)
        Button := 0
    endif
endwhile
for J := 0 to |ModelIDs| - 1 by 1
    clear_shape_model (ModelIDs[J])
endfor

 

Guess you like

Origin blog.csdn.net/Mrsherlock_/article/details/109583259