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