也是刚学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;
}
需要检测的数字和模板:
测试结果如下: