opencv單目攝像機標定(一)


  

 #include <string>  
    #include <iostream>  
    #include <cv.h>  
    #include <highgui.h>  

      
    using namespace std;  
      
    int main()  
    {  
        int cube_length=7;  
      
        CvCapture* capture;  
        capture=cvCreateCameraCapture(0); // opencv調用攝像頭的接口,初始化從攝像頭中獲取視頻,
      
        if(capture==0){  
            printf("無法捕獲攝像頭設備!\n\n");  
            return 0;  
        }else{  
            printf("捕獲攝像頭設備成功!!\n\n");  
        }   
        cvNamedWindow("攝像機幀截取窗口",1); //cvNamedWindow()函數用於在屏幕上創建一個窗口,將被顯示的圖像包含於該窗口中。函數的第一個參數指定了該窗口的窗口標題,如果要使用HighGUI庫所提供的其他函數與該窗口進行交互時,我們將通過該參數值引用這個窗口。     
        printf("按“C”鍵截取當前幀並保存為標定圖片...\n按“Q”鍵退出截取幀過程...\n\n");  

        IplImage* frame; 
        int number_image=1;  //攝像機拍攝圖像張數初始化
        char filename[20]="";  
        while(true)  
        {  
            frame=cvQueryFrame(capture);// 從攝像頭或者文件中抓取並返回一幀   
            if(!frame)  
                 break;  
            cvShowImage("攝像機幀截取窗口",frame); //圖像顯示      
            if(cvWaitKey(10)=='c')
             {  
                sprintf (filename,"%d.jpg",number_image);  // int sprintf_s( char *buffer, size_t sizeOfBuffer, const char *format [, argument] ... ); //這個函數的主要作用是將若干個argument按照format格式存到buffer中    
                cvSaveImage(filename,frame);  //保存,在工作目錄中 
                cout<<"成功獲取當前幀,並以文件名"<<filename<<"保存...\n\n";  
                printf("按“C”鍵截取當前幀並保存為標定圖片...\n按“Q”鍵退出截取幀過程...\n\n");  
                number_image++;  
             }
             else if(cvWaitKey(10)=='q')
            {  
                printf("截取圖像幀過程完成...\n\n");  
                cout<<"共成功截取"<<--number_image<<"幀圖像!!\n\n";  
                break;  
            }  
        }  
      
        cvReleaseImage(&frame);  //釋放圖像  
        cvReleaseCapture(&capture);//若您的是1.0版本,如果報錯請修改為cvReleaseCapture(&capture),或將此句加在cvReleaseImage(&frame)后
        cvDestroyWindow("攝像機幀截取窗口");  
      
        IplImage * show; //RePlay圖像指針
        cvNamedWindow("RePlay",1);  
        int a=1;  //臨時變量,表示在操作第a幀圖像
        int number_image_copy=number_image; //復制圖像幀數 
        CvSize board_size=cvSize(7,7);   // Cvsize:OpenCV的基本數據類型之一,是構造Cvsize類型的函數,width和height,表示矩陣框大小,以像素為精度。與CvPoint結構類似,但數據成員是integer類型的width和height。    
        int board_width=board_size.width; 
        int board_height=board_size.height; 
        int total_per_image=board_width*board_height; //每張圖的角點總數 
        CvPoint2D32f * image_points_buf = new CvPoint2D32f[total_per_image];  //存儲角點坐標的數組
//主要用來轉換成矩陣形式CvMat* cvCreateMat( int rows, int cols, int type );rows矩陣行數。cols矩陣列數。type矩陣元素類型,浮點型的單通道圖像。
// 這里type可以是任何預定義類型,預定義類型的結構如下:CV_<bit_depth> (S|U|F)C<number_of_channels>。      
        CvMat * image_points=cvCreateMat(number_image*total_per_image,2,CV_32FC1); //存儲角點圖像坐標的矩陣 
        CvMat * object_points=cvCreateMat(number_image*total_per_image,3,CV_32FC1); //存儲角點世界坐標的矩陣    
        CvMat * point_counts=cvCreateMat(number_image,1,CV_32SC1); //存儲每幀圖像的識別角點數
        CvMat * intrinsic_matrix=cvCreateMat(3,3,CV_32FC1);  
        CvMat * distortion_coeffs=cvCreateMat(5,1,CV_32FC1);  
      
        int count; //存儲每幀圖像中實際識別的角點數 
        int found; //識別標定板角點的標志位 ,角點能否被檢測到
        int step;  //存儲步長,step=successes*total_per_image; 
        int successes=0; //成功找到標定板上所有角點的圖像幀數初始化
      
        while(a<=number_image_copy)
       {  //讀取每張圖
            sprintf (filename,"%d.jpg",a);  
            show=cvLoadImage(filename,-1);  
         //尋找角點
            found=cvFindChessboardCorners(show,board_size,image_points_buf,&count,  
                                         CV_CALIB_CB_ADAPTIVE_THRESH|CV_CALIB_CB_FILTER_QUADS);  
            if(found==0)
               {         
                cout<<""<<a<<"幀圖片無法找到棋盤格所有角點!\n\n";  
                cvNamedWindow("RePlay",1);  
                cvShowImage("RePlay",show);  
                cvWaitKey(0);  
               }
           else{  
                cout<<""<<a<<"幀圖像成功獲得"<<count<<"個角點...\n";  
                cvNamedWindow("RePlay",1);  
      
                IplImage * gray_image= cvCreateImage(cvGetSize(show),8,1); //創建頭並分配數據IplImage* 
                cvCvtColor(show,gray_image,CV_BGR2GRAY); // cvCvtColor(...),是Opencv里的顏色空間轉換函數,可以實現rgb顏色向HSV,HSI等顏色空間的轉換,也可以轉換為灰度圖像。     
                cout<<"獲取源圖像灰度圖過程完成...\n";  
             //獲取亞像素角點
                cvFindCornerSubPix(gray_image,image_points_buf,count,cvSize(11,11),cvSize(-1,-1),  
                                    cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,0.1));  
                cout<<"灰度圖亞像素化過程完成...\n";  
              //繪制角點 
                cvDrawChessboardCorners(show,board_size,image_points_buf,count,found);
                cout<<"在源圖像上繪制角點過程完成...\n\n";  
                cvShowImage("RePlay",show);  
                cvWaitKey(0);  
               }  
      
            if(total_per_image==count)
            {  
                step=successes*total_per_image;  
                for(int i=step,j=0;j<total_per_image;++i,++j)
               {
 //total_per_image是一幅圖像中的角點總數。  
 // opencv中用來訪問矩陣每個元素的宏,這個宏只對單通道矩陣有效,CV_MAT_ELEM( matrix, elemtype, row, col )參數  matrix:要訪問的矩陣  elemtype:矩陣元素的類型  row:所要訪問元素的行數  col:所要訪問元素的列數   
// cvFindCornerSubPix求完每個角點橫縱坐標值都存在image_point_buf里,現在將其存在image_points中,每行存一個,商為行x,余為列y    
//將角點坐標的數組壓入矩陣image_points
                    CV_MAT_ELEM(*image_points,float,i,0)=image_points_buf[j].x;  
                    CV_MAT_ELEM(*image_points,float,i,1)=image_points_buf[j].y;//找到的點以坐標形式存儲  
                    CV_MAT_ELEM(*object_points,float,i,0)=(float)(j/cube_length); 
                    CV_MAT_ELEM(*object_points,float,i,1)=(float)(j%cube_length); //找到的點的數目以行列形式存儲 
                    CV_MAT_ELEM(*object_points,float,i,2)=0.0f; //0單精度浮點 
                }  
                CV_MAT_ELEM(*point_counts,int,successes,0)=total_per_image;//訪問矩陣角點數  
                successes++; 
            }  
            a++;  
        }  
      
        cvReleaseImage(&show);  
        cvDestroyWindow("RePlay");  
      
        cout<<"*********************************************\n";  
        cout<<number_image<<"幀圖片中,標定成功的圖片為"<<successes<<"幀...\n";  
        cout<<number_image<<"幀圖片中,標定失敗的圖片為"<<number_image-successes<<"幀...\n\n";  
        cout<<"*********************************************\n\n";  
      
        cout<<"按任意鍵開始計算攝像機內參數...\n\n";  
      
        CvCapture* capture1;  
        capture1=cvCreateCameraCapture(0);  
        IplImage * show_colie;  
        show_colie=cvQueryFrame(capture1);  
       //存儲標定成功圖片的角點的矩陣形式                
        CvMat * object_points2=cvCreateMat(successes*total_per_image,3,CV_32FC1);  
        CvMat * image_points2=cvCreateMat(successes*total_per_image,2,CV_32FC1);  
        CvMat * point_counts2=cvCreateMat(successes,1,CV_32SC1);  
      //用來存儲角點提取成功的圖像的角點   
        for(int i=0;i<successes*total_per_image;++i){   
            CV_MAT_ELEM(*image_points2,float,i,0)=CV_MAT_ELEM(*image_points,float,i,0);  
            CV_MAT_ELEM(*image_points2,float,i,1)=CV_MAT_ELEM(*image_points,float,i,1);  
            CV_MAT_ELEM(*object_points2,float,i,0)=CV_MAT_ELEM(*object_points,float,i,0);  
            CV_MAT_ELEM(*object_points2,float,i,1)=CV_MAT_ELEM(*object_points,float,i,1);  
            CV_MAT_ELEM(*object_points2,float,i,2)=CV_MAT_ELEM(*object_points,float,i,2);  
        }  
      
        for(int i=0;i<successes;++i){  
            CV_MAT_ELEM(*point_counts2,int,i,0)=CV_MAT_ELEM(*point_counts,int,i,0);  
        }  
            
        cvReleaseMat(&object_points);  
        cvReleaseMat(&image_points);  
        cvReleaseMat(&point_counts);  

       //初始化相機內參矩陣
        CV_MAT_ELEM(*intrinsic_matrix,float,0,0)=1.0f;//fx  
        CV_MAT_ELEM(*intrinsic_matrix,float,1,1)=1.0f;//fy 

       //標定相機的內參矩陣和畸變系數向量
       cvCalibrateCamera2(object_points2,image_points2,point_counts2,cvGetSize(show_colie),  
                            intrinsic_matrix,distortion_coeffs,NULL,NULL,0);  
          
        cout<<"攝像機內參數矩陣為:\n";  
        cout<<CV_MAT_ELEM(*intrinsic_matrix,float,0,0)<<"    "<<CV_MAT_ELEM(*intrinsic_matrix,float,0,1)  
                                                      <<"    "<<CV_MAT_ELEM(*intrinsic_matrix,float,0,2)  
                                                      <<"\n\n";  
        cout<<CV_MAT_ELEM(*intrinsic_matrix,float,1,0)<<"    "<<CV_MAT_ELEM(*intrinsic_matrix,float,1,1)  
                                                      <<"    "<<CV_MAT_ELEM(*intrinsic_matrix,float,1,2)  
                                                      <<"\n\n";  
        cout<<CV_MAT_ELEM(*intrinsic_matrix,float,2,0)<<"    "<<CV_MAT_ELEM(*intrinsic_matrix,float,2,1)  
                                                      <<"    "<<CV_MAT_ELEM(*intrinsic_matrix,float,2,2)  
                                                      <<"\n\n";  
      
        cout<<"畸變系數矩陣為:\n";  
        cout<<CV_MAT_ELEM(*distortion_coeffs,float,0,0)<<"    "<<CV_MAT_ELEM(*distortion_coeffs,float,1,0)  
                                                       <<"    "<<CV_MAT_ELEM(*distortion_coeffs,float,2,0)  
                                                       <<"    "<<CV_MAT_ELEM(*distortion_coeffs,float,3,0)  
                                                       <<"    "<<CV_MAT_ELEM(*distortion_coeffs,float,4,0)  
                                                       <<"\n\n";  
      
        cvSave("Intrinsics.xml",intrinsic_matrix);//保存在工作目錄下   
        cvSave("Distortion.xml",distortion_coeffs);  
      
        cout<<"攝像機矩陣、畸變系數向量已經分別存儲在名為Intrinsics.xml、Distortion.xml文檔中\n\n";  
      
        CvMat * intrinsic=(CvMat *)cvLoad("Intrinsics.xml");  //加載參數方法  
        CvMat * distortion=(CvMat *)cvLoad("Distortion.xml");  
      
        IplImage * mapx=cvCreateImage(cvGetSize(show_colie),IPL_DEPTH_32F,1);  
        IplImage * mapy=cvCreateImage(cvGetSize(show_colie),IPL_DEPTH_32F,1);  
          
        cvInitUndistortMap(intrinsic,distortion,mapx,mapy);//函數cvInitUndistortMap預先計算非形變對應-正確圖像的每個像素在形變圖像里的坐標。這個對應可以傳遞給cvRemap函數(跟輸入和輸出圖像一起)。   
       
        cvNamedWindow("原始圖像",1);  
        cvNamedWindow("非畸變圖像",1);  
      
        cout<<"按‘E’鍵退出顯示...\n\n";  
      
        while(show_colie){  
            IplImage * clone=cvCloneImage(show_colie);  
            cvShowImage("原始圖像",show_colie);  
            cvRemap(clone,show_colie,mapx,mapy);//校正圖像,輸入為clone,結果為show_colie    
            cvReleaseImage(&clone);  
            cvShowImage("非畸變圖像",show_colie);  
      
            if(cvWaitKey(10)=='e'){  
                break;  
            }  
      
            show_colie=cvQueryFrame(capture1);  
        }  
      
        return 0;  
          
    }  

 


免責聲明!

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



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