基于C++、MFC、halcon实现视觉定位【附部分源码】

基于C++、MFC、halcon实现视觉定位【附部分源码】,第1张

文章目录
  • 前言
  • 演示视频
  • 一、项目文件目录讲解
  • 二、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的框架的资源文件入口,如图:

双击之后进入:

注意在新工程中不一定有这些配置,只需新建即可

1.首先菜单栏的设置,按照此地方设置即可

菜单栏设置入口:

打开后一次按照一下图片进行设置菜单栏








从菜单栏上可以看出,本视觉软件所具有的功能。

2.CameraSetting 的相机设置页面

先上图,只需要按照这个来设置即可:

从界面上可以看出,本相机设置具有的功能。

3.Calibration的相机标定页面设置

先上图,只需要按照这个来设置即可:

从界面上可以看出,本标定设置具有的功能。

4.ModelSetting的模板设置页面的设置

先上图,只需要按照这个来设置即可:

从界面上可以看出,本标定设置具有的功能。

5.CallMe的联系我们的页面设置

先上图,只需要按照这个来设置即可:

这里主要是只放了一个label,用来放图片

三、各文件的功能及代码实现 1.CameraSetting重要函数解析

这里主要是相机的设置,包括搜索相机,打开相机,连续采集等功能

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只需要理解整个目录结构和功能板块即可完成此模板匹配功能

本次项目的源码:(私聊)

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/3002210.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-09-27
下一篇 2022-09-27

发表评论

登录后才能评论

评论列表(0条)

保存