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 &center_x, double &center_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)
",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 &center_x, double &center_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;
}
*/
原文地址:https://www.cnblogs.com/tangyuanjie/p/12924193.html