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