模板匹配实现仪表读数

#include “stdafx.h”
#include <opencv2/highgui/highgui_c.h>
#include “opencv2/imgproc/imgproc_c.h”
#include “opencv2/imgproc/imgproc.hpp”
#include “opencv2/highgui/highgui.hpp”
#include “opencv2/opencv.hpp”
#include <opencv2/features2d/features2d.hpp>
#include “windows.h”
#include <time.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include
#include
#include
#include
#include

#define PI 3.14159265

using namespace cv;
using namespace std;
#pragma warning(disable:4996)
static RNG rng(12345);

#pragma comment(lib,“opencv_world410d.lib”)

bool GreaterSize(vector a, vector b)
{
return (a.size() > b.size());
}

bool GreaterRadius(Vec3f a, Vec3f b)
{
return (a[2] > b[2]);
}

Mat srcImg;

void drawLine(cv::Mat &image, double theta, double rho, cv::Scalar color)
{
if (theta < PI / 4. || theta > 3.*PI / 4.)// ~vertical line
{
cv::Point pt1(rho / cos(theta), 0);
cv::Point pt2((rho - image.rows * sin(theta)) / cos(theta), image.rows);
cv::line(image, pt1, pt2, cv::Scalar(255), 1);
}
else
{
cv::Point pt1(0, rho / sin(theta));
cv::Point pt2(image.cols, (rho - image.cols * cos(theta)) / sin(theta));
cv::line(image, pt1, pt2, color, 1);
}
}

float fitLineValue(vector verCont, float start_deg, float end_deg,Point startPt,Point endPt)
{
cv::Vec4f line;
cv::fitLine(verCont, line, CV_DIST_HUBER, 0, 0.01, 0.01);
double cos_theta = line[0];
double sin_theta = line[1];
double x0 = line[2], y0 = line[3];
double phi = atan2(sin_theta, cos_theta) + PI / 2.0;
double rho = y0 * cos_theta - x0 * sin_theta;
drawLine(srcImg, phi, rho, cv::Scalar(0));
double k = sin_theta / cos_theta;
double b = y0 - k * x0;
double x = 0;
double y = k * x + b;
double deg = (atan2(cos_theta, sin_theta) ) / PI * 180;
cout << "pointer: " << deg << endl;

double cos_theta1 = endPt.x - startPt.x;
double sin_theta1 = endPt.y - startPt.y;
double deg1 = (atan2(cos_theta1, sin_theta1) ) / PI * 180;

cout <<"X axis: "<< deg1 << endl;
cv::line(srcImg, startPt, endPt, cv::Scalar(255), 1);
imshow("srcImg", srcImg);
double newDeg = deg - deg1;
double num = (( newDeg) / 270.0)*(end_deg - start_deg) + start_deg;
return num;

}

vector findTargetContour(int tmpWidth,int tmpHeight,vector<vector> curContour)
{
vector tmpContour;
Point center(tmpWidth/2, tmpHeight/2);
int width = tmpWidth /3;
int height = tmpHeight / 3;
int minx = (int)(center.x - width / 2);
int miny = (int)(center.y - width / 2);
Rect rect(minx, miny, width, height);
vector verCount;
for (int i = 0; i<curContour.size(); i++)
{
int curCount = 0;
for (int j = 0; j<curContour[i].size(); j++)
{
if (rect.contains(curContour[i][j]))
{
curCount++;
}
}
verCount.push_back(curCount);
}
int maxPosition = max_element(verCount.begin(), verCount.end()) - verCount.begin();
return curContour[maxPosition];
}

Point templateMatch(Mat frame, Mat templ, int matchType, int threshold_v, int threshold_max)
{
//模板本身也是有一定体积的,所以result的宽高只能是这样
int width = frame.cols - templ.cols + 1;
int height = frame.rows - templ.rows + 1;
//将各像素的匹配值也输出为图像
Mat result(width, height, CV_32FC1);
matchTemplate(frame, templ, result, CV_TM_CCOEFF_NORMED);

cv::Point minLoc;
cv::Point maxLoc;
double minValue, maxValue;
minMaxLoc(result, &minValue, &maxValue, &minLoc, &maxLoc, Mat());
double thresholdD = (double)threshold_v / 1000;
/*Point curCenterPt(minLoc.x + templ.rows / 2, minLoc.y - templ.cols / 2);*/

Point curCenterPt(0,0);
switch (matchType)
{
case 0://100匹配
	curCenterPt.x = maxLoc.x + templ.cols * 2 / 3;
	curCenterPt.y = maxLoc.y + templ.rows;
	break;
case 1://0匹配
	curCenterPt.x = maxLoc.x ;
	curCenterPt.y = maxLoc.y + templ.rows;
	break;
case 2://圆心匹配
	curCenterPt.x = maxLoc.x+ templ.cols/2;
	curCenterPt.y = maxLoc.y + templ.rows/2;
	break;
}


circle(frame, curCenterPt, 3, Scalar(0, 255, 0), -1, 8, 0);

//imshow();
return curCenterPt;

}

Mat rgbHSVrgb(Mat srcImg)
{
Mat tmpHsvImg;
Mat pointerImg;
//将RGB颜色空间转换为HSV颜色空间
cvtColor(srcImg, tmpHsvImg, COLOR_BGR2HSV); //CV_BGR2YCrCb
int minH = 0; //26
int maxH = 180; //34
int minS = 0; //
int maxS = 255;
int minV = 0; //200
int maxV = 26;
inRange(tmpHsvImg, Scalar(minH, minS, minV), Scalar(maxH, maxS, maxV), pointerImg);
pointerImg.convertTo(pointerImg, CV_8UC3, 255.0, 0);
Mat element = getStructuringElement(MORPH_RECT,Size(5, 5));
//morphologyEx(pointerImg, pointerImg, MORPH_CLOSE, element);
//morphologyEx(pointerImg, pointerImg, MORPH_ERODE, element);
morphologyEx(pointerImg, pointerImg, MORPH_DILATE, element);
morphologyEx(pointerImg, pointerImg, MORPH_DILATE, element);

return pointerImg;

}

Point findFurthestPt(Point cir, vector tmpNeedle)
{
vector vecDis;
//Point center(cvRound(cir[0]), cvRound(cir[1]));
float cx = cir.x;
float cy = cir.y;
for (int i = 0; i<tmpNeedle.size(); i++)
{
float curX = tmpNeedle[i].x;
float curY = tmpNeedle[i].y;
float tmpDis = sqrt(pow((cx - curX), 2) + pow((cy - curY), 2));
vecDis.push_back(tmpDis);
}
int maxPosition = max_element(vecDis.begin(), vecDis.end()) - vecDis.begin();
return tmpNeedle[maxPosition];
}

float meterDigitTemplate(Mat srcImgStart,Mat srcImgEnd,Mat srcImgCenter,Mat srcImg,float start_deg,float end_deg)
{
//当前阈值
int threshold_v = 900;
//将[0,1]部分,映射到[0,1000].
int threshold_max = 1000;
//数字匹配
int matchType = 0; //0代表100匹配
Point curEnd = templateMatch(srcImg, srcImgEnd,matchType,threshold_v, threshold_max);
matchType = 1; //1代表0匹配
Point curStart = templateMatch(srcImg, srcImgStart, matchType, threshold_v, threshold_max);
matchType = 2; //2代表圆心匹配
Point curCenter = templateMatch(srcImg, srcImgCenter,matchType, threshold_v, threshold_max);
//1:提取指针目标
Mat pointerImg = rgbHSVrgb(srcImg);//将3通道图像转化为二值图像
int nChannel = pointerImg.channels();
vector<vector> contours;
vector hierarchy;
//Mat ptrBinaryImage = convertColorToBinaryImage(pointerImg);
findContours(pointerImg, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));//发现轮廓 //findContours(pointerImg, contours, RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
std::sort(contours.begin(), contours.end(), GreaterSize);//对边界进行排序
int nWidht = srcImg.cols;
int nHeight = srcImg.rows;
vector<vector> needle;
vector tmpNeedle;
tmpNeedle = findTargetContour(nWidht, nHeight, contours);//找到指针边界
needle.push_back(tmpNeedle);
pointerImg.release();//指针图像释放
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(srcImg, needle, 0, color, 1, 8, hierarchy, 0, Point());

Point furestPt = findFurthestPt(curCenter,needle[0]);
cv::line(srcImg, furestPt, curCenter, cv::Scalar(255), 1);
imshow("srcImg", srcImg);

float deg = (PI - atan2((curCenter.y - furestPt.y), (curCenter.x - furestPt.x))) / PI * 180;
//cout << deg << endl;
float num = ((225 - deg) / 270.0)*(end_deg - start_deg) + start_deg;
//float valFitLine = fitLineValue(needle[0], start_deg, end_deg, curStart, curEnd);
return num;

}

int main()
{
Mat srcImgEnd = imread(“testdata2/100End.jpg”);
Mat srcImgStart =imread(“testdata2/0start.jpg”);
Mat srcImgCenter = imread(“testdata2/center.jpg”);
srcImg = imread(“testdata2/60.jpg”);
float start_deg = 0;
float end_deg = 100;
float meterNum = meterDigitTemplate(srcImgStart, srcImgEnd, srcImgCenter, srcImg, start_deg, end_deg);
cout << meterNum << endl;
waitKey(0);
system(“pause”);
return 0;
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值