- 前言
- 演示视频
- 一、项目文件目录讲解
- 二、MFC软件界面的设置
- 1.首先菜单栏的设置,按照此地方设置即可
- 2.CameraSetting 的相机设置页面
- 3.Calibration的相机标定页面设置
- 4.ModelSetting的模板设置页面的设置
- 5.CallMe的联系我们的页面设置
- 三、各文件的功能及代码实现
- 1.CameraSetting重要函数解析
- 1.重要函数
- 2.查找相机函数
- 2.打开相机、关闭相机函数
- 3.获取相机属性
- 4.设置相机属性
- 2.ModelSetting重要函数解析
- 3.Calibration重要函数解析
- 1.保存标定信息
- 2.使用标定信息
- 4.主功能(ImageMatchingView)重要函数解析
- 1.重要结构体设置
- 2.软件初始化构造函数+析构函数
- 3.基于halcon窗体的初始化
- 4.载入图像函数
- 5.保存图像函数
- 6.绘制ROI区域,用作建模版
- 7.创建模板函数,以及基于灰度示例
- 8.查找模板函数,以及基于灰度示例
- 9.条形码识别函数
- 10.二维码识别函数
- 11.OCR识别函数
- 总结及源码
前言
本文主要实现基于c++做一个视觉定位识别的功能,调用halcon的dll来实现二次开发,下边从头开始设置。
编程环境:MFC
C++
halcon
IDE: VisualStudio 2010
备注:IDE环境可以根据自己电脑已经安装的内容进行使用即可,IDE环境不限制
演示视频
本次项目的效果视频:
基于c++的MFC框架实现halcon版的多模板匹配
一、项目文件目录讲解
1、Calibration.h、Calibration.cpp:主要是标定界面的逻辑函数
2、CallMe.h、CallMe.cpp:软件里边有个联系我们的按钮,这里是联系我们的界面及事件
3、CameraSetting.h、CameraSetting.cpp:主要是相机设置界面的逻辑函数
4、ModelSetting.h、ModelSetting.cpp:这里主要是模板函数,也就是模板的功能
5、MainFrm.h、MainFrm.cpp:这两个是MFC框架的源文件,主要是MFC程序启动时的一些初始窗体的设置
6、ImageMatchingView.h、ImageMatchingView.cpp:这两个是MFC框架的源文件,主要是MFC程序的试图工作
7、ImageMatchingDoc.h、ImageMatchingDoc.cpp:这两个是MFC框架的源文件,本次项目没有修改此文件
8、ImageMatching.h、ImageMatching.cpp:这两个文件时MFC框架的源文件,可以理解为主软件入口
二、MFC软件界面的设置
这里先打开MFC的框架的资源文件入口,如图:
双击之后进入:
注意在新工程中不一定有这些配置,只需新建即可
菜单栏设置入口:
打开后一次按照一下图片进行设置菜单栏
从菜单栏上可以看出,本视觉软件所具有的功能。
先上图,只需要按照这个来设置即可:
从界面上可以看出,本相机设置具有的功能。
先上图,只需要按照这个来设置即可:
从界面上可以看出,本标定设置具有的功能。
先上图,只需要按照这个来设置即可:
从界面上可以看出,本标定设置具有的功能。
先上图,只需要按照这个来设置即可:
这里主要是只放了一个label,用来放图片
这里主要是相机的设置,包括搜索相机,打开相机,连续采集等功能
1.重要函数public:
afx_msg void OnBnClickedButtonSearchimage();
afx_msg void OnBnClickedCameraconnect();
afx_msg void OnBnClickedGetoneimage();
afx_msg void OnBnClickedStartReadimage();
afx_msg void OnCbnSelchangeCameratype();
afx_msg void OnCbnSelchangeRgbzone();
afx_msg void OnNMCustomdrawExposure(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnNMCustomdrawGain(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnBnClickedAutobalance();
afx_msg void OnBnClickedAtuoexposure();
afx_msg void OnBnClickedTen();
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnBnClickedRoisetting();
2.查找相机函数
这里显示查找相机函数
void CameraSetting::OnBnClickedButtonSearchimage()
{
// TODO: 在此添加控件通知处理程序代码
if(OpenCameraFlag == true)
{
OnBnClickedCameraconnect();
Sleep(1000);
}
HTuple Information, ValueList;
HTuple hv_Length;
m_CameraList.ResetContent();
m_CameraZone.ResetContent();
const HTuple deviceNames[] = { "GigEVision","DirectShow","GenICamTL" };
for each (const HTuple name in deviceNames)
{
HalconCpp::InfoFramegrabber(name, "device", &Information, &ValueList);
HalconCpp::TupleLength(ValueList, &hv_Length);
int length1 = (int)hv_Length[0];
for (int i = 0; i<length1; i++)
{
char strDevice[128];
memset(strDevice, 0, 128);
try {
sprintf_s(strDevice, HTuple(ValueList[i]).S());
}
catch (HTupleAccessException e) {
continue;
}
if (strcmp(strDevice, "default") == 0)
{
break;
}
CString fill_name = name.ToString() + _T(":") + strDevice;
m_CameraList.AddString(fill_name);
}
}
if (m_CameraList.GetCount() > 0)
{
m_CameraList.SetCurSel(0);
OnBnClickedCameraconnect();
}
return VOID();
}
2.打开相机、关闭相机函数
这里显示打开关闭相机函数
//打开相机
void CameraSetting::OnBnClickedCameraconnect()
{
// TODO: 在此添加控件通知处理程序代码
CString Btn_Name = _T("");
GetDlgItemText(IDC_CAMERACONNECT,Btn_Name);
if(Btn_Name == _T("连接"))
{
CString Camera_Name;
m_CameraList.GetLBText(m_CameraList.GetCurSel(), Camera_Name);
CStringArray* Data = DivString(Camera_Name,_T(":"));
CString type = Data->GetAt(0);
CString name = Data->GetAt(1);
type.Replace(_T("\""), _T(""));
CAMERA_TYPE = type;
CString ColorStr;
if (m_CameraZone.GetCount() <=0)
{
if (type == _T("DirectShow"))
{
ColorStr = _T("gray");
}
else if (type == _T("GigEVision") || type == _T("GenICamTL"))
{
ColorStr = _T("default");
}
else
{
ColorStr = _T("default");
}
}
else
{
m_CameraZone.GetLBText(m_CameraZone.GetCurSel(), ColorStr);
}
HTuple Information, ValueList;
InfoFramegrabber(HTuple(CStringToChar(type)), "defaults", &Information, &ValueList);
OpenFramegrabber(HTuple(CStringToChar(type)), ValueList[0], ValueList[1], ValueList[2], ValueList[3], ValueList[4], ValueList[5], ValueList[6], ValueList[7], HTuple(CStringToChar(ColorStr))/*ValueList[8]*/, ValueList[9], ValueList[10], ValueList[11], HTuple(CStringToChar(name)), 0, ValueList[13], &hv_AcqHandle);
//初始化图像大小
GrabImageStart(hv_AcqHandle, -1);
GrabImageAsync(&ho_Image, hv_AcqHandle, -1);
GetImageSize(ho_Image,&m_Width, &m_Height);
SetPart(hv_WindowHandle,0, 0, m_Height - 1, m_Width - 1);
GetCarmerInfo(type);
OpenCameraFlag = true;
EnableCamera(OpenCameraFlag);
SetDlgItemText(IDC_CAMERACONNECT,_T("断开"));
return;
}
else
{
CString Btn_Name2 = _T("");
GetDlgItemText(IDC_START_READIMAGE,Btn_Name2);
if(Btn_Name2 == _T("停止预览"))
{
OnBnClickedStartReadimage();
}
CloseCamera();
SetDlgItemText(IDC_CAMERACONNECT,_T("连接"));
}
}
//关闭相机
void CameraSetting::CloseCamera()
{
OpenCameraFlag = false;
EnableCamera(OpenCameraFlag);
CloseFramegrabber(hv_AcqHandle);
hv_AcqHandle = HTuple();
return;
}
3.获取相机属性
void CameraSetting::GetCarmerInfo(CString CameraType)
{
//像素格式
try
{
HTuple hv_Value, hv_Length;
GetFramegrabberParam(hv_AcqHandle, "PixelFormat", &hv_Value);
TupleLength(hv_Value, &hv_Length);
int length = (int)hv_Length[0];
for (int i = 0; i < length; i++)
{
char strch[128];
memset(strch, 0, 128);
try {
sprintf_s(strch, HTuple(hv_Value[i]).S());
}
catch (HTupleAccessException e) {
continue;
}
CString fill_name = CString(strch);
m_CameraFormat.AddString(fill_name);
}
if (m_CameraFormat.GetCount() > 0)
{
m_CameraFormat.SetCurSel(0);
}
}
catch(...)
{
}
//颜色空间
try{
HTuple Information, ValueList,hv_Length;
if (m_CameraZone.GetCount() <= 0)
{
HalconCpp::InfoFramegrabber(HTuple(CStringToChar(CameraType)), "color_space", &Information, &ValueList);
HalconCpp::TupleLength(ValueList, &hv_Length);
int length1 = (int)hv_Length[0];
for (int i = 0; i < length1; i++)
{
char strch[128];
memset(strch, 0, 128);
try {
sprintf_s(strch, HTuple(ValueList[i]).S());
}
catch (HTupleAccessException e) {
continue;
}
CString fill_name = CString(strch);
m_CameraZone.AddString(fill_name);
}
if (m_CameraZone.GetCount() > 0)
{
m_CameraZone.SetCurSel(0);
}
}
}catch(...){}
//曝光时间
try {
HTuple hv_Value;
if(CameraType == _T("DirectShow"))
{
SetFramegrabberParam(hv_AcqHandle, "exposure", "auto");
//设置滑动条范围
CSliderCtrl *pSlidCtrl = (CSliderCtrl*)GetDlgItem(IDC_EXPOSURE);
pSlidCtrl->SetRange(-13, -1, TRUE);
pSlidCtrl->SetPos(-1);
CString mes;
mes.Format(_T("%d"), -1);
SetDlgItemText(IDC_STATIC_EXP, mes);
((CButton*)GetDlgItem(IDC_AtuoExpoSure))->SetCheck(true);
((CButton*)GetDlgItem(IDC_AtuoExpoSure))->EnableWindow(true);
pSlidCtrl->EnableWindow(false);
}
if(CameraType == _T("GigEVision"))
{
GetFramegrabberParam(hv_AcqHandle,"ExposureTime", &hv_Value);
int extime = int(hv_Value[0].D());
//设置滑动条范围
CSliderCtrl *pSlidCtrl = (CSliderCtrl*)GetDlgItem(IDC_EXPOSURE);
pSlidCtrl->SetRange(0, 200000, TRUE);
pSlidCtrl->SetPos(extime);
CString mes;
mes.Format(_T("%d"), extime);
SetDlgItemText(IDC_STATIC_EXP, mes);
((CButton*)GetDlgItem(IDC_AtuoExpoSure))->SetCheck(false);
((CButton*)GetDlgItem(IDC_AtuoExpoSure))->EnableWindow(false);
pSlidCtrl->EnableWindow(true);
}
}
catch (...) {
}
//增益
try
{
HTuple hv_Value;
GetFramegrabberParam(hv_AcqHandle, "Gain", &hv_Value);
int gain = hv_Value[0].D();
//设置滑动条范围
CSliderCtrl *pSlidCtrl = (CSliderCtrl*)GetDlgItem(IDC_GAIN);
pSlidCtrl->SetRange(0, 24, TRUE);
pSlidCtrl->SetPos(gain);
CString mes;
mes.Format(_T("%d"), gain);
SetDlgItemText(IDC_STATIC_GAIN, mes);
pSlidCtrl->EnableWindow(true);
}
catch(...)
{
}
}
4.设置相机属性
设置曝光时间
void CameraSetting::OnNMCustomdrawExposure(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
int pos = ((CSliderCtrl *)GetDlgItem(IDC_EXPOSURE))->GetPos();
if (oldSlid1 == pos)
return;
oldSlid1 = pos;
CString mes;
mes.Format(_T("%d"), pos);
SetDlgItemText(IDC_STATIC_EXP, mes);
if (OpenCameraFlag == true)
{
try {
if (CAMERA_TYPE == _T("GigEVision"))
SetFramegrabberParam(hv_AcqHandle, "ExposureTime", pos);
else if(CAMERA_TYPE == _T("DirectShow"))
SetFramegrabberParam(hv_AcqHandle, "exposure", pos);
}
catch (...)
{
}
}
*pResult = 0;
}
设置增益
void CameraSetting::OnNMCustomdrawGain(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
int pos = ((CSliderCtrl *)GetDlgItem(IDC_GAIN))->GetPos();
if (oldSlid2 == pos)
return;
oldSlid2 = pos;
CString mes;
mes.Format(_T("%d"), pos);
SetDlgItemText(IDC_STATIC_GAIN, mes);
if (OpenCameraFlag == true)
{
try {
SetFramegrabberParam(hv_AcqHandle, "Gain", pos);
}
catch (...)
{
}
}
*pResult = 0;
}
设置自动曝光
void CameraSetting::OnBnClickedAtuoexposure()
{
// TODO: 在此添加控件通知处理程序代码
if (((CButton*)GetDlgItem(IDC_AtuoExpoSure))->GetCheck()) //选中
{
try {
SetFramegrabberParam(hv_AcqHandle, "exposure", "auto");
}
catch (...) {
}
}
}
设置白平衡
void CameraSetting::OnBnClickedAutobalance()
{
// TODO: 在此添加控件通知处理程序代码
if (((CButton*)GetDlgItem(IDC_AUTOBALANCE))->GetCheck()) //选中
{
try {
SetFramegrabberParam(hv_AcqHandle, "white_balance", "auto");
}
catch (...) {
}
}
}
2.ModelSetting重要函数解析
这里是模板设置的一些标准信息
包括设置模板的起始角度、角度范围、识别分数、识别个数、是否变形等参数的设置
重要代码如下:
void ModelSetting::OnBnClickedSavemodel()
{
// TODO: 在此添加控件通知处理程序代码
CString MesTip=_T("");
MesTip.Format(_T("是否保存 模版%d 的参数?"),m_ModelNumCom.GetCurSel()+1);
if (MessageBox(MesTip, _T("提示"), MB_YESNO | MB_ICONWARNING) == IDNO)
{
return;
}
CString mes;
GetDlgItemText(IDC_ShowStartAngle,mes);
MyModelCom[m_ModelNumCom.GetCurSel()].startAngle = _ttoi(mes);
GetDlgItemText(IDC_ShowEndAngle,mes);
MyModelCom[m_ModelNumCom.GetCurSel()].endAngle = _ttoi(mes);
GetDlgItemText(IDC_ShowLevelNum,mes);
if(((CButton*)GetDlgItem(IDC_CHECK_AutoLeval))->GetCheck())
MyModelCom[m_ModelNumCom.GetCurSel()].Level = -1;
else
MyModelCom[m_ModelNumCom.GetCurSel()].Level = _ttoi(mes);
GetDlgItemText(IDC_ShowScore,mes);
MyModelCom[m_ModelNumCom.GetCurSel()].Score = _ttoi(mes);
MyModelCom[m_ModelNumCom.GetCurSel()].DeformationNum = m_Deformation.GetCurSel();
MyModelCom[m_ModelNumCom.GetCurSel()].MatchNum = m_FindNum.GetCurSel();
GetDlgItemText(IDC_FindModelTimeOut,mes);
MyModelCom[m_ModelNumCom.GetCurSel()].FindModelTimeOut = _ttoi(mes);
::PostMessage(ctu_Hwnd,CtuVision_MESSAGE_EVENT,0,0);
}
3.Calibration重要函数解析
这里主要是相机像素与机器人坐标系的标定和转换
1.保存标定信息void Calibration::AffineTran(int CurrentNum)
{
HTuple concat = NULL, concat1 = NULL, concat2 = NULL, concat3 = NULL;
try
{
for(int i=0;i<MyCalib[CurrentNum].Num;i++)
{
concat = concat.TupleConcat(MyCalib[CurrentNum].MyAllPoint[i].Image_X);
concat1 = concat1.TupleConcat(MyCalib[CurrentNum].MyAllPoint[i].Image_Y);
concat2 = concat2.TupleConcat(MyCalib[CurrentNum].MyAllPoint[i].Robot_X);
concat3 = concat3.TupleConcat(MyCalib[CurrentNum].MyAllPoint[i].Robot_Y);
}
RobotHommat[CurrentNum].VectorToHomMat2d(concat, concat1, concat2, concat3);
MyCalib[CurrentNum].RobotHommatFlag = true;
SetDlgItemText(IDC_OK_NG,_T("OK"));
}
catch(...)
{
DeletePoint(CurrentNum);
SetDlgItemText(IDC_OK_NG,_T("NG"));
}
}
2.使用标定信息
bool Calibration::PixelToRobot(int Num, double img_x,double img_y,double* robot_x,double* robot_y)
{
*robot_x = *robot_y = -1.0;
if (MyCalib[Num].RobotHommatFlag == true)
{
try
{
*robot_x = RobotHommat[Num].AffineTransPoint2d(img_x, img_y, robot_y);
return true;
}
catch(...) //(Exception e)
{
return false;
}
}
return false;
}
4.主功能(ImageMatchingView)重要函数解析 1.重要结构体设置
一个管理整个流程的一个变量的结构体,变量的意义在代码块解析
struct CurrentControl
{
HTuple hv_WindowHandle; //软件窗体的变量
HObject ho_Image; //软件窗体的图像变量
HTuple ho_Hight; //图像高度
HTuple ho_Width; //图像宽度
int ROIRunType; //ROI运算:并集、交集、差集
HObject ROITemp; //当前窗体的ROI变量
int ModelNum; //当前软件使用的模板号
int FindModelFun; //单钱软件使用的匹配算法
double setPartPosition; //图像在窗体显示的位置
int CurrentBarCodeType; //二维码识别类型
int CurrentDataCodeType; //条形码识别类型
//结构体里边的,用来初始化变量
CurrentControl()
{
hv_WindowHandle = -1;
ho_Hight = -1;
ho_Width = -1;
ho_Image.GenEmptyObj();
ROITemp.GenEmptyObj();
ROIRunType = 0;
ModelNum = 0;
FindModelFun=0;
setPartPosition=0.0;
CurrentBarCodeType = 6;
CurrentDataCodeType = 0;
}
};
视觉定位识别的结果的结构体
struct VisionPoint
{
double x; //识别的像素x
double y; //识别的像素y
double r; //识别的角度r
double score; //最终识别的分数
VisionPoint()
{
x=0;
y=0;
r=0;
score=0;
}
};
识别条形码、二维码、OCR的结构体
struct CodeModel
{
HObject BarCodeROI; # 条形码搜索区域
bool BarCodeROIFlag; # 是否已经设置条形码搜索区域
HObject QRCodeROI; # 二维码搜索区域
bool QRCodeROIFlag; # 是否已经设置了二维码搜索区域
HObject OCRCodeROI; # OCR的搜索区域
bool OCRCodeROIFlag; # 是否设置了OCR搜索区域
CodeModel()
{
BarCodeROI.GenEmptyObj();
BarCodeROIFlag = false;
QRCodeROI.GenEmptyObj();
QRCodeROIFlag = false;
OCRCodeROI.GenEmptyObj();
OCRCodeROIFlag = false;
}
};
2.软件初始化构造函数+析构函数
结构体设置完成之后,下边开始整个软件的初始化,包括界面变量以及模板变量的初始化
//view的构造函数
CImageMatchingView::CImageMatchingView()
{
// TODO: 在此处添加构造代码
GetMoreImageTimerFlag = false;
DrawFlag = false;
FilePath = GetWorkDir() + _T("\VisionModel");
if(!PathIsDirectory(FilePath))
CreateDirectory(FilePath,NULL);
camSet = new CameraSetting;
camSet->Create(IDD_CAMERASETTING);
modelSet = new ModelSetting;
modelSet->Create(IDD_ModelSetting);
calib = new Calibration(NULL,FilePath);
calib->Create(IDD_CALIBTION);
callme = new CallMe;
callme->Create(IDD_CALLME);
ReadModel(0,MaxModelNum);
ReadCodeROI();
}
//view的析构函数
CImageMatchingView::~CImageMatchingView()
{
delete camSet;
delete modelSet;
delete calib;
delete callme;
}
3.基于halcon窗体的初始化
窗体初始化,这里我写在了OnInitialUpdate函数
void CImageMatchingView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: 在此添加专用代码和/或调用基类
CRect cli;
GetClientRect(&cli);
SetSystem("clip_region", "false");
SetCheck("~father");
SetWindowAttr("background_color","gray");
OpenWindow(cli.top, cli.left, cli.Width(), cli.Height(), (Hlong)(this->GetSafeHwnd()), "visible", "", &MyCurrentControl.hv_WindowHandle);
SetCheck("father");
SetColor(MyCurrentControl.hv_WindowHandle,"red");
SetDraw(MyCurrentControl.hv_WindowHandle,"margin");
4.载入图像函数
载入图像功能
//载入图像
void CImageMatchingView::OnOpenimage()
{
// TODO: 在此添加命令处理程序代码
CString StrFile;
CString defExe("bmp");
CString defFileName("");
CString defFilter("Image Files(*.bmp *.jpg *.png *.tiff)|*.*|");
CFileDialog dlg(true,defExe,defFileName,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,defFilter);
dlg.m_ofn.lpstrInitialDir= _T(".\");
if(dlg.DoModal()==IDOK)
{
StrFile = dlg.GetPathName();
USES_CONVERSION;
ReadImage(&MyCurrentControl.ho_Image, T2A(StrFile));
MySetPart();
DispObj(MyCurrentControl.ho_Image, MyCurrentControl.hv_WindowHandle);
}
}
5.保存图像函数
保存图像功能
//保存图像
void CImageMatchingView::OnSaveImage()
{
if(HObjectIsNull(MyCurrentControl.ho_Image))
return;
// TODO: 在此添加命令处理程序代码
CString StrFile;
CString defExe("bmp");
CString fileDefaultName = GetTimeMes();
fileDefaultName.Append(_T(".bmp"));
USES_CONVERSION;
CString defFileName(T2A(fileDefaultName));
CString defFilter("Image Files(*.bmp)|*.*|");
CFileDialog dlg(false,defExe,defFileName,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,defFilter);
dlg.m_ofn.lpstrInitialDir= _T(".\");
if(dlg.DoModal()==IDOK)
{
StrFile = dlg.GetPathName();
USES_CONVERSION;
WriteImage(MyCurrentControl.ho_Image,"bmp",0,T2A(StrFile));
}
}
6.绘制ROI区域,用作建模版
绘制ROI区域
void CImageMatchingView::OnRectangle1action()
{
// TODO: 在此添加命令处理程序代码
if(HObjectIsNull(MyCurrentControl.ho_Image))
return;
HTuple hv_Row1, hv_Column1, hv_Row2, hv_Column2;
HObject ROITemp;
SetColor(MyCurrentControl.hv_WindowHandle,"red");
DrawRectangle1(MyCurrentControl.hv_WindowHandle, &hv_Row1, &hv_Column1, &hv_Row2, &hv_Column2);
GenRectangle1(&ROITemp, hv_Row1, hv_Column1, hv_Row2, hv_Column2);
if(HObjectIsNull(MyCurrentControl.ROITemp))
MyCurrentControl.ROITemp = ROITemp;
else
RunROI(ROITemp);
ShowRunROI();
}
7.创建模板函数,以及基于灰度示例
创建模板主入口
void CImageMatchingView::OnCreatemodelaction()
{
// TODO: 在此添加命令处理程序代码
if (modelSet->MyModelCom[MyCurrentControl.ModelNum].EffectiveFlag == true)
{
CString MesTip=_T("");
MesTip.Format(_T("已经存在模板%d,是否替换?"),MyCurrentControl.ModelNum+1);
if (MessageBox(MesTip, _T("提示"), MB_YESNO | MB_ICONWARNING) == IDNO)
{
MyCurrentControl.ROITemp.GenEmptyObj();
return;
}
}
if (HObjectIsNull(MyCurrentControl.ho_Image) || HObjectIsNull(MyCurrentControl.ROITemp))
{
AfxMessageBox(_T("无图或者无ROI"));
return;
}
//清空当前模板,相当于初始化
//InitModel(MyCurrentControl.ModelNum, MyCurrentControl.ModelNum + 1); //删除当前模板
//数据保存
modelSet->MyModelCom[MyCurrentControl.ModelNum].h_img = MyCurrentControl.ho_Image.Clone();
modelSet->MyModelCom[MyCurrentControl.ModelNum].h_roi = MyCurrentControl.ROITemp.Clone();
modelSet->MyModelCom[MyCurrentControl.ModelNum].TemplateAlgorithm = MyCurrentControl.FindModelFun;
modelSet->MyModelCom[MyCurrentControl.ModelNum].modelNum = MyCurrentControl.ModelNum;
bool Res = false;
if (MyCurrentControl.FindModelFun == 0)
Res = Create_ShapeModel();
else if (MyCurrentControl.FindModelFun == 1)
Res = Create_GrayModel();
else if (MyCurrentControl.FindModelFun == 2)
Res = Create_NCCModel();
else if (MyCurrentControl.FindModelFun == 3)
Res = Create_ChangeShapeModel();
else{}
if(Res ==false)
{
//模模板创建失败
InitModel(MyCurrentControl.ModelNum,MyCurrentControl.ModelNum+1);
MyCurrentControl.ROITemp.GenEmptyObj();
ShowStatusMes(_T("模板创建失败!"));
return;
}
else
{
ShowStatusMes(_T("模板创建成功!"));
}
WriteData(MyCurrentControl.ModelNum);
WriteImageROI(MyCurrentControl.ModelNum);
}
以灰度模板算法为例
bool CImageMatchingView::Create_GrayModel()
{
if (HObjectIsNull(modelSet->MyModelCom[MyCurrentControl.ModelNum].h_img) || HObjectIsNull(modelSet->MyModelCom[MyCurrentControl.ModelNum].h_roi))
return false;
HObject hv_ImageReduced;
HTuple hv_Orgin_Area;
HTuple hv_pi = HTuple(0.0).TupleAcos() * 2;
//裁减模板
ReduceDomain(modelSet->MyModelCom[MyCurrentControl.ModelNum].h_img, modelSet->MyModelCom[MyCurrentControl.ModelNum].h_roi, &hv_ImageReduced);
try{
CreateTemplateRot(hv_ImageReduced, 4, HTuple(modelSet->MyModelCom[MyCurrentControl.ModelNum].startAngle).TupleRad(), HTuple(modelSet->MyModelCom[MyCurrentControl.ModelNum].endAngle).TupleRad(), 0.0982, "sort", "original", &modelSet->MyModelCom[MyCurrentControl.ModelNum].hv_ModelID);
}catch(...)
{
return false;
}
//清空显示
ClearWindow(MyCurrentControl.hv_WindowHandle);
DispObj(modelSet->MyModelCom[MyCurrentControl.ModelNum].h_img,MyCurrentControl.hv_WindowHandle);
AreaCenter(modelSet->MyModelCom[MyCurrentControl.ModelNum].h_roi, &hv_Orgin_Area, &modelSet->MyModelCom[MyCurrentControl.ModelNum].hv_Orgin_Row, &modelSet->MyModelCom[MyCurrentControl.ModelNum].hv_Orgin_Column);
SetColor(MyCurrentControl.hv_WindowHandle,"blue");
DispObj(modelSet->MyModelCom[MyCurrentControl.ModelNum].h_roi,MyCurrentControl.hv_WindowHandle);
SetColor(MyCurrentControl.hv_WindowHandle,"green");
DispCross(MyCurrentControl.hv_WindowHandle, modelSet->MyModelCom[MyCurrentControl.ModelNum].hv_Orgin_Row, modelSet->MyModelCom[MyCurrentControl.ModelNum].hv_Orgin_Column, MyCurrentControl.ho_Width[0].I()/24, 0);
MyCurrentControl.ROITemp.GenEmptyObj();
modelSet->MyModelCom[MyCurrentControl.ModelNum].EffectiveFlag = true;
return true;
}
8.查找模板函数,以及基于灰度示例
查找模板的主入口
void CImageMatchingView::OnRunmodelaction()
{
// TODO: 在此添加命令处理程序代码
if(modelSet->MyModelCom[MyCurrentControl.ModelNum].EffectiveFlag == false)
{
MessageBox(_T("当前模板号无模板"), _T("提示"), MB_YESNO | MB_ICONWARNING);
return;
}
std::queue<VisionPoint> EachRes;
if (modelSet->MyModelCom[MyCurrentControl.ModelNum].TemplateAlgorithm == 0)
EachRes = FindModel_Shape(MyCurrentControl.ModelNum);
else if(modelSet->MyModelCom[MyCurrentControl.ModelNum].TemplateAlgorithm == 1)
EachRes = FindModel_Gray(MyCurrentControl.ModelNum);
else if(modelSet->MyModelCom[MyCurrentControl.ModelNum].TemplateAlgorithm == 2)
EachRes = FindModel_NCC(MyCurrentControl.ModelNum);
else if(modelSet->MyModelCom[MyCurrentControl.ModelNum].TemplateAlgorithm == 3)
EachRes = FindModel_ChangeShape(MyCurrentControl.ModelNum);
else{}
if(EachRes.size() == 0)
{
ShowStatusMes(_T("模板匹配失败!"));
CString mes=_T("");
mes.Format(_T("模板匹配结果:%f,%f,%f,%f"),-1.0,-1.0,-1.0,-1.0);
CMainFrame *pFrame = (CMainFrame*)AfxGetMainWnd();
pFrame->m_wndStatusBar.SetPaneText(0, mes);//修改原有的状态栏上就绪一栏的信息
}
else
{
ShowStatusMes(_T("模板匹配成功!"));
VisionPoint p = EachRes.front();
CString mes=_T("");
mes.Format(_T("模板匹配结果:%f,%f,%f,%f"),p.x,p.y,p.r,p.score);
CMainFrame *pFrame = (CMainFrame*)AfxGetMainWnd();
pFrame->m_wndStatusBar.SetPaneText(0, mes);//修改原有的状态栏上就绪一栏的信息
}
}
以灰度模板匹配为例找模板
std::queue<VisionPoint> CImageMatchingView::FindModel_Gray(int ModelNum)
{
std::queue<VisionPoint> pp;
if(HObjectIsNull(MyCurrentControl.ho_Image) || modelSet->MyModelCom[ModelNum].hv_ModelID == -1)
return pp;
HTuple hv_RowCheck = NULL, hv_ColumnCheck = NULL, hv_AngleCheck = NULL, hv_Error = NULL;
HTuple hMat2D = NULL;
HObject ho_ImageAffinTrans;
double Score = modelSet->MyModelCom[ModelNum].Score / 100.0;
HObject hv_img = MyCurrentControl.ho_Image;
if(modelSet->MyModelCom[ModelNum].SearchROIFlag)
ReduceDomain(hv_img, modelSet->MyModelCom[ModelNum].h_SearchROI, &hv_img);
BestMatchRotMg(hv_img, modelSet->MyModelCom[ModelNum].hv_ModelID, HTuple(modelSet->MyModelCom[ModelNum].startAngle).TupleRad(), HTuple(modelSet->MyModelCom[ModelNum].endAngle).TupleRad(), 100 - Score, "true", 4, &hv_RowCheck, &hv_ColumnCheck, &hv_AngleCheck, &hv_Error);
if (int(hv_Error.TupleLength()[0].D()) > 0)
{
if (Score*100 > (100 - hv_Error[0].D()))
return pp;
if (modelSet->MyModelCom[ModelNum].TargetFlag == true)
{
HTuple RowTrans = NULL, ColumnTrans = NULL;
VectorAngleToRigid(modelSet->MyModelCom[ModelNum].hv_Orgin_Row, modelSet->MyModelCom[ModelNum].hv_Orgin_Column, 0, hv_RowCheck[0].D(), hv_ColumnCheck[0].D(), hv_AngleCheck[0].D(), &hMat2D);
AffineTransPixel(hMat2D, modelSet->MyModelCom[ModelNum].hv_Target_Row, modelSet->MyModelCom[ModelNum].hv_Target_Column, &RowTrans, &ColumnTrans);
SetColor(MyCurrentControl.hv_WindowHandle,"green");
DispCross(MyCurrentControl.hv_WindowHandle, RowTrans[0].D(), ColumnTrans[0].D(), MyCurrentControl.ho_Width[0].I()/24, hv_AngleCheck[0].D());
AffineTransRegion(modelSet->MyModelCom[ModelNum].h_roi, &ho_ImageAffinTrans, hMat2D, "constant");
SetColor(MyCurrentControl.hv_WindowHandle,"blue");
DispObj(ho_ImageAffinTrans,MyCurrentControl.hv_WindowHandle);
VisionPoint tempPoint;
tempPoint.x = RowTrans[0].D();
tempPoint.y = ColumnTrans[0].D();
tempPoint.r = hv_AngleCheck[0].D() * 57.3;
tempPoint.score = 100 - hv_Error[0].D();
pp.push(tempPoint);
}
else
{
SetColor(MyCurrentControl.hv_WindowHandle, "green");
DispCross(MyCurrentControl.hv_WindowHandle, hv_RowCheck[0].D(), hv_ColumnCheck[0].D(), MyCurrentControl.ho_Width[0].I()/24, hv_AngleCheck[0].D());
VectorAngleToRigid(modelSet->MyModelCom[ModelNum].hv_Orgin_Row, modelSet->MyModelCom[ModelNum].hv_Orgin_Column, 0, hv_RowCheck[0].D(), hv_ColumnCheck[0].D(), hv_AngleCheck[0].D(), &hMat2D);
AffineTransRegion(modelSet->MyModelCom[ModelNum].h_roi, &ho_ImageAffinTrans, hMat2D, "constant");
SetColor(MyCurrentControl.hv_WindowHandle, "blue");
DispObj(ho_ImageAffinTrans,MyCurrentControl.hv_WindowHandle);
VisionPoint tempPoint;
tempPoint.x = hv_RowCheck[0].D();
tempPoint.y = hv_ColumnCheck[0].D();
tempPoint.r = hv_AngleCheck[0].D() * 57.3;
tempPoint.score = 100 - hv_Error[0].D();
pp.push(tempPoint);
}
}
//显示搜索区域
if (modelSet->MyModelCom[ModelNum].SearchROIFlag)
{
SetColor(MyCurrentControl.hv_WindowHandle, "orange");
DispObj(modelSet->MyModelCom[ModelNum].h_SearchROI,MyCurrentControl.hv_WindowHandle);
}
return pp;
}
9.条形码识别函数
条形码识别
CString CImageMatchingView::ReadBarCode()
{
if (HObjectIsNull(MyCurrentControl.ho_Image))
return _T("Code:-1");
HTuple hv_BarCodeHandle = -1, hv_DecodedDataStrings = -1, hv_BarCodeResults1 = -1,hv_DecodedDataTypes = -1;
HObject ho_SymbolRegions;
HObject hv_img = MyCurrentControl.ho_Image;
if(MyCodeCom.BarCodeROIFlag)
ReduceDomain(hv_img, MyCodeCom.BarCodeROI, &hv_img);
try{
CreateBarCodeModel(HTuple(), HTuple(), &hv_BarCodeHandle);
SetBarCodeParam(hv_BarCodeHandle, "element_size_min", 1);
FindBarCode(hv_img, &ho_SymbolRegions, hv_BarCodeHandle, "auto", &hv_DecodedDataStrings);
GetBarCodeResult(hv_BarCodeHandle, "all", "orientation", &hv_BarCodeResults1);
GetBarCodeResult(hv_BarCodeHandle, "all", "decoded_types", &hv_DecodedDataTypes);
ClearBarCodeModel(hv_BarCodeHandle);
}catch(...)
{
return _T("Code:-1");
}
if(MyCodeCom.BarCodeROIFlag)
{
SetColor(MyCurrentControl.hv_WindowHandle,"orange");
DispObj(MyCodeCom.BarCodeROI,MyCurrentControl.hv_WindowHandle);
}
SetColor(MyCurrentControl.hv_WindowHandle,"green");
DispObj(ho_SymbolRegions,MyCurrentControl.hv_WindowHandle);
CString Code = _T("");
int num = int(hv_DecodedDataStrings.TupleLength()[0].D());
if(num>0)
{
double Angle = hv_BarCodeResults1[0].D();
char CodeType[128];
memset(CodeType, 0, 128);
try {
sprintf_s(CodeType, HTuple(hv_DecodedDataTypes[0]).S());
}
catch (HTupleAccessException e) {
}
char CodeStr[128];
memset(CodeStr, 0, 128);
try {
sprintf_s(CodeStr, HTuple(hv_DecodedDataStrings[0]).S());
}
catch (HTupleAccessException e) {
}
CString ang;
ang.Format(_T("%f"),Angle);
Code = _T("") + CString(CodeType) + _T(":")+ CString(CodeStr) + _T(",") + ang;
}
if(Code == "")
Code = _T("Code:-1");
return Code;
}
10.二维码识别函数
二维码识别
CString CImageMatchingView::ReadQRCode()
{
if(HObjectIsNull(MyCurrentControl.ho_Image))
return _T("Code:-1");
HObject hv_img = MyCurrentControl.ho_Image;
if(MyCodeCom.QRCodeROIFlag)
ReduceDomain(hv_img, MyCodeCom.QRCodeROI, &hv_img);
try
{
HObject ho_SymbolXLDs;
HTuple hv_DataCodeHandle, hv_ResultHandles, hv_DecodedDataStrings;
CreateDataCode2dModel("QR Code", HTuple(), HTuple(), &hv_DataCodeHandle);
FindDataCode2d(hv_img, &ho_SymbolXLDs, hv_DataCodeHandle, HTuple(), HTuple(), &hv_ResultHandles, &hv_DecodedDataStrings);
ClearDataCode2dModel(hv_DataCodeHandle);
if(MyCodeCom.QRCodeROIFlag)
{
SetColor(MyCurrentControl.hv_WindowHandle,"orange");
DispObj(MyCodeCom.QRCodeROI,MyCurrentControl.hv_WindowHandle);
}
SetColor(MyCurrentControl.hv_WindowHandle,"green");
DispObj(ho_SymbolXLDs,MyCurrentControl.hv_WindowHandle);
CString Code = _T("");
int num = int(hv_DecodedDataStrings.TupleLength()[0].D());
if(num>0)
{
char CodeType[128];
memset(CodeType, 0, 128);
try {
sprintf_s(CodeType, HTuple(hv_DecodedDataStrings[0]).S());
}
catch (HTupleAccessException e) {
}
Code = _T("QR Code:") + CString(CodeType);
}
if(Code == "")
Code = _T("Code:-1");
return Code;
}
catch(...)
{
return _T("Code:-1");
}
}
11.OCR识别函数
OCR识别
CString CImageMatchingView::ReadOCRCode()
{
if (HObjectIsNull(MyCurrentControl.ho_Image))
return _T("Code:-1");
try{
HObject ho_Region2, ho_ConnectedRegions1,ho_SelectedRegions1,ho_SortedRegions;
HTuple hv_UsedThreshold2, hv_OCRHandle,hv_Class,hv_Confidence;
HObject hv_img = MyCurrentControl.ho_Image;
if(MyCodeCom.OCRCodeROIFlag)
ReduceDomain(hv_img, MyCodeCom.OCRCodeROI, &hv_img);
BinaryThreshold(hv_img, &ho_Region2, "max_separability", "dark", &hv_UsedThreshold2);
Connection(ho_Region2, &ho_ConnectedRegions1);
SelectShape(ho_ConnectedRegions1, &ho_SelectedRegions1, "area", "and", 150, 99999);
SortRegion(ho_SelectedRegions1, &ho_SortedRegions, "character", "true", "row");
ReadOcrClassMlp("./genicam/Industrial.omc", &hv_OCRHandle);
DoOcrMultiClassMlp(ho_SortedRegions, hv_img, hv_OCRHandle, &hv_Class, &hv_Confidence);
ClearOcrClassMlp(hv_OCRHandle);
if(MyCodeCom.OCRCodeROIFlag)
{
SetColor(MyCurrentControl.hv_WindowHandle,"orange");
DispObj(MyCodeCom.OCRCodeROI,MyCurrentControl.hv_WindowHandle);
}
int num = int(hv_Class.TupleLength()[0].D());
CString Code = _T("Code:");
for(int i=0;i<num;i++)
{
char temp[128];
memset(temp, 0, 128);
try {
sprintf_s(temp, HTuple(hv_Class[i]).S());
}
catch (HTupleAccessException e) {
}
Code = Code + CString(temp);
}
if(Code == "")
Code = _T("Code:-1");
return Code;
}
catch(...)
{
return _T("Code:-1");
}
}
总结及源码
该工程篇幅比较多,不过具体的函数在文章中已经表标明,具体的查看源码使用。
mfc调用halcon只需要理解整个目录结构和功能板块即可完成此模板匹配功能
本次项目的源码:(私聊)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)