前言
正在学习Halcon的例程的基于相关性的模板匹配。花了点时间做了一个简单的demo。
首先简单记录一下什么是基于相关性的模板匹配:
一、基于相关性的模板匹配
归一化相关性.NCC,(normalization cross-correlation),顾名思义,就是用于归一化待匹配目标之间的相关程度,注意这里比较的是原始像素。通过在待匹配像素位置p(px,py)构建3*3邻域匹配窗口,与目标像素位置p’(px+d,py)同样构建邻域匹配窗口的方式建立目标函数来对匹配窗口进行度量相关性。它是基于图像灰度信息的匹配方法。
NCC的定义
在[-1,1]绝对尺度范围之间衡量两者的相似性。相关系数刻画了两者之间的近似程度的线性描述。一般说来,越接近于1,两者越近似的有线性关系。
二、基于相关性的模板匹配的代码实现
1.Halcon中完成基于相关性的模板匹配
在Halcon软件中,按住Ctrl+E的快捷键,打开Halcon中关于模板匹配的例程,如下图所示:
利用USB摄像头,任意选取一物体作为我的模板,参考Halcon例程实现代码如下:
* Image Acquisition 01: Code generated by Image Acquisition 01
open_framegrabber ('DirectShow', 1, 1, 0, 0, 0, 0, 'default', 8, 'gray', -1, 'false', 'default', '[0] ', 0, -1, AcqHandle)
grab_image_start (AcqHandle, -1)
grab_image_async (Image, AcqHandle, -1) /异步抓图
gen_rectangle2 (ROI_0, 251.392, 498.324, rad(-95.6182), 128.183, 64.3729)*利用ROI选取模板
area_center (ROI_0, Area, RowRef, ColumnRef)
reduce_domain (Image, ROI_0, ImageReduced)
dev_set_draw ('margin')
dev_display (Image)
Rows := []
Cols := []
create_ncc_model (ImageReduced, 'auto', -0.39, 0.79, 'auto', 'use_polarity', ModelID)
while (true)
grab_image_async (Image, AcqHandle, -1)
* Image Acquisition 01: Do something
find_ncc_model (Image, ModelID, 0, 360, 0.5, 1, 0.5, 'true', 0, Row, Column, Angle, Score)
if(|Score| > 0)
*vector_angle_to_rigid (Row, Column, rad(49.8188), Row, Column, Angle, HomMat2D)
*affine_trans_region (ROI_0, RegionAffineTrans, HomMat2D, 'nearest_neighbor')
Rows := [Rows,Row]
Cols := [Cols,Column]
dev_display (Image)
dev_display_ncc_matching_results (ModelID, 'green', Row, Column, Angle, 0)
dev_display (Image)
endif
endwhile
close_framegrabber (AcqHandle)
将以上Halcon代码导出为C++文件,部分代码如下:
using namespace HalconCpp;
// Procedure declarations
// Chapter: Matching / Correlation-Based
// Short Description: Display the results of Correlation-Based Matching.
void dev_display_ncc_matching_results (HTuple hv_ModelID, HTuple hv_Color, HTuple hv_Row,
HTuple hv_Column, HTuple hv_Angle, HTuple hv_Model);//函数声明
// Procedures
// Chapter: Matching / Correlation-Based
// Short Description: Display the results of Correlation-Based Matching.
void dev_display_ncc_matching_results (HTuple hv_ModelID, HTuple hv_Color, HTuple hv_Row,
HTuple hv_Column, HTuple hv_Angle, HTuple hv_Model)//函数定义
{
// Local iconic variables
HObject ho_ModelRegion, ho_ModelContours, ho_ContoursAffinTrans;
HObject ho_Cross;
// Local control variables
HTuple hv_NumMatches, hv_Index, hv_Match, hv_HomMat2DIdentity;
HTuple hv_HomMat2DRotate, hv_HomMat2DTranslate, hv_RowTrans;
HTuple hv_ColTrans;
//This procedure displays the results of Correlation-Based Matching.
//
hv_NumMatches = hv_Row.TupleLength();
if (0 != (hv_NumMatches>0))
{
if (0 != ((hv_Model.TupleLength())==0))
{
TupleGenConst(hv_NumMatches, 0, &hv_Model);
}
else if (0 != ((hv_Model.TupleLength())==1))
{
TupleGenConst(hv_NumMatches, hv_Model, &hv_Model);
}
{
HTuple end_val9 = (hv_ModelID.TupleLength())-1;
HTuple step_val9 = 1;
for (hv_Index=0; hv_Index.Continue(end_val9, step_val9); hv_Index += step_val9)
{
GetNccModelRegion(&ho_ModelRegion, HTuple(hv_ModelID[hv_Index]));
GenContourRegionXld(ho_ModelRegion, &ho_ModelContours, "border_holes");
if (HDevWindowStack::IsOpen())
SetColor(HDevWindowStack::GetActive(),HTuple(hv_Color[hv_Index%(hv_Color.TupleLength())]));
{
HTuple end_val13 = hv_NumMatches-1;
HTuple step_val13 = 1;
for (hv_Match=0; hv_Match.Continue(end_val13, step_val13); hv_Match += step_val13)
{
if (0 != (hv_Index==HTuple(hv_Model[hv_Match])))
{
HomMat2dIdentity(&hv_HomMat2DIdentity);
HomMat2dRotate(hv_HomMat2DIdentity, HTuple(hv_Angle[hv_Match]), 0, 0, &hv_HomMat2DRotate);
HomMat2dTranslate(hv_HomMat2DRotate, HTuple(hv_Row[hv_Match]), HTuple(hv_Column[hv_Match]),
&hv_HomMat2DTranslate);
AffineTransContourXld(ho_ModelContours, &ho_ContoursAffinTrans, hv_HomMat2DTranslate);
if (HDevWindowStack::IsOpen())
DispObj(ho_ContoursAffinTrans, HDevWindowStack::GetActive());
AffineTransPixel(hv_HomMat2DTranslate, 0, 0, &hv_RowTrans, &hv_ColTrans);
GenCrossContourXld(&ho_Cross, hv_RowTrans, hv_ColTrans, 6, HTuple(hv_Angle[hv_Match]));
if (HDevWindowStack::IsOpen())
DispObj(ho_Cross, HDevWindowStack::GetActive());
}
}
}
}
}
}
return;
}
void action()
{
// Local iconic variables
HObject ho_Image, ho_ROI_0, ho_ImageReduced;
// Local control variables
HTuple hv_AcqHandle, hv_Area, hv_RowRef, hv_ColumnRef;
HTuple hv_Rows, hv_Cols, hv_ModelID, hv_Row, hv_Column;
HTuple hv_Angle, hv_Score;
//Image Acquisition 01: Code generated by Image Acquisition 01
OpenFramegrabber("DirectShow", 1, 1, 0, 0, 0, 0, "default", 8, "gray", -1, "false",
"default", "[0] ", 0, -1, &hv_AcqHandle);
GrabImageStart(hv_AcqHandle, -1);
GrabImageAsync(&ho_Image, hv_AcqHandle, -1);
GenRectangle2(&ho_ROI_0, 378.959, 523.422, HTuple(86.7433).TupleRad(), 147.265,
69.2766);//此处对应的选取即为Halcon中选取的模板
AreaCenter(ho_ROI_0, &hv_Area, &hv_RowRef, &hv_ColumnRef);
ReduceDomain(ho_Image, ho_ROI_0, &ho_ImageReduced);
if (HDevWindowStack::IsOpen())
SetDraw(HDevWindowStack::GetActive(),"margin");
if (HDevWindowStack::IsOpen())
DispObj(ho_Image, HDevWindowStack::GetActive());
hv_Rows = HTuple();
hv_Cols = HTuple();
CreateNccModel(ho_ImageReduced, "auto", -0.39, 0.79, "auto", "use_polarity", &hv_ModelID);
while (0 != 1)
{
GrabImageAsync(&ho_Image, hv_AcqHandle, -1);
//Image Acquisition 01: Do something
FindNccModel(ho_Image, hv_ModelID, 0, 360, 0.5, 1, 0.5, "true", 0, &hv_Row, &hv_Column,
&hv_Angle, &hv_Score);
if (0 != ((hv_Score.TupleLength())>0))
{
hv_Rows = hv_Rows.TupleConcat(hv_Row);
hv_Cols = hv_Cols.TupleConcat(hv_Column);
if (HDevWindowStack::IsOpen())
DispObj(ho_Image, HDevWindowStack::GetActive());
dev_display_ncc_matching_results(hv_ModelID, "green", hv_Row, hv_Column, hv_Angle,
0);
if (HDevWindowStack::IsOpen())
DispObj(ho_Image, HDevWindowStack::GetActive());
//dev_display (RegionAffineTrans)
}
}
CloseFramegrabber(hv_AcqHandle);
}
2.MFC实现与Halcon混合编程
在Visual Studio 2015中运用C++运用HAlcon需要配置Halcon环境,如何配置环境可参考:
Halcon与MFC的混合编程–VC++环境配置
“https://blog.csdn.net/qq_40896597/article/details/109703054?spm=1001.2014.3001.5502”
配置好环境之后,新建MFC项目,界面编辑如下:
“采集并建立模板” 的事件和运行 “模板匹配” 的部分代码如下:
//建立模板
void CModel_MatchDlg::OnBnClickedBtnSetModel()
{
// TODO: 在此添加控件通知处理程序代码
HTuple hv_Width1;
HTuple hv_Height1; //选取的模板图片尺寸
//Image Acquisition 01: Code generated by Image Acquisition 01
OpenFramegrabber("DirectShow", 1, 1, 0, 0, 0, 0, "default", 8, "gray", -1, "false",
"default", "[0] ", 0, -1, &hv_AcqHandle);
GrabImageStart(hv_AcqHandle, -1);
//while (true)
GrabImageAsync(&ho_Image, hv_AcqHandle, -1);
//这里是在Halcon中选定的模板具体信息。需要修改
GenRectangle2(&ho_ROI_0, 420.672, 464.5, HTuple(-81.1412).TupleRad(), 103.896,51.3797);
AreaCenter(ho_ROI_0, &hv_Area, &hv_Row, &hv_Column);
ReduceDomain(ho_Image, ho_ROI_0, &ho_ImageReduced);
GrabImageAsync(&ho_Image, hv_AcqHandle, -1);
GetImageSize(ho_ImageReduced, &hv_Width1, &hv_Height1);
SetPart(m_HWindowID2, 0, 0, hv_Height1, hv_Width1);
DispObj(ho_ImageReduced, m_HWindowID2);
if (HDevWindowStack::IsOpen())
SetDraw(HDevWindowStack::GetActive(), "margin");
if (HDevWindowStack::IsOpen())
DispObj(ho_ImageReduced, HDevWindowStack::GetActive());
hv_Rows = HTuple();
hv_Cols = HTuple();
//创建模板
CreateNccModel(ho_ImageReduced, "auto", -0.39, 0.79, "auto", "use_polarity",
&hv_ModelID);
CloseFramegrabber(hv_AcqHandle);
}
部分识别模板的代码如下:
//识别模板
if (pDlg->ModelMatch)
{
FindNccModel(pDlg->ho_Image, pDlg->hv_ModelID, 0, 360, 0.5, 1, 0.5, "true", 0, &pDlg->hv_Row, &pDlg->hv_Column,
&pDlg->hv_Angle, &pDlg->hv_Score);
if (0 != ((pDlg->hv_Score.TupleLength())>0))
{
pDlg->hv_Rows = pDlg->hv_Rows.TupleConcat(pDlg->hv_Row);
pDlg->hv_Cols = pDlg->hv_Cols.TupleConcat(pDlg->hv_Column);
if (HDevWindowStack::IsOpen())
DispObj(pDlg->ho_Image, HDevWindowStack::GetActive());
pDlg->dev_display_ncc_matching_results(pDlg->hv_ModelID, "green", pDlg->hv_Row, pDlg->hv_Column, pDlg->hv_Angle,
0);
if (HDevWindowStack::IsOpen())
DispObj(pDlg->ho_Image, HDevWindowStack::GetActive());
}
}
3.实现效果
MFC与Halcon的混合编程之基于相关性的模板匹配
具体效果视频请见:https://www.bilibili.com/video/BV1Di4y1N7RD/
源代码传送地址:https://download.csdn.net/download/qq_40896597/15728138