• Open Source Computer Vision Library

摄像头标定

Wikipedia,自由的百科全书

OPENCV没有提供完整的示例,自己整理了一下,贴出来记录。

步骤如下:

首先自制一张标定图片,用A4纸打印出来,设定距离,再设定标定棋盘的格子数目,如8×6,以下是我做的图片8×8

o_camera_calibration_8_8.JPG

然后利用cvFindChessboardCorners找到棋盘在摄像头中的2D位置,这里cvFindChessboardCorners不太稳定,有时不能工作,也许需要图像增强处理。

计算实际的距离,应该是3D的距离。我设定为21.6毫米,既在A4纸上为两厘米。

再用cvCalibrateCamera2计算内参,

最后用cvUndistort2纠正图像的变形。

结果如下: o_camera_calibration2.JPG

代码下载

代码:

  1. #include "stdafx.h"
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. // OpenCV
  6. #include <cxcore.h>
  7. #include <cv.h>
  8. #include <highgui.h>
  9. #include <cvaux.h>
  10.  
  11.  
  12. void InitCorners3D(CvMat *Corners3D, CvSize ChessBoardSize, int Nimages, float SquareSize);
  13. void makeChessBoard();
  14. int myFindChessboardCorners( const void* image, CvSize pattern_size,
  15. CvPoint2D32f* corners, int* corner_count=NULL,
  16. int flags=CV_CALIB_CB_ADAPTIVE_THRESH );
  17.  
  18.  
  19. inline int drawCorssMark(IplImage *dst,CvPoint pt)
  20. /*************************************************
  21. Function: main_loop
  22. Description: 绘制一个十字标记
  23. Calls:
  24. Called By:
  25. Input: RGB image, pt
  26. Output:
  27. Return:
  28. Others: 需要检查坐标是否越界 to do list
  29. *************************************************/
  30. {
  31.  
  32. const int cross_len = 4;
  33. CvPoint pt1,pt2,pt3,pt4;
  34. pt1.x = pt.x;
  35. pt1.y = pt.y - cross_len;
  36. pt2.x = pt.x;
  37. pt2.y = pt.y + cross_len;
  38. pt3.x = pt.x - cross_len;
  39. pt3.y = pt.y;
  40. pt4.x = pt.x + cross_len;
  41. pt4.y = pt.y;
  42.  
  43. cvLine(dst,pt1,pt2,CV_RGB(0,255,0),2,CV_AA, 0 );
  44. cvLine(dst,pt3,pt4,CV_RGB(0,255,0),2,CV_AA, 0 );
  45.  
  46. return 0;
  47. }
  48.  
  49. /* declarations for OpenCV */
  50. IplImage *current_frame_rgb,grid;
  51. IplImage *current_frame_gray;
  52. IplImage *chessBoard_Img;
  53.  
  54. int Thresholdness = 120;
  55.  
  56. int image_width = 320;
  57. int image_height = 240;
  58.  
  59. bool verbose = false;
  60.  
  61. const int ChessBoardSize_w = 7;
  62. const int ChessBoardSize_h = 7;
  63. // Calibration stuff
  64. bool calibration_done = false;
  65. const CvSize ChessBoardSize = cvSize(ChessBoardSize_w,ChessBoardSize_h);
  66. //float SquareWidth = 21.6f; //实际距离 毫米单位 在A4纸上为两厘米
  67. float SquareWidth = 17; //投影实际距离 毫米单位 200
  68.  
  69. const int NPoints = ChessBoardSize_w*ChessBoardSize_h;
  70. const int NImages = 20; //Number of images to collect
  71.  
  72. CvPoint2D32f corners[NPoints*NImages];
  73. int corner_count[NImages] = {0};
  74. int captured_frames = 0;
  75.  
  76. CvMat *intrinsics;
  77. CvMat *distortion_coeff;
  78. CvMat *rotation_vectors;
  79. CvMat *translation_vectors;
  80. CvMat *object_points;
  81. CvMat *point_counts;
  82. CvMat *image_points;
  83. int find_corners_result =0 ;
  84.  
  85.  
  86. void on_mouse( int event, int x, int y, int flags, void* param )
  87. {
  88.  
  89. if( event == CV_EVENT_LBUTTONDOWN )
  90. {
  91. //calibration_done = true;
  92. }
  93. }
  94.  
  95.  
  96. int main(int argc, char *argv[])
  97. {
  98.  
  99.  
  100. CvFont font;
  101. cvInitFont( &font, CV_FONT_VECTOR0,5, 5, 0, 7, 8);
  102.  
  103. intrinsics = cvCreateMat(3,3,CV_32FC1);
  104. distortion_coeff = cvCreateMat(1,4,CV_32FC1);
  105. rotation_vectors = cvCreateMat(NImages,3,CV_32FC1);
  106. translation_vectors = cvCreateMat(NImages,3,CV_32FC1);
  107.  
  108. point_counts = cvCreateMat(NImages,1,CV_32SC1);
  109.  
  110. object_points = cvCreateMat(NImages*NPoints,3,CV_32FC1);
  111. image_points = cvCreateMat(NImages*NPoints,2,CV_32FC1);
  112.  
  113.  
  114. // Function to fill in the real-world points of the checkerboard
  115. InitCorners3D(object_points, ChessBoardSize, NImages, SquareWidth);
  116.  
  117.  
  118. CvCapture* capture = 0;
  119.  
  120.  
  121. if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0])))
  122. capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 );
  123. else if( argc == 2 )
  124. capture = cvCaptureFromAVI( argv[1] );
  125.  
  126. if( !capture )
  127. {
  128. fprintf(stderr,"Could not initialize capturing...\n");
  129. return -1;
  130. }
  131.  
  132.  
  133. // Initialize all of the IplImage structures
  134. current_frame_rgb = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 3);
  135.  
  136. IplImage *current_frame_rgb2 = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 3);
  137. current_frame_gray = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 1);
  138.  
  139. chessBoard_Img = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 3);
  140. current_frame_rgb2->origin = chessBoard_Img->origin = current_frame_gray->origin = current_frame_rgb->origin = 1;
  141.  
  142. makeChessBoard();
  143.  
  144. cvNamedWindow( "result", 0);
  145. cvNamedWindow( "Window 0", 0);
  146. cvNamedWindow( "grid", 0);
  147. cvMoveWindow( "grid", 100,100);
  148. cvSetMouseCallback( "Window 0", on_mouse, 0 );
  149. cvCreateTrackbar("Thresholdness","Window 0",&Thresholdness, 255,0);
  150.  
  151. while (!calibration_done)
  152. {
  153.  
  154. while (captured_frames < NImages)
  155. {
  156. current_frame_rgb = cvQueryFrame( capture );
  157. //current_frame_rgb = cvLoadImage( "c:\\BoardStereoL3.jpg" );
  158. //cvCopy(chessBoard_Img,current_frame_rgb);
  159.  
  160. if( !current_frame_rgb )
  161. break;
  162.  
  163. cvCopy(current_frame_rgb,current_frame_rgb2);
  164. cvCvtColor(current_frame_rgb, current_frame_gray, CV_BGR2GRAY);
  165. //cvThreshold(current_frame_gray,current_frame_gray,Thresholdness,255,CV_THRESH_BINARY);
  166. //cvThreshold(current_frame_gray,current_frame_gray,150,255,CV_THRESH_BINARY_INV);
  167.  
  168. /*
  169. int pos = 1;
  170. IplConvKernel* element = 0;
  171. const int element_shape = CV_SHAPE_ELLIPSE;
  172. element = cvCreateStructuringElementEx( pos*2+1, pos*2+1, pos, pos, element_shape, 0 );
  173. cvDilate(current_frame_gray,current_frame_gray,element,1);
  174. cvErode(current_frame_gray,current_frame_gray,element,1);
  175. cvReleaseStructuringElement(&element);
  176. */
  177.  
  178. find_corners_result = cvFindChessboardCorners(current_frame_gray,
  179. ChessBoardSize,
  180. &corners[captured_frames*NPoints],
  181. &corner_count[captured_frames],
  182. 0);
  183.  
  184.  
  185.  
  186. cvDrawChessboardCorners(current_frame_rgb2, ChessBoardSize, &corners[captured_frames*NPoints], NPoints, find_corners_result);
  187.  
  188.  
  189. cvShowImage("Window 0",current_frame_rgb2);
  190. cvShowImage("grid",chessBoard_Img);
  191.  
  192. if(find_corners_result==1)
  193. {
  194. cvWaitKey(2000);
  195. cvSaveImage("c:\\hardyinCV.jpg",current_frame_rgb2);
  196. captured_frames++;
  197. }
  198. //cvShowImage("result",current_frame_gray);
  199.  
  200. intrinsics->data.fl[0] = 256.8093262; //fx
  201. intrinsics->data.fl[2] = 160.2826538; //cx
  202. intrinsics->data.fl[4] = 254.7511139; //fy
  203. intrinsics->data.fl[5] = 127.6264572; //cy
  204.  
  205. intrinsics->data.fl[1] = 0;
  206. intrinsics->data.fl[3] = 0;
  207. intrinsics->data.fl[6] = 0;
  208. intrinsics->data.fl[7] = 0;
  209. intrinsics->data.fl[8] = 1;
  210.  
  211. distortion_coeff->data.fl[0] = -0.193740; //k1
  212. distortion_coeff->data.fl[1] = -0.378588; //k2
  213. distortion_coeff->data.fl[2] = 0.028980; //p1
  214. distortion_coeff->data.fl[3] = 0.008136; //p2
  215.  
  216. cvWaitKey(40);
  217. find_corners_result = 0;
  218. }
  219. //if (find_corners_result !=0)
  220. {
  221.  
  222. printf("\n");
  223.  
  224. cvSetData( image_points, corners, sizeof(CvPoint2D32f));
  225. cvSetData( point_counts, &corner_count, sizeof(int));
  226.  
  227.  
  228. cvCalibrateCamera2( object_points,
  229. image_points,
  230. point_counts,
  231. cvSize(image_width,image_height),
  232. intrinsics,
  233. distortion_coeff,
  234. rotation_vectors,
  235. translation_vectors,
  236. 0);
  237.  
  238.  
  239. // [fx 0 cx; 0 fy cy; 0 0 1].
  240. cvUndistort2(current_frame_rgb,current_frame_rgb,intrinsics,distortion_coeff);
  241. cvShowImage("result",current_frame_rgb);
  242.  
  243.  
  244. float intr[3][3] = {0.0};
  245. float dist[4] = {0.0};
  246. float tranv[3] = {0.0};
  247. float rotv[3] = {0.0};
  248.  
  249. for ( int i = 0; i < 3; i++)
  250. {
  251. for ( int j = 0; j < 3; j++)
  252. {
  253. intr[i][j] = ((float*)(intrinsics->data.ptr + intrinsics->step*i))[j];
  254. }
  255. dist[i] = ((float*)(distortion_coeff->data.ptr))[i];
  256. tranv[i] = ((float*)(translation_vectors->data.ptr))[i];
  257. rotv[i] = ((float*)(rotation_vectors->data.ptr))[i];
  258. }
  259. dist[3] = ((float*)(distortion_coeff->data.ptr))[3];
  260.  
  261. printf("-----------------------------------------\n");
  262. printf("INTRINSIC MATRIX: \n");
  263. printf("[ %6.4f %6.4f %6.4f ] \n", intr[0][0], intr[0][1], intr[0][2]);
  264. printf("[ %6.4f %6.4f %6.4f ] \n", intr[1][0], intr[1][1], intr[1][2]);
  265. printf("[ %6.4f %6.4f %6.4f ] \n", intr[2][0], intr[2][1], intr[2][2]);
  266. printf("-----------------------------------------\n");
  267. printf("DISTORTION VECTOR: \n");
  268. printf("[ %6.4f %6.4f %6.4f %6.4f ] \n", dist[0], dist[1], dist[2], dist[3]);
  269. printf("-----------------------------------------\n");
  270. printf("ROTATION VECTOR: \n");
  271. printf("[ %6.4f %6.4f %6.4f ] \n", rotv[0], rotv[1], rotv[2]);
  272. printf("TRANSLATION VECTOR: \n");
  273. printf("[ %6.4f %6.4f %6.4f ] \n", tranv[0], tranv[1], tranv[2]);
  274. printf("-----------------------------------------\n");
  275.  
  276. cvWaitKey(0);
  277.  
  278. calibration_done = true;
  279. }
  280.  
  281. }
  282.  
  283. exit(0);
  284. cvDestroyAllWindows();
  285. }
  286.  
  287. void InitCorners3D(CvMat *Corners3D, CvSize ChessBoardSize, int NImages, float SquareSize)
  288. {
  289. int CurrentImage = 0;
  290. int CurrentRow = 0;
  291. int CurrentColumn = 0;
  292. int NPoints = ChessBoardSize.height*ChessBoardSize.width;
  293. float * temppoints = new float[NImages*NPoints*3];
  294.  
  295. // for now, assuming we're row-scanning
  296. for (CurrentImage = 0 ; CurrentImage < NImages ; CurrentImage++)
  297. {
  298. for (CurrentRow = 0; CurrentRow < ChessBoardSize.height; CurrentRow++)
  299. {
  300. for (CurrentColumn = 0; CurrentColumn < ChessBoardSize.width; CurrentColumn++)
  301. {
  302. temppoints[(CurrentImage*NPoints*3)+(CurrentRow*ChessBoardSize.width + CurrentColumn)*3]=(float)CurrentRow*SquareSize;
  303. temppoints[(CurrentImage*NPoints*3)+(CurrentRow*ChessBoardSize.width + CurrentColumn)*3+1]=(float)CurrentColumn*SquareSize;
  304. temppoints[(CurrentImage*NPoints*3)+(CurrentRow*ChessBoardSize.width + CurrentColumn)*3+2]=0.f;
  305. }
  306. }
  307. }
  308. (*Corners3D) = cvMat(NImages*NPoints,3,CV_32FC1, temppoints);
  309. }
  310.  
  311. int myFindChessboardCorners( const void* image, CvSize pattern_size,
  312. CvPoint2D32f* corners, int* corner_count,
  313. int flags )
  314.  
  315. {
  316.  
  317.  
  318. IplImage* eig = cvCreateImage( cvGetSize(image), 32, 1 );
  319. IplImage* temp = cvCreateImage( cvGetSize(image), 32, 1 );
  320. double quality = 0.01;
  321. double min_distance = 5;
  322. int win_size =10;
  323.  
  324. int count = pattern_size.width * pattern_size.height;
  325. cvGoodFeaturesToTrack( image, eig, temp, corners, &count,
  326. quality, min_distance, 0, 3, 0, 0.04 );
  327. cvFindCornerSubPix( image, corners, count,
  328. cvSize(win_size,win_size), cvSize(-1,-1),
  329. cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03));
  330.  
  331. cvReleaseImage( &eig );
  332. cvReleaseImage( &temp );
  333.  
  334. return 1;
  335. }
  336.  
  337. void makeChessBoard()
  338. {
  339.  
  340. CvScalar e;
  341. e.val[0] =255;
  342. e.val[1] =255;
  343. e.val[2] =255;
  344. cvSet(chessBoard_Img,e,0);
  345. for(int i = 0;i<ChessBoardSize.width+1;i++)
  346. for(int j = 0;j<ChessBoardSize.height+1;j++)
  347. {
  348. int w =(image_width)/2/(ChessBoardSize.width);
  349. int h = w; //(image_height)/2/(ChessBoardSize.height);
  350.  
  351. int ii = i+1;
  352. int iii = ii+1;
  353. int jj =j+1;
  354. int jjj =jj+1;
  355. int s_x = image_width/6;
  356.  
  357. if((i+j)%2==1)
  358. cvRectangle( chessBoard_Img, cvPoint(w*i+s_x,h*j+s_x),cvPoint(w*ii-1+s_x,h*jj-1+s_x), CV_RGB(0,0,0),CV_FILLED, 8, 0 );
  359. }
  360. }
  361.  
Views
Personal tools