模式识别—最邻近模板匹配法
简介
在模式识别中一个最基本的方法,就是模板匹配法(template matching),它基本上是一种统计识别方法。 为了在图像中检测出已知形状的目标物,我们使用这个目标物的形状模板(或窗口)与图像匹配,在约定的某种准则下检测出目标物图像,通常称其为模板匹配法。它能检测出图像中上线条、曲线、图案等等。它的应用包括:目标模板与侦察图像相匹配;文字识别和语音识别等。
原理
我们采用以下的算式来衡量模板T(m,n)与所覆盖的子图Sij(i,j)的关系,已知原始图像S(W,H),如图所示:
利用以下公式衡量它们的相似性:
上述公式中第一项为子图的能量,第三项为模板的能量,都和模板匹配无关。第二项是模板和子图的互为相关,随(i,j)而改变。当模板和子图匹配时,该项由最大值。在将其归一化后,得到模板匹配的相关系数:
当模板和子图完全一样时,相关系数R(i,j) = 1。在被搜索图S中完成全部搜索后,找出R的最大值Rmax(im,jm),其对应的子图Simjm即位匹配目标。显然,用这种公式做图像匹配计算量大、速度慢。我们可以使用另外一种算法来衡量T和Sij的误差,其公式为:
计算两个图像的向量误差,可以增加计算速度,根据不同的匹配方向选取一个误差阀值E0,当E(i,j)>E0时就停止该点的计算,继续下一点的计算。
最终的实验证明,被搜索的图像越大,匹配的速度越慢;模板越小,匹配的速度越快;阀值的大小对匹配速度影响大;
改进的模板匹配算法
将一次的模板匹配过程更改为两次匹配;
第一次匹配为粗略匹配。取模板的隔行隔列数据,即1/4的模板数据,在被搜索土上进行隔行隔列匹配,即在原图的1/4范围内匹配。由于数据量大幅减少,匹配速度显著提高。同时需要设计一个合理的误差阀值E0:
E0 = e0 * (m + 1) / 2 * (n + 1) / 2
式中:e0为各点平均的最大误差,一般取40~50即可;
m,n为模板的长宽;
第二次匹配是精确匹配。在第一次误差最小点(imin, jmin)的邻域内,即在对角点为(imin -1, jmin -1), (Imin + 1, jmin + 1)的矩形内,进行搜索匹配,得到最后结果。
流程图
算法实现的关键问题是进行匹配,求最小距离,其解决方法是和训练集的样品逐一进行距离的计算,最后找出最相邻的样品得到类别号。
程序实现
开发环境:Visual C++ 2015
图片文字分割处理
分割前图片:
分割后图片:
// 图片文字分割处理 void CHwrProjectApp::OnImgprcAll() { // TODO: 在此添加命令处理程序代码 // 声明一些必要的全局变量 CString strPathName; // 返回完整的文件路径 HDIB m_hDIB; BOOL isOpen = TRUE; // 是否打开(否则为保存) // 创建一个打开文件对话框,并返回完整的文件路径 CString filter = L"256色位图文件(*.bmp)|*.bmp||"; //文件过虑的类型 CFileDialog openFileDlg(isOpen, NULL, NULL, OFN_HIDEREADONLY | OFN_READONLY, filter, NULL); if (openFileDlg.DoModal() == IDOK) strPathName = openFileDlg.GetPathName(); else return; // 创建一个文件对象 CFile file; // 以只读模式打开文件 file.Open(strPathName, CFile::modeRead); // 读取文件到HDIB句柄中. 注意:此时只是读取位图文件中文件头之后的部分,不含文件头 m_hDIB = ::ReadDIBFile(file); // HDIB句柄: 就是一块存储位图数据的内存区域的地址 // HDIB句柄包含:位图信息头、调色板(如果有的话)、DIB图像数据 // 关闭文件 file.Close(); // 指向DIB的指针(指向位图信息头) BYTE* lpDIB = (BYTE*)::GlobalLock((HGLOBAL)m_hDIB); // 获取DIB中颜色表中的颜色数目 WORD wNumColors; wNumColors = ::DIBNumColors((char*)lpDIB); // 判断是否是256色位图 if (wNumColors != 256) { // 提示用户 MessageBox(NULL,(LPCWSTR)L"非256色位图!", (LPCWSTR)L"系统提示", MB_ICONINFORMATION | MB_OK); // 解除锁定 ::GlobalUnlock((HGLOBAL)m_hDIB); // 返回 return; } ImgprcAll(m_hDIB); MessageBox(NULL, (LPCWSTR)L"处理完成,请到目录下查看图片!", (LPCWSTR)L"系统提示", MB_ICONINFORMATION | MB_OK); }
加载template,进行识别
// 加载template void CHwrProjectApp::OnButtonOpen() { // TODO: 在此添加命令处理程序代码 // CString name = _T("111.txt"); // char *dibFileName = classify.CStringToCharArray(name); // 加载template //CString curDir; //char curdir[256]; //::GetCurrentDirectory(256, (LPWSTR)curdir); //curDir.Format(_T("%s"), curdir); // classify.LoadFile("E:\\picture.bmp"); CFile TheFile(_T("E:\\template.dat"), CFile::modeRead); CArchive ar(&TheFile, CArchive::load, 40960); TheFile.SeekToBegin(); for (int i = 0; i<10; i++) { ar >> classify.pattern[i].number; for (int n = 0; n<classify.pattern[i].number; n++) for (int j = 0; j<25; j++) { ar >> classify.pattern[i].feature[n][j]; } } ar.Close(); TheFile.Close(); //CFileDialog dlg(TRUE, _T("BMP"), _T("*.BMP"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("位图文件(*.BMP)|*.BMP|")); //if (IDOK == dlg.DoModal()) //{ // filename.Format(_T("%s"), dlg.GetPathName()); // char* dibFileName = (char*)(LPCTSTR)filename; // char *dibFileName = classify.CStringToCharArray(filename); // classify.LoadFile(dibFileName); //} int result; CString str; classify.LoadFile("E:\\part1.bmp"); // 最邻近模板匹配法 classify.GetPosition(); classify.SetFeature(); result = classify.GetNumberByLeastDistance(); str.Format(_T("应用最小距离法,\n自动分类识别结果为:%d"), result); AfxMessageBox(str, MB_OK, NULL); classify.LoadFile("E:\\part2.bmp"); // 最邻近模板匹配法 classify.GetPosition(); classify.SetFeature(); result = classify.GetNumberByLeastDistance(); str.Format(_T("应用最小距离法,\n自动分类识别结果为:%d"), result); AfxMessageBox(str, MB_OK, NULL); classify.LoadFile("E:\\part3.bmp"); // 最邻近模板匹配法 classify.GetPosition(); classify.SetFeature(); result = classify.GetNumberByLeastDistance(); str.Format(_T("应用最小距离法,\n自动分类识别结果为:%d"), result); AfxMessageBox(str, MB_OK, NULL); //MessageBox(NULL, (LPCWSTR)L"识别完成!", (LPCWSTR)L"系统提示", MB_ICONINFORMATION | MB_OK); }
识别算法
Classification.h
#pragma once #include "GetFeature.h" struct number_no { int number; int no; }; class Classification : public GetFeature { public: Classification(); ~Classification(); // 计算两个样品的匹配程度 ,返回两各样品的的匹配程度。 double pipei(double s1[], double s2[]); // 最小距离法 ,返回数字类别和编号 最邻近匹配模板法 number_no LeastDistance(); // 返回最邻近匹配模板法Result int GetNumberByLeastDistance(); };
Classification.cpp
#include "stdafx.h" #include "Classification.h" Classification::Classification() { } Classification::~Classification() { } /****************************************************************** * 函数名称:LeastDistance() * 函数类型:number_no,结构体 * 函数功能:最小距离法 ,返回数字类别和编号 ******************************************************************/ number_no Classification::LeastDistance() { double min = 10000000000; number_no number_no; for (int n = 0; n<10; n++) { for (int i = 0; i<pattern[n].number; i++) { if (pipei(pattern[n].feature[i], testsample)<min) { // 匹配的最小值 min = pipei(pattern[n].feature[i], testsample); number_no.number = n; // 样品类别 number_no.no = i; // 样品序号 } } } return number_no;// 返回手写数字的类别和序号 } int Classification::GetNumberByLeastDistance() { double min = 10000000000; number_no number_no; for (int n = 0; n<10; n++) { for (int i = 0; i<pattern[n].number; i++) { if (pipei(pattern[n].feature[i], testsample)<min) { //匹配的最小值 min = pipei(pattern[n].feature[i], testsample); number_no.number = n;//样品类别 number_no.no = i;//样品序号 } } } return number_no.number;//返回手写数字的类别和序号 } /**************************************************************** * 函数名称:pipei(double s1[], double s2[]) * 函数类型:double * 参数说明:double s1[], double s2[]:两个样品的特征 * 函数功能:计算两个样品的匹配程度 ,返回两各样品的的匹配程度。 ****************************************************************/ double Classification::pipei(double s1[], double s2[]) { double count = 0.0; for (int i = 0; i<25; i++) { count += (s1[i] - s2[i])*(s1[i] - s2[i]); } return count; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!