opencv 使用直方图匹配数字

也是刚学opencv,参考一些资料,完成简单的数字匹配;

#pragma once
#include <iostream>
#include <opencv2/core/utils/logger.hpp>
#include <opencv2/opencv.hpp>
#include <boost/shared_array.hpp>
#include <opencv2/imgproc/types_c.h>
#include <boost/format.hpp>
#include <math.h>
#include <vector>
#include <map>
using namespace  cv;
using namespace  std;

class NumModule
{
public:
    NumModule(int num);
    NumModule();
    virtual ~NumModule();
    bool MatchImg(Mat &src);
    bool MatchImgHuSrcModel(Mat &srcimg, Mat &modelimg);
private:
    bool  GetImg();
    Point getNextMaxLoc(Mat &img, Point maxLoc, double minValue, int templatW, int templatH);
    bool  Printdigit();
    void  GetContourCoordinate(Mat &img, vector<vector<Point>>&contour);
private:
    int m_dnum;
    string strTmppath;
    vector<Mat>m_vecimg;
    map<int,int> m_mapdata;
};
#include "NumModule.h"

NumModule::NumModule()
{

}

NumModule::NumModule(int num):m_dnum(num)
{
    strTmppath = "./Image/Work/Test6/";
    m_vecimg.clear();
    m_mapdata.clear();
}

NumModule::~NumModule()
{
    
}
/*----------------------------------------------------------------
* Function :GetImg
* Description :获取模板的img
* Param  :
* Output :
* Return :bool
* Author :
* Date :2022/02/10
/----------------------------------------------------------------*/
bool NumModule::GetImg()
{
    string path = "";
    for (int i=0;i< m_dnum;i++)
    {
        path = strTmppath + to_string(i) + ".jpg";
        Mat tmp = imread(path);
        if (!tmp.data)
        {
            cout << path << "is not exist!" << endl;
            return false;
        }
        //灰度化----阈值化
        Mat  tempgray, tempthres;
        cvtColor(tmp, tempgray, CV_BGR2GRAY);
        threshold(tempgray, tempthres, 128, 255, THRESH_BINARY | THRESH_OTSU);
        m_vecimg.push_back(tempthres);
    }
    return true;
}
/*----------------------------------------------------------------
* Function :getNextMaxLoc
* Description :得到下一个匹配度高的数字坐标
* Param  :Mat &img, Point maxLoc, double minValue, int templatW, int templatH
* Output :
* Return :Point
* Author :cyf
* Date :2022/02/10
/----------------------------------------------------------------*/
Point NumModule::getNextMaxLoc(Mat &img, Point maxLoc, double minValue, int templatW, int templatH)
{
    //设置开始寻找的位置,同时为多次进入函数 不检测之前的坐标
    int startX = maxLoc.x - templatW;
    int startY = maxLoc.y - templatH;
    int endX = maxLoc.x + templatW;
    int endY = maxLoc.y + templatH;
    //卡控
    if (startX < 0 || startY < 0)
    {
        startX = startY = 0;
    }
    if (endX > (img.cols - 1) || endY > (img.rows - 1))
    {
        endX = img.cols - 1;
        endY = img.rows - 1;
    }
    //替换为最小值,因为采用了 使用归一化系数匹配,1是匹配度最高的
    for (int y = startY; y < endY; y++)
    {
        for (int x = startX; x < endX; x++)
        {
            //cvSetReal2D(&img, y, x, maxValue);
            float *data = img.ptr<float>(y);
            data[x] = minValue;
        }
    }
    double new_minValue, new_max_Value;
    Point new_minLoc, new_maxLoc;
    minMaxLoc(img, &new_minValue, &new_max_Value, &new_minLoc, &new_maxLoc);
    //imshow("result_end", img);
    return new_maxLoc;
}
/*----------------------------------------------------------------
* Function :MatchImg
* Description :匹配多个对象
* Param  :src 
* Output :
* Return :
* Author :
* Date :2022/02/10
/----------------------------------------------------------------*/
bool NumModule::MatchImg(Mat &src)
{
    do 
    {
        //灰度化----阈值化
        Mat srcgray, srcthres;
        cvtColor(src, srcgray, CV_BGR2GRAY);
        threshold(srcgray, srcthres, 128, 255, THRESH_BINARY | THRESH_OTSU);

        //得到模板图像
        if (!GetImg())
            return false;
        for (int i = 0; i < m_vecimg.size(); i++)
        {
            Mat temp = m_vecimg[i].clone();
            if (temp.empty())
            {
                cout << "子图像不存在" << endl;
                break;
            }
            //设置结果图的尺寸,根据Opencv的公式
            int srcW, srcH, templatW, templatH, resultH, resultW;
            srcW = src.cols;
            srcH = src.rows;
            templatW = temp.cols;
            templatH = temp.rows;
            if (srcW < templatW || srcH < templatH)
            {
                cout << "模板不能比原图大" << endl;
                break;
            }
            //设置输出图的大小,opencv公式计算
            Mat result;
            resultW = srcW - temp.cols + 1;
            resultH = srcH - temp.rows + 1;

            double minValue, maxValue;
            Point minLoc, maxLoc;
            result.create(Size(resultW, resultH), CV_32FC1);
            //模板匹配,使用归一化系数匹配
            matchTemplate(srcthres, m_vecimg[i], result, TM_CCOEFF_NORMED);
            //计算输出图中 的 最大最小值,和相应的坐标
            minMaxLoc(result, &minValue, &maxValue, &minLoc, &maxLoc);
            //建立循环,多目标匹配
            float *data = result.ptr<float>(maxLoc.y);
            vector<Point> mveccoordinate;
            while (data[maxLoc.x] > 0.9)
            {
                mveccoordinate.push_back(maxLoc);
                maxLoc = getNextMaxLoc(result, maxLoc, minValue, templatW, templatH);
                data = result.ptr<float>(maxLoc.y);
            }
            for (size_t k = 0; k < mveccoordinate.size(); k++)
            {
                //rectangle(src, cv::Rect(mveccoordinate[k].x, mveccoordinate[k].y, temp.cols, temp.rows), Scalar(0, 0, 255), 2, 8);
                //m_mapdata.insert(mveccoordinate[k].x, i);
                m_mapdata[mveccoordinate[k].x] = i;
            }
        }
        Printdigit();
        return true;
    } while (0);
    return false;
}
/*----------------------------------------------------------------
* Function :Printdigit
* Description : 输出匹配的数字
* Param  :
* Output :
* Return :bool
* Author :
* Date :2022/02/10
/----------------------------------------------------------------*/
bool  NumModule::Printdigit()
{
    do 
    {
        if (m_mapdata.empty())
        {
            cout << "待检测的图中没有匹配到数字" << endl;
            break;
        }
        //方法1
        for (auto it:m_mapdata)
        {
            cout << it.second;
        }
        //方法3
        /*for_each(m_mapdata.begin(), m_mapdata.end(), [](map<int,int>::reference a)
        {
            cout << a.second;
        });*/
        //方法2
/*         auto it = m_mapdata.cbegin();
//         while (it!=m_mapdata.cend())
//         {
//             cout << it->second;
//             it++;
        }*/ 
        cout << endl;
    } while (0);
    return false;
}

/*----------------------------------------------------------------
* Function ;MatchImgHuSrcModel
* Description :利用HU矩 模板匹配.
* Param  :  
* Output :
* Return :
* Author :
* Date :2022/03/08
/----------------------------------------------------------------*/
bool NumModule::MatchImgHuSrcModel(Mat&src, Mat &modelimg)
{
    Mat srcgray, srcbinary;
    Mat modelimggray, modelimgbinary;
    vector<vector<Point>> srccontours, modelcontours;


    //转换为灰度图
    cvtColor(src, srcgray, CV_BGR2GRAY);
    cvtColor(modelimg, modelimggray, CV_BGR2GRAY);

    //转换为二值化图
    threshold(srcgray, srcbinary, 128, 255, THRESH_BINARY | THRESH_OTSU);
    threshold(modelimggray, modelimgbinary, 128, 255, THRESH_BINARY | THRESH_OTSU);
    bitwise_not(srcbinary, srcbinary);
    bitwise_not(modelimgbinary, modelimgbinary);
    
    //获取轮廓
    GetContourCoordinate(srcbinary, srccontours);
    GetContourCoordinate(modelimgbinary, modelcontours);

    //模板
    Moments mm2 = moments(modelcontours[0]);
    Mat hu2;
    HuMoments(mm2, hu2);

    for (int i=0; i< srccontours.size();i++)
    {
        Moments mm = moments(srccontours[i]);
        Mat hum;
        HuMoments(mm, hum);
        //Hu矩匹配
        double dis = matchShapes(hum, hu2, CONTOURS_MATCH_I1, 0);
        if (dis<8)
        {
            drawContours(src, srccontours, i, Scalar(255, 0, 0), 2, LINE_AA);
        }
    }
    imshow("result", src);
    return 0;
}


/*----------------------------------------------------------------
* Function ;GetContourCoordinate
* Description : 获取指定图片的轮廓坐标
* Param  :
* Output :
* Return :
* Author :
* Date :2022/03/08
/----------------------------------------------------------------*/
void NumModule::GetContourCoordinate(Mat &img, vector<vector<Point>>&contours)
{
    vector<Vec4i>hierarchy;
    findContours(img, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
}
#include "NumModule.h"

void main()
{
    cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_SILENT);

    //opencv   直方图 匹配并打印所有的数字 

    Mat src = imread("./Image/Work/Test6/Test6.png");
    if (src.empty())
    {
        cout << "can't find ./Image/Work/Test6/Test6.png" << endl;
        return;
    }
    imshow("src", src);

    NumModule nmodule(10);
    nmodule.MatchImg(src);

    waitKey(0);
    system("pause");
    return;
}

需要检测的数字和模板:


测试结果如下:

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值