#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;  
          
    }  

 

posted on 2016-11-30 17:43  Jessica&jie  阅读(6148)  评论(0编辑  收藏  举报