先处理图像,滤去杂质,进行霍夫线变换,得到线段的序列,选择一根最长的线,这里简单处理,选择纵向最长的,进行角度的计算。
#include <iostream> #include <opencv2/opencv.hpp> #include <queue> #include <math.h> using namespace std; using namespace cv; int main() { IplImage * g1 = cvLoadImage("倾斜的尺子.bmp", 1);//原图 IplImage * g2 = cvCreateImage(cvSize(g1->width, g1->height), IPL_DEPTH_8U, 1);//存储灰度化后的图像 IplImage * g3 = cvCreateImage(cvSize(g1->width, g1->height), IPL_DEPTH_8U, 1);//存储二值化、腐蚀、膨胀后的图像 CvMemStorage* m_storage = cvCreateMemStorage(0); int length = 0; int maxTemp = 0; int maxLength = 0; double slope = 0;//斜率 int tubeAngle = 0;//角度 IplImage *dst = cvCloneImage(g1);//霍夫变换得到的直线画在dst上 cvShowImage("原图", g1); cvCvtColor(g1, g2, CV_BGR2GRAY);// 转化为灰度图像 cvAdaptiveThreshold(g2, g3, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 31);//自适应二值化 Mat gg3 = cv::cvarrToMat(g3); erode(gg3, gg3, Mat(2, 2, CV_8U), Point(-1, -1), 2); //腐蚀 dilate(gg3, gg3, Mat(2, 2, CV_8U), Point(-1, -1), 2); //膨胀 腐蚀膨胀为了滤出噪声点而凸显目标 cvShowImage("处理后的图像", g3); CvSeq* lines_p = cvHoughLines2(g3, m_storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI / 180, 30, 30, 10); cvZero(dst);cvGetSeqElem CvPoint* line_p; for (int i = 0; i < lines_p->total; i++) { line_p = (CvPoint*)(lines_p, i); cvLine(dst, line_p[0], line_p[1], CV_RGB(255, 255, 255), 2, CV_AA, 0); length = abs(line_p[0].y - line_p[1].y); if (i == 0) { maxLength = length; } else { if (length > maxLength) { maxTemp = i;//得到纵向最长的直线对应的序号 maxLength = length; } } } cvShowImage("霍夫线变换得到的线", dst); line_p = (CvPoint*)cvGetSeqElem(lines_p, maxTemp); if (line_p != NULL) { if (line_p[0].x != line_p[1].x) { slope = abs((double)maxLength / (double)(line_p[0].x - line_p[1].x)); tubeAngle = std::atan(slope) * 180 / 3.14159; } else tubeAngle = 90; } cout << tubeAngle << endl; waitKey(); return 0; }
结果如下:
39度。
原图g1:
处理后的图像g3:
线变换得到的线段dst: