VS2008 MFC Halcon模板匹配例子

软件操作如下

1.如下界面


2.点击“显示图片”,可得被匹配图像,如下图


3.在被匹配图像中,点击鼠标左键,移动鼠标,松开鼠标左键,可抓取需要被匹配的模板


4.点击“模板匹配”,可得匹配结果如下



程序如下:

1.如图,添加如下控件


2.Halcon在VS中的配置,在这不做说明

3.主要程序如下:

// Halcon_MFCDlg.h : 头文件
//

#pragma once
#include "HalconCpp.h"
using namespace Halcon;
// CHalcon_MFCDlg 对话框
class CHalcon_MFCDlg : public CDialog
{
// 构造
public:
	CHalcon_MFCDlg(CWnd* pParent = NULL);	// 标准构造函数

// 对话框数据
	enum { IDD = IDD_HALCON_MFC_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	afx_msg void OnBnClickedButton1();//显示图片按钮
	afx_msg void OnBnClickedButton2();//模板匹配按钮
	void OnLButtonDown(CPoint point,CRect Rect);//鼠标左键点击
	void OnLButtonUp(CPoint point,CRect Rect);//鼠标左键抬起
	BOOL PreTranslateMessage(MSG* pMsg);//捕获鼠标事件
	CPoint m_PointCicleCenter,old_center;//鼠标左键起点坐标和落点坐标
	void DrawEllipse(int x,int y,int r);//画圆
	void DrawResult(int x,int y,int r);//画模板匹配结果圆
	void MatchTemplate();//模板匹配
	Hobject  ho_Image;//图像变量
	HTuple template_windowsID,m_TemplateID;
	void dispTemplate(int x,int y,int rr);//显示匹配模板
	BOOL m_bErase;
	void MoveMouse(CPoint point,CRect Rect);
	CPen* pGrayPen; 
	 CPen* pLinePen;
	 int nRadius;//模板半径
};
// Halcon_MFCDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "Halcon_MFC.h"
#include "Halcon_MFCDlg.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CHalcon_MFCDlg 对话框




CHalcon_MFCDlg::CHalcon_MFCDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CHalcon_MFCDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CHalcon_MFCDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CHalcon_MFCDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BUTTON1, &CHalcon_MFCDlg::OnBnClickedButton1)
//	ON_WM_LBUTTONDOWN()
ON_BN_CLICKED(IDC_BUTTON2, &CHalcon_MFCDlg::OnBnClickedButton2)
END_MESSAGE_MAP()


// CHalcon_MFCDlg 消息处理程序

BOOL CHalcon_MFCDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	old_center.x = 0;
	old_center.y = 0;
	pGrayPen = new CPen(0, 1, RGB(100, 100, 100));
	pLinePen = new CPen(0, 1, RGB(250, 0, 0));

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CHalcon_MFCDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CHalcon_MFCDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CHalcon_MFCDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CHalcon_MFCDlg::OnBnClickedButton1()
{
	 //TODO: 在此添加控件通知处理程序代码
	HTuple HWindowID,num;
	CRect Rect;
	HTuple m_HWindowID;
	HTuple m_ImageWidth,m_ImageHeight;

	read_image(&ho_Image, "keypad.png");//读取图像
//	rgb1_to_gray(ho_Image,&ho_Image);//彩色图像转灰度图像
	get_image_size(ho_Image, &m_ImageWidth, &m_ImageHeight); //获取图像大小

	
	CWnd * pWnd = GetDlgItem( IDC_STATIC);
	pWnd->GetWindowRect(&Rect);
	ScreenToClient(&Rect);//得到IDC_STATIC在窗口中的位置

	pWnd->MoveWindow(Rect.left,Rect.top,m_ImageWidth[0].I(),m_ImageHeight[0].I());//将IDC_STATIC设置成图片的大小
	HWindowID = (Hlong)pWnd->m_hWnd;//获取父窗口句柄
	pWnd->GetWindowRect(&Rect);

	open_window(0,0,Rect.Width(),Rect.Height(),HWindowID,"","",&m_HWindowID );
	set_part(m_HWindowID,0,0,m_ImageHeight-1,m_ImageWidth-1);
	disp_obj(ho_Image, m_HWindowID);//在窗口中显示图像
}

void CHalcon_MFCDlg::OnLButtonDown(CPoint point,CRect lRect)
{
	if((point.x>=lRect.left && point.x<=lRect.right) && (point.y>=lRect.top && point.y<=lRect.bottom))
	{
		//获取鼠标左键点下时,光标在IDC_STATIC的坐标
		m_PointCicleCenter.x = point.x-lRect.left;
		m_PointCicleCenter.y = point.y-lRect.top;
	}
}
void CHalcon_MFCDlg::OnLButtonUp(CPoint point,CRect Rect)
{
	dispTemplate(old_center.x,old_center.y,nRadius);//显示需要被匹配的模板

	CWnd * pWnd = GetDlgItem( IDC_STATIC);
	CRect lRect;
	pWnd->GetWindowRect(&lRect);
	ScreenToClient(&lRect);

	CDC* pDC = GetDC(); // 获取设备上下文        
	pDC->SelectObject(pGrayPen); // 选取灰色笔
	pDC->SelectStockObject(NULL_BRUSH);
	pDC->SetROP2(R2_XORPEN); // 设置为异或绘图方式

	//消除视图中圆形
	if (m_bErase) { // need to erase
		pDC->Ellipse(old_center.x-nRadius +lRect.left, old_center.y-nRadius +lRect.top,
			old_center.x+nRadius + lRect.left, old_center.y+nRadius + lRect.top);
	}

	ReleaseDC(pDC); // 释放设备上下文
	m_bErase = FALSE;
}
//捕获鼠标消息
BOOL CHalcon_MFCDlg::PreTranslateMessage(MSG* pMsg)
{
	CRect Rect;
	CWnd * pWnd = GetDlgItem( IDC_STATIC);
	pWnd->GetWindowRect(&Rect);
	static BOOL flag =FALSE;
	//鼠标左键在IDC_STATIC中点下
	if (pMsg->message==WM_LBUTTONDOWN && GetDlgItem(IDC_STATIC)->GetSafeHwnd() == pMsg->hwnd)
	{
		flag = TRUE;
		OnLButtonDown(pMsg->pt,Rect);
	}
	//鼠标左键在IDC_STATIC中抬起
	if (pMsg->message== WM_LBUTTONUP && GetDlgItem(IDC_STATIC)->GetSafeHwnd() == pMsg->hwnd)
	{
		flag = FALSE;
		OnLButtonUp(pMsg->pt,Rect);
	}
	//鼠标左键在IDC_STATIC中移动
	if(flag)
	{
		if (pMsg->message== WM_MOUSEMOVE && GetDlgItem(IDC_STATIC)->GetSafeHwnd() == pMsg->hwnd)
		{
			MoveMouse(pMsg->pt,Rect);
		}
	}
	return CDialog::PreTranslateMessage(pMsg);
}

//画圆
void CHalcon_MFCDlg::DrawEllipse(int x,int y,int r) 
{ 
	CClientDC dc(this); 
	CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
	CBrush *pOldBrush=dc.SelectObject(pBrush);
	dc.Ellipse(x-r,y-r,x+r,y+r); 
	dc.SelectObject(pOldBrush); 
}

//画出模板匹配结果
void CHalcon_MFCDlg::DrawResult(int x,int y,int r) 
{ 
	CClientDC dc(this); 
	CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
	CBrush *pOldBrush=dc.SelectObject(pBrush);
	dc.Ellipse(x-r,y-r,x+r,y+r); 
	dc.SelectObject(pOldBrush); 
}

//模板匹配
void CHalcon_MFCDlg::MatchTemplate()
{
	HTuple RowNew,ColumnNew,angle,Error1;
	best_match_rot_mg(ho_Image,m_TemplateID,-0.99,0.79,40,"true",4,&RowNew,&ColumnNew,&angle,&Error1);
	if(Error1<50)
	{
		CRect rect;
		CWnd * pWnd = GetDlgItem( IDC_STATIC);
		pWnd->GetWindowRect(&rect);
		ScreenToClient(&rect);
		DrawResult(ColumnNew[0].I() + rect.left ,RowNew[0].I() + rect.top,30);
	}
	else
	{
		AfxMessageBox(_T("模板匹配失败"));
	}

}

void CHalcon_MFCDlg::OnBnClickedButton2()
{
	// TODO: 在此添加控件通知处理程序代码
	MatchTemplate();
}

//显示需要被匹配的模板
void CHalcon_MFCDlg::dispTemplate(int x,int y,int rr)
{
	Hobject region_template,region;
	HTuple template_width,template_height;
	HTuple windowsID;
	gen_circle(&region_template,(double)y,(double)x,(double)rr);
	reduce_domain(ho_Image,region_template,&region);
	crop_domain(region,&region_template);

	get_image_size(region_template, &template_width, &template_height); 
	int ii = template_width[0].I();
	CString str;
	str.Format(_T("%d"),ii);
	CWnd * pWnd = GetDlgItem( IDC_STATIC_1);
	CRect rect;
	pWnd->GetWindowRect(&rect);
	ScreenToClient(&rect);
	pWnd->MoveWindow(rect.left,rect.top,template_width[0].I(),template_height[0].I());
	windowsID = (Hlong)pWnd->m_hWnd;//获取父窗口句柄
	pWnd->GetWindowRect(&rect);
	static BOOL flag = FALSE;
	if(flag)
	{
		close_window(template_windowsID);
	}
	else
	{
		flag = TRUE;
	}
	open_window(0,0,rect.Width(),rect.Height(),windowsID,"visible","",&template_windowsID );
	set_part(template_windowsID,0,0,template_height-1,template_width-1);
	disp_obj(region_template, template_windowsID);
	create_template_rot(region,1,-0.99,0.79,0.01,"sort","original",&m_TemplateID);

}
void CHalcon_MFCDlg::MoveMouse(CPoint point2,CRect Rect)
{
	CPoint point;
	CWnd * pWnd = GetDlgItem( IDC_STATIC);
	CRect lRect;
	pWnd->GetWindowRect(&lRect);
	ScreenToClient(&lRect);
	if((point2.x>=Rect.left && point2.x<=Rect.right) && (point2.y>=Rect.top && point2.y<=Rect.bottom))
	{
		point.x = point2.x - Rect.left;
		point.y =point2.y - Rect.top;

		CDC* pDC = GetDC(); // 获取设备上下文        
		pDC->SelectObject(pGrayPen); // 选取灰色笔
		pDC->SelectStockObject(NULL_BRUSH);
		pDC->SetROP2(R2_XORPEN); // 设置为异或绘图方式
		if (m_bErase) { // need to erase
			pDC->Ellipse(old_center.x-nRadius +lRect.left, old_center.y-nRadius +lRect.top,
				old_center.x+nRadius + lRect.left, old_center.y+nRadius + lRect.top);
		}
		else // 需要擦除为假
			m_bErase = TRUE; // 设需要擦除为真
		CPoint center;
		center.x=(float(m_PointCicleCenter.x+point.x))/2;
		center.y=(float(m_PointCicleCenter.y+point.y))/2;
		nRadius=sqrt((double)(point.y-m_PointCicleCenter.y)*(point.y-m_PointCicleCenter.y)+
			(point.x-m_PointCicleCenter.x)*(point.x-m_PointCicleCenter.x))/2;
		pDC->Ellipse(center.x-nRadius +lRect.left, center.y-nRadius +lRect.top, 
			center.x+nRadius +lRect.left, center.y+nRadius + lRect.top);
		old_center=center;
		ReleaseDC(pDC); // 释放设备上下文
	}
}





评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值