double getAngle(CvPoint cen, CvPoint first, CvPoint second)
{
double ma_x = first.x - cen.x;
double ma_y = first.y - cen.y;
double mb_x = second.x - cen.x;
double mb_y = second.y - cen.y;
double v1 = (ma_x*mb_x) + (ma_y*mb_y);
double ma_val = sqrt(ma_x*ma_x + ma_y*ma_y);
double mb_val = sqrt(mb_x*mb_x + mb_y*mb_y);
double cosM = v1 / (ma_val*mb_val);
double angleAMB = acos(cosM) * 180 / CV_PI;
return angleAMB;
}
double getMeterValue(CvPoint pointerCenter, CvPoint pointerEnd)
{
double angle = getAngle(pointerCenter, CvPoint(pointerCenter.x, 0), pointerEnd);
//double angleStart = 45, angleEnd = 315;
double angleStart = 30, angleEnd = 330;
double maxValue = 100;
cout << "meterAngle:" << angle << endl;
if (pointerEnd.x
angle = 180 - angle;
}
else {
angle = 180 + angle;
}
double meterValue = (abs(angle - angleStart) / (angleEnd - angleStart))*maxValue;
cout << "meterAngle:" << angle << endl;
//cout << "meterValue:" << meterValue << " Mpa" << endl;
cout << "meterValue:" << meterValue << " ℃ " << endl;
return meterValue;
}
int main()
{
//----对仪表读数进行识别处理---------------------------------------------------------
Mat srcImage = imread("000003.jpg");
if (srcImage.empty())
return -1; //双边滤波
Mat resultImage2;
bilateralFilter(srcImage, resultImage2, 25, 25 * 2, 25 / 2); //双边滤波,滤除高斯噪声
//imshow("bilateralFilterImage", resultImage2);
//灰度化处理
Mat resultImage3;
cvtColor(resultImage2, resultImage3, CV_RGB2GRAY); //把图片转化为灰度图
//namedWindow("resultImage2", 2);
//cvResizeWindow("mask", mask, nHeight);
//imshow("resultImage2", resultImage2); //在窗口my中显示image图像
//imshow("CV_RGB2GRAYImage", resultImage3);
//roiSaveImg("./roi-graymeter.jpg", resultImage3); //存储图片到文件,等待识别处理
imwrite("./roi-graymeter.jpg", resultImage3);
//namedWindow("resultImage3", 0);
////cvResizeWindow("mask", mask, nHeight);
//imshow("resultImage3", resultImage3); //在窗口my中显示image图像
//二值化处理
Mat resultImage4;
threshold(resultImage3, resultImage4, 200, 255, CV_THRESH_BINARY_INV);
//imshow("cvThresholdImage", resultImage4);
imwrite("./roi-erzhimeter.jpg", resultImage4); //存储图片到文件,等待识别处理
//-----hough变换检测圆,获取圆心并绘制圆------------------------------------------------
const char * filename = "./roi-graymeter.jpg";
IplImage * src = cvLoadImage(filename, 0);
IplImage * dst;
IplImage * color_dst;
CvMemStorage * storage = cvCreateMemStorage(0);
CvSeq * lines = 0;
int i;
CvPoint meterCenterPoint;
IplImage * img = cvLoadImage(filename, 1);
IplImage * gray = cvCreateImage(cvGetSize(img), 8, 1);
cvCvtColor(img, gray, CV_BGR2GRAY);
cvSmooth(gray, gray, CV_GAUSSIAN, 9, 9);
//cvHoughCircles(image,storage,method,dp,min_dist,p1 = 100,p2 = 100,min_radius = 0,max_radius = 0);
//method:CV_HOUGH_GRADIENT H.K于2003年发表的21HT方法
//dp检测圆心累加器的分辨率,1不变,2累加器尺寸为原图一半
//min_dist 检测到的圆心之间的最小距离。取值太小,在一个圆被分解为多个圆。太大则漏检
//p1在CV_HOUGH_GRADIENT情况下,此参数为传递给Canny边缘检测算子的两个阈值较高的那个,低阈值为其一半
//p2取值越小则误检很多不存在的圆
//min_radius 被搜索圆得最小半径,小于此半径被忽略
//max_radius 最大半径,默认为max(width,height);
CvSeq * circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, 1, gray->height /4, 160, 160, 150, 310);
//CvSeq * circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, 2, gray->height / 3.0, 100, 100, 0, 310);
float radius_max = 0, radius_tmp;
for (i = 0; i < circles->total; i++)
{
//遍历找到半径最大的圆,即表盘
float * p = (float *)cvGetSeqElem(circles, i);
radius_tmp = cvRound(p[2]);
cvCircle (img, CvPoint (cvRound (p[0]), cvRound (p[1])), 3, CV_RGB (0, 255, 0), -1, 8, 0); //绘制绿色圆心
cvCircle (img, CvPoint (cvRound (p[0]), cvRound (p[1])), radius_tmp, CV_RGB (255, 0, 0), 3, 8, 0); //绘制圆
if (radius_tmp>radius_max)
{
radius_max = radius_tmp;
meterCenterPoint = CvPoint(cvRound(p[0]), cvRound(p[1]));
}
//cvCircle(img, meterCenterPoint, radius_tmp, CV_RGB(255, 0, 0), 3, 8, 0); //绘制圆
cout << "cvCircle:" << radius_tmp << endl;
}
//cvLine(img, meterPointerEndPoint, meterCenterPoint, CV_RGB(255, 0, 0), 1, CV_AA, 0);
cvCircle(img, meterCenterPoint, radius_max, CV_RGB(255, 0, 0), 3, 8, 0); //绘制半径最大的圆
//-----------霍夫变换检测线-------------------------------------------------------------
if (!src)
{
printf("Load image error!\n");
return -1;
}
dst = cvCreateImage(cvGetSize(src), 8, 1);
color_dst = cvCreateImage(cvGetSize(src), 8, 3);
cvCanny(src, dst, 50, 100, 3);
//cvThreshold (src, dst, 70, 255, CV_THRESH_BINARY_INV);//二值化处理
cvCvtColor(dst, color_dst, CV_GRAY2BGR); //累积概率hough变换
printf("累积概率hough变换\n");
double distance = 0, distance1, distance2; //两点之间的距离
CvPoint pointO, pointA, meterPointerEndPoint; //存储仪表指针坐标点
//通过霍夫变换取得相关直线
lines = cvHoughLines2(dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180, 120, 120, 8);
//遍历圆心到各直线的距离,将最长的线段作为指针(经验值)
//计算圆心到直线上各点的距离,选择距离最大的作为指针的外端点
for (i = 0; i
{
CvPoint*line = (CvPoint*)
cvGetSeqElem(lines, i);
pointO = meterCenterPoint; //圆心的坐标
pointA = line[0]; //直线端点1
distance1 = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2);
distance1 = sqrtf(distance1);
if (distance1>distance&&distance1
distance = distance1;
meterPointerEndPoint = pointA;
}
pointA = line[1]; //直线端点2
distance2 = powf((pointO.x - pointA.x), 2) + powf((pointO.y - pointA.y), 2);
distance2 = sqrtf(distance2);
if (distance2>distance&&distance2
distance = distance2;
meterPointerEndPoint = pointA;
}
cvLine(img, line[0], line[1], CV_RGB(255, 0, 0), 1, CV_AA, 0);
//cvLine(color_dst, line[0], line[1], CV_RGB(255, 0, 0), 1, CV_AA, 0);
//cvLine(img, meterCenterPoint, line[0], CV_RGB(0, 255, 0), 1, CV_AA, 0);
//cvLine(img, meterCenterPoint, line[1], CV_RGB(0, 0, 255), 1, CV_AA, 0);
}
//绘制表针
cvLine(img, meterCenterPoint, meterPointerEndPoint, CV_RGB(105, 0, 75), 3, CV_AA, 0);
//cvNamedWindow("Source", 1);
//cvShowImage("Source", src);
//cvNamedWindow("Hough", 1);
//cvShowImage("Hough", color_dst);
float meterVaule = getMeterValue(meterCenterPoint, meterPointerEndPoint);
// cv::putText(
// cv::Mat& img, // 待绘制的图像
// const string& text, // 待绘制的文字
// cv::Point origin, // 文本框的左下角
// int fontFace, // 字体 (如cv::FONT_HERSHEY_PLAIN)
// double fontScale, // 尺寸因子,值越大文字越大
// cv::Scalar color, // 线条的颜色(RGB)
// int thickness = 1, // 线条宽度
// int lineType = 8, // 线型(4邻域或8邻域,默认8邻域)
// bool bottomLeftOrigin = false // true='origin at lower left'
// )
//设置绘制文本的相关参数:meterVaule
char str[50];
char *text;
text = gcvt(meterVaule, 4, str);//浮点数转换为字符串
string valueText(text);//转换为字符串
valueText = "value:" + valueText;
int font_face = cv::FONT_HERSHEY_COMPLEX;
double font_scale = 1;
int thickness = 2;
int baseline;
//获取文本框的长宽
cv::Size text_size = cv::getTextSize(valueText, font_face, font_scale, thickness, &baseline);
//将文本框居中绘制
cv::Point origin;
Mat imgMatTmp = cvarrToMat(img);
origin.x = imgMatTmp.cols / 2 - text_size.width / 2;
origin.y = imgMatTmp.rows / 4 + text_size.height;
putText(imgMatTmp, valueText, origin, font_face, font_scale, cv::Scalar(200, 25, 25), thickness, 8, 0);
cvShowImage("meterPointer-value", img);
cvNamedWindow("circles", 1);
cvShowImage("circles", img);
waitKey(0);
cvReleaseMemStorage(&storage);
//cvReleaseImage(&srcImage);
cvReleaseImage(&dst);
cvReleaseImage(&img);
system("pause");
return 0;
}