Learning opencv 例11-1(单应性摄像头定标)程序详解

本文介绍了一种基于OpenCV的单应性相机标定方法,通过对棋盘格图像进行处理,实现相机内部参数和畸变系数的计算,并展示了如何使用这些参数纠正图像畸变。

学习机器视觉。尝试例11-1,程序比较抽象,又没有找到详细解释,于是决定自己看程序,测试程序,理解单应性相机标定。(申明:这是个人通过测试和理解的心得,不一定完全正确。)

源程序:

#include "stdafx.h"
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
#include <stdlib.h>

int n_boards = 0; //Will be set by input list
const int board_dt = 20;// wait 20 frames per chessboard view
int board_w;
int board_h;

int main(int argc, char* argv[]) {
//int main(4,8,8,10,0){   //如果不用脚本引导main程序执行,则可以像这样自行输入参数。
if(argc != 4){
printf("ERROR:Wrong number of input parametersn");
return -1;
}
board_w = atoi(argv[1]); //棋盘板的宽度(横向棋盘格数)
board_h = atoi(argv[2]);  //棋盘板的高度(纵向棋盘格数)
n_boards = atoi(argv[3]);//图像张数
int board_n  = board_w * board_h;
CvSize board_sz = cvSize( board_w, board_h );  
CvCapture* capture = cvCreateCameraCapture(0);
assert(capture);

  cvNamedWindow( "Calibration" );
  //ALLOCATE STORAGE 
  CvMat* image_points      = cvCreateMat(n_boards*board_n,2,CV_32FC1);  //总的图像点存储
  CvMat* object_points     = cvCreateMat(n_boards*board_n,3,CV_32FC1);//总的实物点存储
  CvMat* point_counts      = cvCreateMat(n_boards,1,CV_32SC1);  
  CvMat* intrinsic_matrix  = cvCreateMat(3,3,CV_32FC1); //内部参数矩阵
  CvMat* distortion_coeffs = cvCreateMat(5,1,CV_32FC1); //畸变矩阵
  
  CvPoint2D32f* corners = new CvPoint2D32f[ board_n ];  //角
  int corner_count;
  int successes = 0;
  int step,frame=0;
  IplImage *image = cvQueryFrame(capture); //读图像
  IplImage *gray_image = cvCreateImage(cvGetSize(image),8,1);
  //subpixel
  //capture corner views loop until we've got n_boards
  //successful captures (all corners on the board are found)
  //
  while(successes<n_boards){  //每张图循环一次
 //skip every board_dt frames to allow user to move chessboard
 if(frame++ % board_dt==0){  //每20帧取一张
 //Find chessboard corners://寻找棋盘内角点,将个数存入corner_count,将角点像素存入corners。
 int found = cvFindChessboardCorners(image,board_sz,corners,&corner_count,CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);
  
 //Get Subpixel accuracy on those corners
 cvCvtColor(image,gray_image,CV_BGR2GRAY); //转换图像类型。
 cvFindCornerSubPix(gray_image,corners,corner_count,cvSize(11,11),cvSize(-1,-1),cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,0.1));//寻找内角点的压像素值。

 //Draw it
 cvDrawChessboardCorners(image,board_sz,corners,corner_count,found);
 cvShowImage("Calibration",image);  //画出角点

 //If we got a good board ,add it to our data
 if(corner_count == board_n){  //角点全部被找出
 step = successes*board_n;
 for(int i=step,j=0;j<board_n;++i,++j){
 CV_MAT_ELEM(*image_points,float,i,0)=corners[j].x;
 CV_MAT_ELEM(*image_points,float,i,1)=corners[j].y;  //将角点坐标存储到图像点当中。
 CV_MAT_ELEM(*object_points,float,i,0)=j/board_w;  
 CV_MAT_ELEM(*object_points,float,i,1)=j%board_w;  //世界坐标,说明设定每个格子的长度为1.
 CV_MAT_ELEM(*object_points,float,i,2)=0.0f;   //Z轴坐标值为0,将棋盘平面设为世界坐标的XOY平面。
 }
 CV_MAT_ELEM(*point_counts,int,successes,0)=board_n;
 successes++;
 }
 }//end skip board_dt between chessboard capture

 //Handle pause/unpause and ESC
 int c =cvWaitKey(15);   //暂停和退出设置。
 if(c=='p'){
 c = 0;
 while(c!='p'&&c!=27){
 c=cvWaitKey(250);
 }
 }
 if(c==27)
 return 0;
 image = cvQueryFrame(capture);//Get next image
  }//End collection while loop.

  //allocate matrices according to how many chessboards found
  CvMat * object_points2 = cvCreateMat(successes*board_n,3,CV_32FC1);
  CvMat * image_points2 = cvCreateMat(successes*board_n,2,CV_32FC1);
  CvMat * point_counts2 = cvCreateMat(successes,1,CV_32FC1);
  //transfer the points into the correct size matrices
  //below, we write out the details in the next two loops.we could instead have written:
  //image_points->rows=object_points->rows=
  //successes*board_n;point_counts->rows = successes;
  //
  for(int i = 0;i<successes*board_n;++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(*image_points,float,i,2);
  }
  for(int i=0;i<successes;++i){//There are all the same number
 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);//搞不懂为什么不直接用point_counts等,而要赋给point_counts2
  //at this point we have all of the chessboard corners we need.
  //initialize the intrinsic matrix such that the two focal
  //lengths have a ratio of 1.0
  //
  CV_MAT_ELEM(*intrinsic_matrix,float,0,0)=1.0f; //初始化内参矩阵
  CV_MAT_ELEM(*intrinsic_matrix,float,1,1)=1.0f;

  //calibrate the camera!
  cvCalibrateCamera2(
 object_points2,image_points2,
 point_counts2,cvGetSize(image),
 intrinsic_matrix,distortion_coeffs,
 NULL,NULL,0 //CV_CALIB_FIX_ASPECT_RATIO
 );  //定标,校正和旋转平移

  //save the intrinsics and distortions
  cvSave("Intrinsics.xml",intrinsic_matrix);  //把参数存下来。
  cvSave("Distortion.xml",distortion_coeffs);
  //example of loading these matrices back in:
  CvMat *intrinsic = (CvMat*)cvLoad("Intrinsics.xml");//intrinsic把参数读出来,传给重投影的函数应用的指针。
  CvMat *distortion = (CvMat*)cvLoad("Distortion.xml");

  //build the undistort map that will use for all
  //subsequent frames
  //
  IplImage* mapx = cvCreateImage(cvGetSize(image),IPL_DEPTH_32F,1);
  IplImage* mapy = cvCreateImage(cvGetSize(image),IPL_DEPTH_32F,1);
  cvInitUndistortMap(
 intrinsic,
 distortion,
 mapx,
 mapy
 );
  //just run the camera to the screen, now showing the raw and the undistorted image.
  //
  cvNamedWindow("Undistort");
  while(image){
 IplImage *t=cvCloneImage(image);
 cvShowImage("Calibration",image);//show raw image
 cvRemap(t,image,mapx,mapy);//undistort image  //重投影图像。
 cvReleaseImage(&t);
      cvShowImage("Undistort",image);//show corrected image

 //handle pause/unpause and ESC
 int c = cvWaitKey(15);
 if(c=='p'){
 c=0;
 while(c!='p'&&c!=27){
 c=cvWaitKey(250);
 }
 }
 if(c==27)
 break;
 image = cvQueryFrame(capture);
  }
  return 0;
  }


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值