• 模式识别—最邻近模板匹配法


    简介

    在模式识别中一个最基本的方法,就是模板匹配法(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("应用最小距离法,
    自动分类识别结果为:%d"), result);
        AfxMessageBox(str, MB_OK, NULL);
    
    
        classify.LoadFile("E:\part2.bmp");
        // 最邻近模板匹配法
        classify.GetPosition();
        classify.SetFeature();
        result = classify.GetNumberByLeastDistance();
        str.Format(_T("应用最小距离法,
    自动分类识别结果为:%d"), result);
        AfxMessageBox(str, MB_OK, NULL);
    
    
        classify.LoadFile("E:\part3.bmp");
        // 最邻近模板匹配法
        classify.GetPosition();
        classify.SetFeature();
        result = classify.GetNumberByLeastDistance();
        str.Format(_T("应用最小距离法,
    自动分类识别结果为:%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;
    }
  • 相关阅读:
    java===单类设计模式之饿汉式与懒汉式
    java===数组工具类创建,并使用eclipse导出说明文档.html
    java===static关键字
    java===this关键字
    java=====二维数组应用
    java===算法思想锻炼
    【CSP-S 2019模拟】题解
    【CSP-S 2019模拟】题解
    【LOJ#2124】【HAOI2015】—树上染色(树形dp)
    【LOJ#2019】【AHOI / HNOI2017】—影魔(线段树+扫描线)
  • 原文地址:https://www.cnblogs.com/Bobby0322/p/5424346.html
Copyright © 2020-2023  润新知