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

学习机器视觉。尝试例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;
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值