您的位置:首页 > 其它

关于图像透射变换的一点总结

2011-03-07 16:30 323 查看
前段时间为将机器人单目视觉图像从透视图转化为鸟瞰图做了一点研究,这两天为了一个利用图像偏振的野外积水检测,需要将透视图转化为鸟瞰图。上次的这块东西没有好好的总结一下,所以今天花了下午不少时间回顾上次做的研究。ps不做好总结害死人啊,光找上次的那几个工程就花了半天时间,搜索了整个E盘,结果却发现原来那几个工程都在桌面上,浮云啊。

言归正传,这里用到的其实就是学习OpenCV这本书12章ex12里面的东西。无非就是利用事先标定好的摄像头内参数和畸变矩阵将图像去畸变,计算透射变换矩阵,然后将原来的透视图转化为鸟瞰图而已。

#include <cv.h>
#include <highgui.h>
#include <stdio.h>
#include <stdlib.h>
void help(){
printf("Birds eye view/n/n"
"  birdseye board_w board_h intrinsics_mat.xml distortion_mat.xml checker_image /n/n"
"Where: board_{w,h}    are the # of internal corners in the checkerboard/n"
"       intrinsic      intrinsic path/name of matrix from prior calibration/n"
"       distortion     distortion path/name of matrix from pror calibration/n"
"       checker_image  is the path/name of image of checkerboard on the plane /n"
"                      Frontal view of this will be shown./n/n"
" ADJUST VIEW HEIGHT using keys 'u' up, 'd' down. ESC to quit./n/n");
}
int main(int argc, char* argv[]) {
argv[5]="test";
argc=6;
if(argc != 6){
printf("/nERROR: too few parameters/n");
help();
return -1;
}
help();
//INPUT PARAMETERS:
int board_w =9;// atoi("12");
int board_h =6;// atoi("12");
int board_n  = board_w * board_h;
CvSize board_sz = cvSize( board_w, board_h );
//读入已近标定好的摄像机内参数和畸变参数
CvMat *intrinsic = (CvMat*)cvLoad("Intrinsics.xml");
CvMat *distortion = (CvMat*)cvLoad("Distortion.xml");
IplImage *image = 0, *gray_image = 0;
if((image = cvLoadImage("001.bmp"))== 0){
printf("Error: Couldn't load %s/n",argv[5]);
return -1;
}
gray_image = cvCreateImage(cvGetSize(image),8,1);
cvCvtColor(image, gray_image, CV_BGR2GRAY);

//UNDISTORT OUR IMAGE
//图片去畸变处理
IplImage* mapx = cvCreateImage( cvGetSize(image), IPL_DEPTH_32F, 1 );
IplImage* mapy = cvCreateImage( cvGetSize(image), IPL_DEPTH_32F, 1 );
cvInitUndistortMap(
intrinsic,
distortion,
mapx,
mapy
);
IplImage *t = cvCloneImage(image);
cvRemap( t, image, mapx, mapy );
//GET THE CHECKERBOARD ON THE PLANE
cvNamedWindow("Checkers",0);
CvPoint2D32f* corners = new CvPoint2D32f[ board_n ];
int corner_count = 0;
int found = cvFindChessboardCorners(
image,
board_sz,
corners,
&corner_count,
CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS
);
if(!found){
printf("Couldn't aquire checkerboard on %s, only found %d of %d corners/n",
argv[5],corner_count,board_n);
//		return -1;
}
//Get Subpixel accuracy on those corners
cvFindCornerSubPix(gray_image, corners, corner_count,
cvSize(11,11),cvSize(-1,-1),
cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 ));
//GET THE IMAGE AND OBJECT POINTS:
//Object points are at (r,c): (0,0), (board_w-1,0), (0,board_h-1), (board_w-1,board_h-1)
//That means corners are at: corners[r*board_w + c]
CvPoint2D32f objPts[4], imgPts[4];
objPts[0].x = 0;         objPts[0].y = 0;
objPts[1].x = board_w-1; objPts[1].y = 0;
objPts[2].x = 0;         objPts[2].y = board_h-1;
objPts[3].x = board_w-1; objPts[3].y = board_h-1;
/*	imgPts[3] = corners[0];
imgPts[2] = corners[board_w-1];
imgPts[1] = corners[(board_h-1)*board_w];
imgPts[0] = corners[(board_h-1)*board_w + board_w-1];*/
imgPts[0] = cvPoint2D32f(322 , 375 );
imgPts[1] = cvPoint2D32f( 430, 374 );
imgPts[2] = cvPoint2D32f(321 ,  416);
imgPts[3] = cvPoint2D32f( 436,  415);
//顺序为0 1 2 3分别对应左上、右上、左下、右下
//	imgPts[1] = corners[0];
//	imgPts[3] = corners[board_w-1];
//	imgPts[0] = corners[(board_h-1)*board_w];
//	imgPts[2] = corners[(board_h-1)*board_w + board_w-1];
//DRAW THE POINTS in order: B,G,R,YELLOW
cvCircle(image,cvPointFrom32f(imgPts[0]),9,CV_RGB(0,0,255),3);
cvCircle(image,cvPointFrom32f(imgPts[1]),9,CV_RGB(0,255,0),3);
cvCircle(image,cvPointFrom32f(imgPts[2]),9,CV_RGB(255,0,0),3);
cvCircle(image,cvPointFrom32f(imgPts[3]),9,CV_RGB(255,255,0),3);
//DRAW THE FOUND CHECKERBOARD
cvDrawChessboardCorners(image, board_sz, corners, corner_count, found);
cvShowImage( "Checkers", image );
//FIND THE HOMOGRAPHY
CvMat *H = cvCreateMat( 3, 3, CV_32F);
CvMat *H_invt = cvCreateMat(3,3,CV_32F);
cvGetPerspectiveTransform(objPts,imgPts,H);
//LET THE USER ADJUST THE Z HEIGHT OF THE VIEW
float Z = 25;
int key = 1;
IplImage *birds_image = cvCloneImage(image);
cvNamedWindow("Birds_Eye",1);
while(key != 27) {//escape key stops
CV_MAT_ELEM(*H,float,2,2) = Z;
//	   cvInvert(H,H_invt); //If you want to invert the homography directly
//	   cvWarpPerspective(image,birds_image,H_invt,CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS );
//USE HOMOGRAPHY TO REMAP THE VIEW
cvWarpPerspective(image,birds_image,H,
CV_INTER_LINEAR+CV_WARP_INVERSE_MAP+CV_WARP_FILL_OUTLIERS );
cvShowImage("Birds_Eye", birds_image);
key = cvWaitKey();
if(key == 'u') Z += 0.5;
if(key == 'd') Z -= 0.5;
}
/*
//SHOW ROTATION AND TRANSLATION VECTORS
CvMat* image_points  = cvCreateMat(4,1,CV_32FC2);
CvMat* object_points = cvCreateMat(4,1,CV_32FC3);
for(int i=0;i<4;++i){
CV_MAT_ELEM(*image_points,CvPoint2D32f,i,0) = imgPts[i];
CV_MAT_ELEM(*object_points,CvPoint3D32f,i,0) = cvPoint3D32f(objPts[i].x,objPts[i].y,0);
}
CvMat *RotRodrigues   = cvCreateMat(3,1,CV_32F);
CvMat *Rot   = cvCreateMat(3,3,CV_32F);
CvMat *Trans = cvCreateMat(3,1,CV_32F);
cvFindExtrinsicCameraParams2(object_points,image_points,
intrinsic,distortion,
RotRodrigues,Trans);
cvRodrigues2(RotRodrigues,Rot);
//SAVE AND EXIT
cvSave("Rot.xml",Rot);
cvSave("Trans.xml",Trans);
cvSave("H.xml",H);
cvInvert(H,H_invt);
cvSave("H_invt.xml",H_invt); //Bottom row of H invert is horizon line*/
cvSave("Here.xml",H);
return 0;
}


程序也挺简单,就是利用棋盘法,利用cvFindChessboardCorners这个函数找到棋盘的各个角点,然后利用cvFindCornerSubPix计算亚像素角点。接着利用棋盘的四个顶点坐标和棋盘本身的长宽比来计算透射变换矩阵。(其实这里只用到了棋盘的四个顶点坐标,OpenCV自带的棋盘角点检测函数老是找不准棋盘上的所有角点,这里还不如直接自己手动确定棋盘四个顶点的角点坐标,具体坐标就是
imgPts[3] = corners[0];
imgPts[2] = corners[board_w-1];
imgPts[1] = corners[(board_h-1)*board_w];
imgPts[0] = corners[(board_h-1)*board_w + board_w-1];
这里的四个亚像素坐标,顺序为为0 1 2 3分别对应左上、右上、左下、右下)。然后利用cvGetPerspectiveTransform函数就可以计算得到透射变换矩阵H。

然后就可以利用cvWarpPerspective函数对图像进行透视变换。

具体结果如下图。第一幅图为原图,第二图图即为透视变换后的鸟瞰图。



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: