Halcon复习专题-第二章-模板匹配

第二章 模版匹配

本章的要点主要在代码块中,代码块仅用来展示用法,不可复制,因为用了//来说明用法,而Halcon语法中的注释符号是*并不是//,直接复制运行会error.

模版匹配的学习方法就是在Halcon中按下ctrl+e,寻找例子,掌握各个应用场景的处理流程,然后实战即可.

模版匹配比较浅显,总的来说就是先获得一个模版图片,然后创建匹配模型,根据模型来对输入进行匹配对比,从而获得目标对象.

模版匹配一般有灰度匹配、轮廓匹配、相关性匹配、组件匹配、特征描述子匹配等方法,按照输入输出来说,则分为1对多和多对多匹配方式,即模版:对象=1:n和n:n两种.

在模版匹配中,常常使用一种显示结果的方法:仿射变换.一般来说仿射变换都是为了展示结果的,每次完成匹配后,都需要把模版位置转移到目标位置上去,一般操作包括:平移、旋转和缩放.

在Halcon中,所有的disp_开头的算子都是表示显示的.

第一节 相关性匹配

相关性匹配的输出结果是0-1的数值,该数值越接近1越表示相似程度越高.

使用场景常在:光照不均匀、目标有明暗变化和物体有纹理变化情况下

1.1相关性匹配标准流程

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 带显示结果的相关性匹配

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)

第二节 轮廓形状匹配

轮廓匹配就是轮廓形状匹配也叫形状匹配,在日常中,轮廓形状匹配是使用最多的匹配方法,简而言之就是使用轮廓来寻找目标,该匹配方法对光照具有很高的要求.

轮廓形状匹配的流程一般如下:

2.1轮廓匹配标准流程

  下述程序是基于blob分析的轮廓匹配方法

// 更新状态
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保存模版

介绍保存模版的方法

实际上只有一个算子是重要的,即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读取模版

介绍如何从保存的模版文件中读取模版文件

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图像指针和缩放轮廓

//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不规则轮廓匹配

一般来说,如果待匹配的对象是规则的图形,可以通过助手获得,即使需要放缩时,也可以通过带scale的算子进行等比例的放缩匹配,但是当遇到不规则的图形时,往往采用blob分析抠图或者直接使用不规则轮廓匹配方法

准备一个模型进行不等比例的匹配,可以使用不规则轮廓匹配方法

//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轮廓的读取

从DXF文件中读取xld轮廓

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

第三节 多对多的组件匹配

在模板:对象=n:n的场景下,往往需要区域数组和常规数组来进行辅助操作

Tuple数组:下面的Model用来存储图片区域的数组,下标从1开始

常规数组:常规控制变量的数组,下标从0开始,比如下面的IndexS和IndexE和ModelIDs的下标都是从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

猜你喜欢

转载自blog.csdn.net/Mrsherlock_/article/details/109583259