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)\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 &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;
}
*/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM