2017-5-28圆弧检测(opencv-qt)
F:\学科、技能、编程\【编程-文件\proj\圆弧检测(opencv-qt)
可以自动或者手动测量圆弧液柱的角度:
使用说明 :
找圆心(最小二乘拟合)相关代码
#include <iostream> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; bool circleLeastFit(CvSeq* points, double ¢er_x, double ¢er_y, double &radius);//最小二乘法拟合函数 int main() { const char* winname ="winname"; //const char* winname1 ="winname1"; //const char* winname2 ="winname2"; //const char* winname3 ="winname3"; char * picname = "P11.jpg"; //加载原图 IplImage * pImage = cvLoadImage(picname); //分量图像 IplImage *pR = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1); IplImage *pG = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1); IplImage *pB = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1); IplImage *temp = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1); IplImage *binary = cvCreateImage(cvGetSize(pImage),IPL_DEPTH_8U,1); //trackbar的变量值 //对应各个通道 int b_low =20; int b_high = 100; int g_low = 20; int g_high = 100; int r_low = 0; int r_high = 100; //轮廓相关 CvMemStorage *storage = cvCreateMemStorage(0); CvSeq * seq = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage); //窗口 cvNamedWindow(winname); cvShowImage(winname, pImage); //显示原图 cvNamedWindow("r",2); cvNamedWindow("g",2); cvNamedWindow("b",2); //各个通道 cvNamedWindow("binary",2);//二值化图 //在相应的窗口建立滑动条 cvCreateTrackbar( "b1","b", &b_low, 254, NULL); //H通道分量范围0-180 cvSetTrackbarPos("b1","b",0 ); //设置默认位置 cvCreateTrackbar( "b2","b", &b_high, 254, NULL);//H通道分量范围0-180 cvSetTrackbarPos("b2","b",110 ); cvCreateTrackbar( "g1","g", &g_low, 254, NULL); cvSetTrackbarPos("g1","g",0 ); cvCreateTrackbar( "g2","g", &g_high, 254, NULL); cvSetTrackbarPos("g2","g",158 ); cvCreateTrackbar( "r1","r", &r_low, 254, NULL); cvSetTrackbarPos("r1","r",68 ); cvCreateTrackbar( "r2","r", &r_high, 254, NULL); cvSetTrackbarPos("r2","r",137); while(1) { //各个通道分离 cvSplit(pImage,pB,pG,pR,NULL); //阈值化 cvThreshold(pB, temp,b_low , 255, CV_THRESH_BINARY); cvThreshold(pB, pB,b_high , 255, CV_THRESH_BINARY_INV); cvAnd(temp,pB,pB,NULL);//与操作,合成一张图 cvThreshold(pG, temp,g_low , 255, CV_THRESH_BINARY); cvThreshold(pG, pG,g_high , 255, CV_THRESH_BINARY_INV); cvAnd(temp,pG,pG,NULL);//与操作,合成一张图 cvThreshold(pR, temp,r_low , 255, CV_THRESH_BINARY); cvThreshold(pR, pR,r_high , 255, CV_THRESH_BINARY_INV); cvAnd(temp,pR,pR,NULL);//与操作,合成一张图 //显示各个通道的图像 cvShowImage("b",pB); cvShowImage("g",pG); cvShowImage("r",pR); //合成到一张图里 cvAnd(pB, pG, binary, NULL); cvAnd(pR, binary, binary, NULL); //膨胀腐蚀操作去除黑点 //cvDilate(binary,binary); //cvErode(binary,binary); //显示合成的二值化图 cvShowImage("binary",binary); //cvSaveImage("erzhitu.jpg",binary); // 处理轮廓 int cnt = cvFindContours(binary,storage,&seq,sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);//返回轮廓的数目 CvSeq* _contour =seq; cout<<"number of contours "<<cnt<<endl; ////////////////////_ //找到长度最大轮廓; double maxarea=0; int ind_max = -1; int m=0; for( ; seq != 0; seq = seq->h_next ) { m++; double tmparea = abs(cvArcLength(seq,CV_WHOLE_SEQ,-1)); //double contArea = fabs(cvContourArea(pcontour,CV_WHOLE_SEQ)); if(tmparea > maxarea) { maxarea = tmparea; ind_max=m; } // cout<<"seqfor: "<<seq->total<<endl; } m=0; seq = _contour; for( ; seq != 0; seq = seq->h_next ) { m++; if(m == ind_max) { break; } } CvSeq* cur_cont = seq; cout<<"seq: "<<seq->total<<endl; cout<<"cur_cont: "<<cur_cont->total<<endl; //for (int i=0;i<cur_cont->total;++i) //{ // CvPoint* p = CV_GET_SEQ_ELEM(CvPoint,cur_cont,i);//输出轮廓上点的坐标 // printf("(%d,%d)\n",p->x,p->y); //} //cvWaitKey(0); //建立彩色输出图像 IplImage *pOutlineImage = cvCreateImage(cvGetSize(pImage), IPL_DEPTH_8U, 3); cvCopy(pImage,pOutlineImage); //int nLevels = 5; //获取最大轮廓的凸包点集 CvSeq* hull=NULL; hull = cvConvexHull2(cur_cont,0,CV_CLOCKWISE,0); cout<<"hull total points number:"<<hull->total<<endl; CvPoint pt0 = **(CvPoint**)cvGetSeqElem(hull,hull->total - 1); for(int i = 0;i<hull->total;++i){ CvPoint pt1 = **(CvPoint**)cvGetSeqElem(hull,i); cvLine(pOutlineImage,pt0,pt1,CV_RGB(0,0,255)); pt0 = pt1; } //最小二乘法拟合圆 double center_x=0; double center_y=0; double radius=0; cout<<"nihe :"<<circleLeastFit(hull, center_x, center_y, radius); cout<<"canshu: "<<center_x<<endl<<center_y<<endl<<radius<<endl; //绘制圆 cvCircle(pOutlineImage,Point2f(center_x,center_y),radius,CV_RGB(0,100,100)); ////////////////////////////////////////////////////////////////////////// //绘制轮廓 //cvDrawContours(pOutlineImage, cur_cont, CV_RGB(255,0,0), CV_RGB(0,255,0),0); //cvDrawContours(dst,contour,CV_RGB(255,0,0),CV_RGB(0,255,0),0); cvShowImage(winname, pOutlineImage); //显示原图jiangshang luokuo if (cvWaitKey(1000) == 27) { cvSaveImage("tutu.jpg",pOutlineImage); break; } cvClearMemStorage( storage ); //清除轮廓所占用的内存 cvReleaseImage(&pOutlineImage);//清除彩色输出图像 } cvDestroyAllWindows(); cvReleaseImage(&pImage); cvReleaseImage(&pR); cvReleaseImage(&pG); cvReleaseImage(&pB); cvReleaseImage(&temp); cvReleaseImage(&binary); return 0; } //最小二乘法拟合,输出圆心的xy坐标值和半径大小; bool circleLeastFit(CvSeq* points, double ¢er_x, double ¢er_y, double &radius) { center_x = 0.0f; center_y = 0.0f; radius = 0.0f; if (points->total < 3) { return false; } double sum_x = 0.0f, sum_y = 0.0f; double sum_x2 = 0.0f, sum_y2 = 0.0f; double sum_x3 = 0.0f, sum_y3 = 0.0f; double sum_xy = 0.0f, sum_x1y2 = 0.0f, sum_x2y1 = 0.0f; int N = points->total ; for (int i = 0; i < N; i++) { CvPoint pt1 = **(CvPoint**)cvGetSeqElem(points,i); double x =pt1.x; double y = pt1.y ; double x2 = x * x; double y2 = y * y; sum_x += x; sum_y += y; sum_x2 += x2; sum_y2 += y2; sum_x3 += x2 * x; sum_y3 += y2 * y; sum_xy += x * y; sum_x1y2 += x * y2; sum_x2y1 += x2 * y; } double C, D, E, G, H; double a, b, c; C = N * sum_x2 - sum_x * sum_x; D = N * sum_xy - sum_x * sum_y; E = N * sum_x3 + N * sum_x1y2 - (sum_x2 + sum_y2) * sum_x; G = N * sum_y2 - sum_y * sum_y; H = N * sum_x2y1 + N * sum_y3 - (sum_x2 + sum_y2) * sum_y; a = (H * D - E * G) / (C * G - D * D); b = (H * C - E * D) / (D * D - G * C); c = -(a * sum_x + b * sum_y + sum_x2 + sum_y2) / N; center_x = a / (-2); center_y = b / (-2); radius = sqrt(a * a + b * b - 4 * c) / 2; return true; }
标定相关代码
#include "opencv2/core/core.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/calib3d/calib3d.hpp" #include "opencv2/highgui/highgui.hpp" #include <iostream> #include <fstream> using namespace cv; using namespace std; #define MAX_GRAY_VALUE 255 #define MIN_GRAY_VALUE 0 using namespace cv; using namespace std; #include <opencv2/imgproc/imgproc.hpp> #include <iostream> #include <stdio.h> using namespace std; using namespace cv; bool check_line_state=false; IplImage* workImg; IplImage* imgshow; CvRect ROI_rect; IplImage* src=0; void on_mouse( int event, int x, int y, int flags, void* ustc) { CvFont font; cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 1, CV_AA); if( event == CV_EVENT_LBUTTONDOWN ) { CvPoint pt = cvPoint(x,y); char temp[16]; sprintf(temp,"(%d,%d)",pt.x,pt.y); cout<<"("<<pt.x<<","<<pt.y<<")"<<endl; x1=pt.x; y1=pt.y; cvPutText(src,temp, pt, &font, cvScalar(255, 255, 255, 0)); cvCircle( src, pt, 2,cvScalar(255,0,0,0) ,CV_FILLED, CV_AA, 0 ); cvShowImage( "src", src ); } } int main() { //获取端点的坐标 src=cvLoadImage("dst7.png",1); cvNamedWindow("src",1); cvSetMouseCallback( "src", on_mouse, 0 ); cvShowImage("src",src); cvWaitKey(0); cvDestroyAllWindows(); cvReleaseImage(&src); return 0; } /* //寻找圆心坐标 int main(int args,char** argv) { static double radius; static int i; Mat srcImage = imread("dst7.png"); if (!srcImage.data) return -1; imshow("srcImage", srcImage); Mat srcGray; cvtColor(srcImage, srcGray, COLOR_BGR2GRAY); //高斯平滑滤波 GaussianBlur(srcGray, srcGray, Size(9, 9), 2,2); static vector<Vec3f> circles; //Hough圆检测 HoughCircles(srcGray, circles, CV_HOUGH_GRADIENT,1,srcGray.rows/8,200,16,0,0); //将得到的结果绘图 for (size_t i = 0; i < circles.size(); i++) { Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); cout<<center<<endl; radius = cvRound(circles[i][2]); cout<<radius<<endl; //检测圆中心 circle(srcImage, center, 3, Scalar(0, 255, 0), -1, 8, 0); //检测圆轮廓 circle(srcImage, center, radius, Scalar(120, 120, 120), 3, 8, 0); } imshow("HoughResult", srcImage); imwrite("HoughResult.jpg",srcImage); IplImage* image=cvLoadImage("dst5.png"); int p=0; int q=0; for (int k=0;k<=360;k++) { double m = 3.1415926535*2*k/360; CvScalar s; s=cvGet2D(image,cvRound(circles[i][0])+radius*cos(m),cvRound(circles[i][1])+radius*sin(m)); if(s.val[0]!=255) { p++; q++; } else q++; cout<<m<<p<<q<<endl; } waitKey(0); return 0; } //二值化部分 //otsu函数计算最佳阈值 int otsu(Mat dst){ int i, j; int tmp; double u0, u1, w0, w1, u, uk; double cov; double maxcov = 0.0; int maxthread = 0; int hst[MAX_GRAY_VALUE] = { 0 }; double pro_hst[MAX_GRAY_VALUE] = { 0.0 }; int height = dst.cols; int width = dst.rows; //统计每个灰度的数量 for (i = 0; i<width; i++){ for (j = 0; j<height; j++){ tmp = dst.at<uchar>(i, j); hst[tmp]++; } } //计算每个灰度级占图像中的概率 for (i = MIN_GRAY_VALUE; i<MAX_GRAY_VALUE; i++) pro_hst[i] = (double)hst[i] / (double)(width*height); //计算全局平均灰度值 u = 0.0; for (i = MIN_GRAY_VALUE; i<MAX_GRAY_VALUE; i++) u += i*pro_hst[i]; //统计前景和背景的平均灰度值,并计算类间方差 for (i = MIN_GRAY_VALUE; i<MAX_GRAY_VALUE; i++){ w0 = 0.0; w1 = 0.0; u0 = 0.0; u1 = 0.0; uk = 0.0; for (j = MIN_GRAY_VALUE; j < i; j++){ uk += j*pro_hst[j]; w0 += pro_hst[j];//前景占图像画幅比例 } u0 = uk / w0;//前景平均灰度 w1 = 1 - w0;//背景占图像画幅比例 u1 = (u - uk) / (1 - w0);//背景平均灰度 //计算类间方差 cov = w0*w1*(u1 - u0)*(u1 - u0); if (cov > maxcov) { maxcov = cov; maxthread = i; } } cout << maxthread << endl; return maxthread; } int main(){ int width, height; int i, j; Mat obj = imread("22.jpg"); Mat dst1; cvtColor(obj, dst1, CV_RGB2GRAY);//灰度化 height = dst1.cols;//计算图像高度 width = dst1.rows;//计算图像宽度 int thd = otsu(dst1); imshow("原图", dst1); for (i = 0; i < width; i++) for (j = 0; j< height; j++) if (dst1.at<uchar>(i, j) > thd) dst1.at<uchar>(i, j) = MAX_GRAY_VALUE-1; else dst1.at<uchar>(i, j) = MIN_GRAY_VALUE; imwrite("dst1.png",dst1); imshow("二值化", dst1); //膨胀(闭运算消除内部米粒) Mat dst2=imread("dst1.png"); Mat dst3; Mat element = getStructuringElement(MORPH_RECT,Size(3,3)); //imshow("闭运算消除内部空隙 原图", dst2); dilate( dst2,dst3,element); //膨胀 imshow("闭运算消除内部空隙 效果图", dst3); imwrite("dst3.png",dst3); //腐蚀(开运算去除毛刺) Mat dst4=imread("dst3.png"); Mat dst5; //imshow("开运算去除毛刺 原图",dst4); erode(dst4,dst5,element); imshow("开运算去除毛刺 效果图",dst5); imwrite("dst5.png",dst5); //边缘检测 Mat dst6=imread("dst5.png"); Mat dst7; //imshow("边缘检测 原图",dst6); Canny(dst6,dst7,150.100,3); imshow("边缘检测 效果图",dst7); imwrite("dst7.png",dst7); waitKey(0); return 0; } int main() { cv::Mat image, Extractcorner; cv::vector<cv::Point2f> corners; //用来储存所有角点坐标 cv::Size board_size = cv::Size(7, 7); //标定板每行,每列角点数 image = cv::imread("2.jpg"); Extractcorner = image.clone(); cv::Mat imageGray; cv::cvtColor(image, imageGray, CV_RGB2GRAY); bool patternfound = cv::findChessboardCorners(image, board_size, corners, cv::CALIB_CB_FAST_CHECK + cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE); if (!patternfound) { std::cout << "can not find chessboard corners!" << std::endl; exit(1); } else { //亚像素精确化 cv::cornerSubPix(imageGray, corners, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1)); } //角点检测图像显示 for (int i = 0; i < corners.size(); i++) { cv::circle(Extractcorner, corners[i], 5, cv::Scalar(255, 0, 255), 2); } cv::imshow("Extractcorner", Extractcorner); cv::imwrite("Extractcorner.jpg", Extractcorner); //输出角点坐标 cout<<corners<<endl; //参考图像 cv::Mat image2, Extractcorner2; cv::vector<cv::Point2f> corners2; //用来储存所有角点坐标 cv::Size board_size2 = cv::Size(7, 7); //标定板每行,每列角点数 image2 = cv::imread("1.jpg"); Extractcorner2 = image2.clone(); cv::Mat imageGray2; cv::cvtColor(image2, imageGray2, CV_RGB2GRAY); bool patternfound2 = cv::findChessboardCorners(image2, board_size, corners2, cv::CALIB_CB_FAST_CHECK + cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE); if (!patternfound2) { std::cout << "can not find chessboard corners!" << std::endl; exit(1); } else { //亚像素精确化 cv::cornerSubPix(imageGray2, corners2, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1)); } //角点检测图像显示 for (int i = 0; i < corners2.size(); i++) { cv::circle(Extractcorner2, corners2[i], 5, cv::Scalar(255, 0, 255), 2); } cv::imshow("Extractcorner2", Extractcorner2); cv::imwrite("Extractcorner2.jpg", Extractcorner2); //输出角点坐标 cout<<corners2<<endl; //仿射变换1 Mat src = imread("2.jpg"); Mat dst_warp; Point2f srcPoints[3];//原图中的三点 Point2f dstPoints[3];//目标图中的三点 //三个点对的值 srcPoints[0] = Point2f(142.52786,115.98566); srcPoints[1] = Point2f(110.28358,409.29211); srcPoints[2] = Point2f(438.46851,126.58415); dstPoints[0] = Point2f(44.506947, 46.233685); dstPoints[1] = Point2f(44.496399, 325.76706); dstPoints[2] = Point2f(314.50659, 46.230354); Mat M1 = getAffineTransform(srcPoints,dstPoints);//由三个点对计算变换矩阵 warpAffine(src,dst_warp,M1,src.size());//仿射变换 imshow("src",src); imshow("dst_warp",dst_warp); imwrite("dst_warp.jpg",dst_warp); //一次变换后图像 cv::Mat image3, Extractcorner3; cv::vector<cv::Point2f> corners3; //用来储存所有角点坐标 cv::Size board_size3 = cv::Size(7, 7); //标定板每行,每列角点数 image3 = cv::imread("dst_warp.jpg"); Extractcorner3 = image3.clone(); cv::Mat imageGray3; cv::cvtColor(image3, imageGray3, CV_RGB2GRAY); bool patternfound3 = cv::findChessboardCorners(image3, board_size, corners3, cv::CALIB_CB_FAST_CHECK + cv::CALIB_CB_ADAPTIVE_THRESH + cv::CALIB_CB_NORMALIZE_IMAGE); if (!patternfound3) { std::cout << "can not find chessboard corners!" << std::endl; exit(1); } else { //亚像素精确化 cv::cornerSubPix(imageGray3, corners3, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1)); } //角点检测图像显示 for (int i = 0; i < corners3.size(); i++) { cv::circle(Extractcorner3, corners3[i], 5, cv::Scalar(255, 0, 255), 2); } cv::imshow("Extractcorner3", Extractcorner3); cv::imwrite("Extractcorner3.jpg", Extractcorner3); //输出角点坐标 cout<<corners3<<endl; ofstream outfile; outfile.open("date.txt"); outfile<<corners<<endl<<endl<<endl<<corners2<<corners3<<endl; outfile.close(); //仿射变换2 Mat src2 = imread("dst_warp.jpg"); Mat dst_warp2; Point2f src2Points[3];//原图中的三点 Point2f dst2Points[3];//目标图中的三点 //三个点对的值 src2Points[0] = Point2f(395.12207, 306.01523); src2Points[1] = Point2f(44.515686, 325.73227); src2Points[2] = Point2f(314.53482, 46.279831); dst2Points[0] = Point2f(314.49469, 325.76535); dst2Points[1] = Point2f(44.496399, 325.76706); dst2Points[2] = Point2f(314.50659, 46.230354); Mat M2 = getAffineTransform(src2Points,dst2Points);//由三个点对计算变换矩阵 warpAffine(src2,dst_warp2,M2,src2.size());//仿射变换 imshow("src2",src); imshow("dst_warp2",dst_warp2); imwrite("dst_warp2.jpg",dst_warp2); cv::waitKey(0); return 0; } */