【opencv3.0】鱼眼图像畸变校正——标定校正 17/11/14更新代码

前两天发表的时候没注意,代码出了点错误,所以修改了一下,重新发上来。
参考:
http://docs.opencv.org/3.0.0/db/d58/group__calib3d__fisheye.html#gga91b6a47d784dd47ea2c76ef656d7c3dca0899eaa2f96d6eed9927c4b4f4464e05
http://docs.opencv.org/master/modules/calib3d/doc/calib3d.html
opencv3.0 fisheye model reference
http://stackoverflow.com/questions/31089265/what-are-the-main-references-to-the-fish-eye-camera-model-in-opencv3-0-0dev/34388476#34388476

Kannala J, Brandt S S. A generic camera model and calibration method for conventional, wide-angle, and fish-eye lenses[J]. Pattern Analysis and Machine Intelligence, IEEE Transactions on, 2006, 28(8): 1335-1340.
文献地址:http://download.csdn.net/detail/qq_15947787/9583006

opencv也是参考matlab的Calib_gui_fisheye处理,但是不清楚为什么,Calib_gui_fisheye不能准确的提取角点
鱼眼镜头模型
  鱼眼镜头的内参模型可以表示为 这里写图片描述,与普通镜头的内参一样,但畸变参数不同,为这里写图片描述,含义如下:

设(X,Y,Z)为一个三维坐标点,投影在图像上的二维坐标为(u,v),如果不考虑畸变,投影关系如下:
  这里写图片描述
  R和t分别代表相机外参中的旋转矩阵和平移向量。
这里写图片描述

标定流程
  首先调用OpenCV的FindChessboardCorners()来寻找图像上的标定板的角点,再根据标定板的尺寸指定这些角点对应的三维点的三维坐标,再调用fisheye::calibrate()来进行标定,利用标定结果中的内参和畸变参数调用fisheye::undistortImage()对图像做去畸变操作。最后调用一张待测试的畸变图片利用标定结果进行畸变校正。

实验结果:
第1幅图像的平均误差:0.0255382像素
第2幅图像的平均误差:0.0325026像素
第3幅图像的平均误差:0.0244082像素
第4幅图像的平均误差:0.0311312像素
第5幅图像的平均误差:0.0205482像素
第6幅图像的平均误差:0.0385998像素
第7幅图像的平均误差:0.0423178像素
第8幅图像的平均误差:0.0442407像素
第9幅图像的平均误差:0.0396359像素
第10幅图像的平均误差:0.0337944像素
第11幅图像的平均误差:0.0294888像素
第12幅图像的平均误差:0.0391749像素
第13幅图像的平均误差:0.0589933像素
第14幅图像的平均误差:0.0239711像素
第15幅图像的平均误差:0.0267404像素
第16幅图像的平均误差:0.0298319像素
第17幅图像的平均误差:0.0346551像素
第18幅图像的平均误差:0.0538333像素
第19幅图像的平均误差:0.0385998像素
第20幅图像的平均误差:0.0485061像素
第21幅图像的平均误差:0.0441557像素
第22幅图像的平均误差:0.0541894像素
第23幅图像的平均误差:0.0299604像素
第24幅图像的平均误差:0.0385502像素
第25幅图像的平均误差:0.0226273像素
总体平均误差:0.0362398像素

相机内参数矩阵:
[322.4122272795701, 0, 626.3428871332725;
0, 322.6954347937962, 502.2060247826215;
0, 0, 1]
畸变系数:
[-0.0314732, 0.00545013, -0.00336236, 0.000262814]
第1幅图像的旋转向量:
[-3.03815, 0.388065, -0.0138772]
第1幅图像的旋转矩阵:
[0.9679029375838276, -0.2506097001682914, 0.01893889115435969;
-0.2513223502463919, -0.9648466048558239, 0.07686420080128105;
-0.0009897894864664397, -0.07915685238656738, -0.9968616819985727]
第1幅图像的平移向量:
[-36.6125, 83.2967, 169.266]
第2幅图像的旋转向量:
[-2.32548, 1.54006, 0.40201]
第2幅图像的旋转矩阵:
[0.378521586564022, -0.9239226330487051, -0.05557316479564789;
-0.8332059579221207, -0.3662733126966977, 0.4142604157885093;
-0.4030995412899122, -0.1105026178266161, -0.908460197953288]
第2幅图像的平移向量:
[63.1312, -57.5069, 165.236]
第3幅图像的旋转向量:
[2.44823, -1.67407, 0.725759]
第3幅图像的旋转矩阵:
[0.2871968675132958, -0.8984517932453987, 0.3321179526985517;
-0.8565648483398981, -0.3960822205235546, -0.3307801916281831;
0.4287360725189769, -0.1894815289131304, -0.8833357970340301]
第3幅图像的平移向量:
[9.19866, 173.995, 164.369]
第4幅图像的旋转向量:
[-2.92706, 0.182327, -0.805427]
第4幅图像的旋转矩阵:
[0.8529147476243522, -0.08859570292138545, 0.5144776328556494;
-0.1416154555912262, -0.9878071991931738, 0.06466838454629012;
0.502475368573004, -0.1280146032529221, -0.8550618488340014]
第4幅图像的平移向量:
[-114.612, 29.7974, 148.561]
第5幅图像的旋转向量:
[-2.94241, 0.292916, 0.443054]
第5幅图像的旋转矩阵:
[0.9372522606978974, -0.2140932338616103, -0.2751768286599686;
-0.1693276205911718, -0.969441300775839, 0.1775154113168249;
-0.3047726311885831, -0.1197816829265942, -0.9448629486405216]
第5幅图像的平移向量:
[83.013, 73.6934, 241.275]
第6幅图像的旋转向量:
[-2.75668, -1.001, -0.612898]
第6幅图像的旋转矩阵:
[0.6946906160764714, 0.6411847485001515, 0.326016972297594;
0.5818913059604812, -0.7673820777792599, 0.2693088464027711;
0.4228563065426579, 0.002620113353144188, -0.9061929590452126]
第6幅图像的平移向量:
[-156.079, -54.4814, 152.871]
第7幅图像的旋转向量:
[-2.83598, -0.88453, -0.738399]
第7幅图像的旋转矩阵:
[0.7170926483253193, 0.5539372902422747, 0.4230030876918346;
0.5151514661855453, -0.8300409149112951, 0.213661055085159;
0.4694646958022115, 0.06469588899046283, -0.8805778451352673]
第7幅图像的平移向量:
[-123.099, -60.5503, 92.6496]
第8幅图像的旋转向量:
[-2.94589, 0.176748, -0.583872]
第8幅图像的旋转矩阵:
[0.9181256495730359, -0.08877720787035021, 0.3862174244630025;
-0.1403284549278882, -0.9842687480550225, 0.1073450340712148;
0.3706119484496446, -0.1527535235761953, -0.9161403520757148]
第8幅图像的平移向量:
[-65.3965, 65.5516, 93.5776]
第9幅图像的旋转向量:
[-2.98668, 0.512548, 0.0276313]
第9幅图像的旋转矩阵:
[0.9427996228264289, -0.3333589160928895, 0.0008392018329849635;
-0.3313366658414531, -0.9367974551508381, 0.1123678863910088;
-0.03667267466945741, -0.1062184592445554, -0.9936663191677078]
第9幅图像的平移向量:
[25.637, 36.055, 149.153]
第10幅图像的旋转向量:
[-2.64713, 0.908772, 0.463857]
第10幅图像的旋转矩阵:
[0.7472614296825292, -0.6330773665259889, -0.202023275147545;
-0.5349933296317385, -0.7534557166822899, 0.3822127944592156;
-0.3941858609315764, -0.1775317745962544, -0.9017205642827143]
第10幅图像的平移向量:
[57.5034, -40.0235, 123.005]
第11幅图像的旋转向量:
[2.97099, 0.81535, -0.234947]
第11幅图像的旋转矩阵:
[0.8492655838870934, 0.5110771946433385, -0.1324691252345593;
0.503201513260689, -0.8594801895012334, -0.08990017189681285;
-0.1598005165106387, 0.009690457699146879, -0.9871017627137103]
第11幅图像的平移向量:
[3.82139, 101.52, 152.074]
第12幅图像的旋转向量:
[-2.86077, 0.432068, -0.546188]
第12幅图像的旋转矩阵:
[0.8891914447529974, -0.2460402134947138, 0.3857496440977657;
-0.3187574034884554, -0.9379532461778478, 0.1365189573126591;
0.3282259774901665, -0.2443520438382157, -0.9124471416869645]
第12幅图像的平移向量:
[-68.367, 122.421, 113.478]
第13幅图像的旋转向量:
[-2.90951, -0.523456, -0.663067]
第13幅图像的旋转矩阵:
[0.8449852726290712, 0.3552543160840582, 0.39974274220256;
0.3063658779533411, -0.9342262591823131, 0.1826506104016627;
0.4383375843637559, -0.03186953965575178, -0.8982452307562103]
第13幅图像的平移向量:
[-94.5581, 9.47137, 65.9367]
第14幅图像的旋转向量:
[-2.76209, 0.958866, -0.22678]
第14幅图像的旋转矩阵:
[0.7766776415625997, -0.5931753322324745, 0.2119312773699317;
-0.6252672489575734, -0.7667435817622675, 0.1454137105206963;
0.07624112064880313, -0.2454532645072427, -0.9664057049008724]
第14幅图像的平移向量:
[24.2611, 88.5081, 199.387]
第15幅图像的旋转向量:
[-2.84249, 0.0876038, -0.180569]
第15幅图像的旋转矩阵:
[0.9902889632803219, -0.04179158984697147, 0.1325942390273699;
-0.07827787950080752, -0.9558115385084162, 0.2833670348417959;
0.1148927447058423, -0.2909944430263867, -0.9498009745950575]
第15幅图像的平移向量:
[-6.92544, 32.624, 260.476]
第16幅图像的旋转向量:
[-2.17961, -1.94061, -0.409744]
第16幅图像的旋转矩阵:
[0.1026106120077555, 0.9917855891805973, 0.07637019966642694;
0.9380038094599215, -0.1220286791600962, 0.3244346696965635;
0.3310889846281055, 0.03834509820222493, -0.9428200982699678]
第16幅图像的平移向量:
[-55.2808, -83.903, 214.285]
第17幅图像的旋转向量:
[-2.21555, -0.438635, -0.150732]
第17幅图像的旋转矩阵:
[0.9312004456805553, 0.3620443217263547, -0.04230412592218191;
0.2595653905931794, -0.5771436506885823, 0.7742938812079467;
0.2559131453648801, -0.7320034942372609, -0.6314106005238542]
第17幅图像的平移向量:
[-64.4695, -103.74, 235.816]
第18幅图像的旋转向量:
[-2.97812, 0.0864579, -0.700192]
第18幅图像的旋转矩阵:
[0.8938975219841372, -0.03636454892238611, 0.4467939567320607;
-0.07340853688611149, -0.9951239589453907, 0.06587482861528146;
0.4422198626281497, -0.09168383671358701, -0.8922083092992448]
第18幅图像的平移向量:
[-86.0809, 61.0628, 69.4594]
第19幅图像的旋转向量:
[-3.00008, 0.239955, 0.155099]
第19幅图像的旋转矩阵:
[0.9820966811162741, -0.1644457693799922, -0.09188959611088617;
-0.1513134378357853, -0.9792000888366407, 0.1351718519242486;
-0.1122067398631442, -0.118847696466265, -0.9865520120976629]
第19幅图像的平移向量:
[-15.7077, 32.6659, 127.149]
第20幅图像的旋转向量:
[-2.95971, 0.562952, 0.361615]
第20幅图像的旋转矩阵:
[0.9030375888807793, -0.3736248978488473, -0.2119611963917617;
-0.3481253492941344, -0.9256202897130543, 0.1484446713437644;
-0.2516582091790878, -0.06026205256178804, -0.9659382127102203]
第20幅图像的平移向量:
[41.3163, 10.388, 118.481]
第21幅图像的旋转向量:
[-2.79374, 0.881471, 0.164568]
第21幅图像的旋转矩阵:
[0.8152064293359687, -0.5775133587591865, -0.04378125196911152;
-0.554407144845817, -0.7999860287028848, 0.22946692926018;
-0.1675446069356131, -0.1627902771509103, -0.9723312863175394]
第21幅图像的平移向量:
[-31.4756, 3.75149, 134.514]
第22幅图像的旋转向量:
[-2.98309, 0.637638, 0.0981236]
第22幅图像的旋转矩阵:
[0.9108160328030114, -0.4104565740919268, -0.04404038117117651;
-0.4047071445053953, -0.9088735260558214, 0.1008019881805276;
-0.08140197525412385, -0.07398861006652813, -0.9939312873660584]
第22幅图像的平移向量:
[85.0147, 158.892, 162.763]
第23幅图像的旋转向量:
[2.84253, -1.05597, -0.348542]
第23幅图像的旋转矩阵:
[0.7350751148451006, -0.6328998562959699, -0.2431097436056436;
-0.6532645704372982, -0.7571181193324142, -0.004189795928232765;
-0.1814110706292024, 0.1618947969487858, -0.9699897412725961]
第23幅图像的平移向量:
[99.5097, 185.972, 139.866]
第24幅图像的旋转向量:
[2.69949, -1.26373, -0.371771]
第24幅图像的旋转矩阵:
[0.6171775811411872, -0.735612817963387, -0.2792232357535401;
-0.7696284157724025, -0.6381835525130317, -0.01984577883350193;
-0.1635968672449875, 0.227146506356165, -0.9600211089751176]
第24幅图像的平移向量:
[122.42, 183.516, 123.981]
第25幅图像的旋转向量:
[2.73412, 0.903944, -0.920859]
第25幅图像的旋转矩阵:
[0.6369387495798474, 0.5748277850836829, -0.5136945072506112;
0.5029505052567296, -0.8148489726280646, -0.2882046860635478;
-0.5842515028184876, -0.07479417960493308, -0.8081188106655877]
第25幅图像的平移向量:
[38.5595, 196.165, 166.877]

畸变图像角点检测与校正结果:(只列出一部分)
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

对了200°视场的鱼眼图像效果还是很好的。
后面的校正图出现拉伸很严重的原因是因为标定板拍摄的时候是倾斜的,并不与光轴垂直。所以会出现近大远小的情况,也就是拉伸的情况。可以这么理解,把这些校正图中的棋盘位置看成无数连续的垂直于光轴的标定板,由于透视效果,远处的格子自然小,近处的会大,连续后就会成为这种现象,虽然人眼感觉怪怪的,但是符合空间分布情况。可以想象一下隧道里的情况,下图还是一个小视场的图,墙上格子变化很明显,如果视场更大一些,就更明显了。
这里写图片描述

代码下载:
附件中删除了部分图像(有脸的图都删了……-
http://download.csdn.net/detail/qq_15947787/9527601

2016/10/24 23:00重新装上了VS2013和OPENCV3.0,简单修改了下代码,删除了一些没必要的变量,做了简单优化,另外感觉损失原有图像信息的方法,也间接得到改善,不需要修改参数,可以直接运行。 //以下三行为需要手动修改的参数 int image_count= 14;//图像数量 Size board_size = Size(9,6);//定标板上每行、列的角点数 int x_expand = 0,y_expand = 200;//x,y方向的扩展(x横向,y纵向),适当增大可以不损失原图像信息
(这里的链接删除了)

2016/12/2 20:00在做双目标定及空间点计算时,突然看到stereoRectify有一个alpha参数,可以调节校正图的大小,而initUndistortRectifyMap中的size是校正图的大小,并不是原图大小,这样应该就好办了吧。
还有一个是在http://blog.csdn.net/dip007/article/details/51498644看到了方法,在这里谢谢他,直接把上面代码的最后一部分替代即可,代码如下
懒得复制的可以直接下载
http://download.csdn.net/detail/qq_15947787/9700379

   /********************************************************* 
           测试一张图片  
  **********************************************************/
    if (1)
    {
		cout<<"TestImage ..."<<endl;
		Mat distort_img = imread("a.jpg",1);
		Mat undistort_img;
		Mat intrinsic_mat(intrinsic_matrix),new_intrinsic_mat;
		
		intrinsic_mat.copyTo(new_intrinsic_mat);
		//调节视场大小,乘的数越小视场越大
		new_intrinsic_mat.at<double>(0,0)*=0.8;
		new_intrinsic_mat.at<double>(1,1)*=0.8;
		//调节校正图中心,一般不做改变
		new_intrinsic_mat.at<double>(0,2)+=0;
		new_intrinsic_mat.at<double>(1,2)+=0;

		fisheye::undistortImage(distort_img,undistort_img,intrinsic_matrix,distortion_coeffs,new_intrinsic_mat);
		imwrite("output.jpg",undistort_img);
		cout<<"保存结束"<<endl;
    }

2016/12/8 17:00其实主点坐标调节一下比较好,将他置于校正图中心处,把最后一段代码改成这样,在原文的代码直接改就可以,从上面的链接下载的直接改也可以

/********************************************************** 
           测试一张图片  
    *********************************************************/
    if (1)
    {
		cout<<"TestImage ..."<<endl;
		Mat distort_img = imread("a.jpg",1);
		Mat undistort_img;
		Mat intrinsic_mat(intrinsic_matrix),new_intrinsic_mat;
		
		intrinsic_mat.copyTo(new_intrinsic_mat);
		//调节视场大小,乘的系数越小视场越大
		new_intrinsic_mat.at<double>(0,0) *= 0.5;
		new_intrinsic_mat.at<double>(1,1) *= 0.5;
		//调节校正图中心,建议置于校正图中心
		new_intrinsic_mat.at<double>(0,2) = 0.5 * distort_img.cols;
		new_intrinsic_mat.at<double>(1,2) = 0.5 * distort_img.rows;

		fisheye::undistortImage(distort_img,undistort_img,intrinsic_matrix,distortion_coeffs,new_intrinsic_mat);
		imwrite("output.jpg",undistort_img);
		cout<<"保存结束"<<endl;
    }

**2017/8/17 **
将(两处)

fisheye::initUndistortRectifyMap(intrinsic_matrix,distortion_coeffs,R,intrinsic_matrix,image_size,CV_32FC1,mapx,mapy);

修改为:`

fisheye::initUndistortRectifyMap(intrinsic_matrix,distortion_coeffs,R,
            getOptimalNewCameraMatrix(intrinsic_matrix, distortion_coeffs, image_size, 1, image_size, 0),image_size,CV_32FC1,mapx,mapy);`

不影响标定,只影响到畸变校正结果

原代码删除,所有代码重新上传,下面为最新代码:

//运行环境 VS2012+opencv3.0已测试  VS2015+opencv3.2已测试
#include <opencv2\opencv.hpp>
#include <fstream>
using namespace std;
using namespace cv;

int main()
{
	ofstream fout("caliberation_result.txt");  /**    保存定标结果的文件     **/

	/************************************************************************
	读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
	*************************************************************************/
	cout << "开始提取角点………………" << endl;
	int image_count = 20;                    /****    图像数量     ****/
	Size board_size = Size(9, 6);            /****    定标板上每行、列的角点数       ****/
	vector<Point2f> corners;                  /****    缓存每幅图像上检测到的角点       ****/
	vector<vector<Point2f>>  corners_Seq;    /****  保存检测到的所有角点       ****/
	vector<Mat>  image_Seq;
	int successImageNum = 0;                /****   成功提取角点的棋盘图数量    ****/

	int count = 0;
	for (int i = 0; i != image_count; i++)
	{
		cout << "Frame #" << i + 1 << "..." << endl;
		string imageFileName;
		std::stringstream StrStm;
		StrStm << i + 1;
		StrStm >> imageFileName;
		imageFileName += ".jpg";
		cv::Mat image = imread("img" + imageFileName);
		/* 提取角点 */
		Mat imageGray;
		cvtColor(image, imageGray, CV_RGB2GRAY);
		bool patternfound = findChessboardCorners(image, board_size, corners, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE +
			CALIB_CB_FAST_CHECK);
		if (!patternfound)
		{
			cout << "找不到角点,需删除图片文件" << imageFileName << "重新排列文件名,再次标定" << endl;
			getchar();
			exit(1);
		}
		else
		{
			/* 亚像素精确化 */
			cornerSubPix(imageGray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
			/* 绘制检测到的角点并保存 */
			Mat imageTemp = image.clone();
			for (int j = 0; j < corners.size(); j++)
			{
				circle(imageTemp, corners[j], 10, Scalar(0, 0, 255), 2, 8, 0);
			}
			string imageFileName;
			std::stringstream StrStm;
			StrStm << i + 1;
			StrStm >> imageFileName;
			imageFileName += "_corner.jpg";
			imwrite(imageFileName, imageTemp);
			cout << "Frame corner#" << i + 1 << "...end" << endl;

			count = count + corners.size();
			successImageNum = successImageNum + 1;
			corners_Seq.push_back(corners);
		}
		image_Seq.push_back(image);
	}
	cout << "角点提取完成!\n";
	/************************************************************************
	摄像机定标
	*************************************************************************/
	cout << "开始定标………………" << endl;
	Size square_size = Size(20, 20);
	vector<vector<Point3f>>  object_Points;        /****  保存定标板上角点的三维坐标   ****/

	Mat image_points = Mat(1, count, CV_32FC2, Scalar::all(0));  /*****   保存提取的所有角点   *****/
	vector<int>  point_counts;
	/* 初始化定标板上角点的三维坐标 */
	for (int t = 0; t<successImageNum; t++)
	{
		vector<Point3f> tempPointSet;
		for (int i = 0; i<board_size.height; i++)
		{
			for (int j = 0; j<board_size.width; j++)
			{
				/* 假设定标板放在世界坐标系中z=0的平面上 */
				Point3f tempPoint;
				tempPoint.x = i*square_size.width;
				tempPoint.y = j*square_size.height;
				tempPoint.z = 0;
				tempPointSet.push_back(tempPoint);
			}
		}
		object_Points.push_back(tempPointSet);
	}
	for (int i = 0; i< successImageNum; i++)
	{
		point_counts.push_back(board_size.width*board_size.height);
	}
	/* 开始定标 */
	Size image_size = image_Seq[0].size();
	cv::Matx33d intrinsic_matrix;    /*****    摄像机内参数矩阵    ****/
	cv::Vec4d distortion_coeffs;     /* 摄像机的4个畸变系数:k1,k2,k3,k4*/
	std::vector<cv::Vec3d> rotation_vectors;                           /* 每幅图像的旋转向量 */
	std::vector<cv::Vec3d> translation_vectors;                        /* 每幅图像的平移向量 */
	int flags = 0;
	flags |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;
	flags |= cv::fisheye::CALIB_CHECK_COND;
	flags |= cv::fisheye::CALIB_FIX_SKEW;
	fisheye::calibrate(object_Points, corners_Seq, image_size, intrinsic_matrix, distortion_coeffs, rotation_vectors, translation_vectors, flags, cv::TermCriteria(3, 20, 1e-6));
	cout << "定标完成!\n";

	/************************************************************************
	对定标结果进行评价
	*************************************************************************/
	cout << "开始评价定标结果………………" << endl;
	double total_err = 0.0;                   /* 所有图像的平均误差的总和 */
	double err = 0.0;                        /* 每幅图像的平均误差 */
	vector<Point2f>  image_points2;             /****   保存重新计算得到的投影点    ****/

	cout << "每幅图像的定标误差:" << endl;
	cout << "每幅图像的定标误差:" << endl << endl;
	for (int i = 0; i<image_count; i++)
	{
		vector<Point3f> tempPointSet = object_Points[i];
		/****    通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点     ****/
		fisheye::projectPoints(tempPointSet, image_points2, rotation_vectors[i], translation_vectors[i], intrinsic_matrix, distortion_coeffs);
		/* 计算新的投影点和旧的投影点之间的误差*/
		vector<Point2f> tempImagePoint = corners_Seq[i];
		Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2);
		Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);
		for (size_t i = 0; i != tempImagePoint.size(); i++)
		{
			image_points2Mat.at<Vec2f>(0, i) = Vec2f(image_points2[i].x, image_points2[i].y);
			tempImagePointMat.at<Vec2f>(0, i) = Vec2f(tempImagePoint[i].x, tempImagePoint[i].y);
		}
		err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
		total_err += err /= point_counts[i];
		cout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
		fout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
	}
	cout << "总体平均误差:" << total_err / image_count << "像素" << endl;
	fout << "总体平均误差:" << total_err / image_count << "像素" << endl << endl;
	cout << "评价完成!" << endl;

	/************************************************************************
	保存定标结果
	*************************************************************************/
	cout << "开始保存定标结果………………" << endl;
	Mat rotation_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */

	fout << "相机内参数矩阵:" << endl;
	fout << intrinsic_matrix << endl;
	fout << "畸变系数:\n";
	fout << distortion_coeffs << endl;
	for (int i = 0; i<image_count; i++)
	{
		fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
		fout << rotation_vectors[i] << endl;

		/* 将旋转向量转换为相对应的旋转矩阵 */
		Rodrigues(rotation_vectors[i], rotation_matrix);
		fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
		fout << rotation_matrix << endl;
		fout << "第" << i + 1 << "幅图像的平移向量:" << endl;
		fout << translation_vectors[i] << endl;
	}
	cout << "完成保存" << endl;
	fout << endl;


	/************************************************************************
	显示定标结果
	*************************************************************************/
	Mat mapx = Mat(image_size, CV_32FC1);
	Mat mapy = Mat(image_size, CV_32FC1);
	Mat R = Mat::eye(3, 3, CV_32F);

	cout << "保存矫正图像" << endl;
	for (int i = 0; i != image_count; i++)
	{
		cout << "Frame #" << i + 1 << "..." << endl;
		//fisheye::initUndistortRectifyMap(intrinsic_matrix,distortion_coeffs,R,intrinsic_matrix,image_size,CV_32FC1,mapx,mapy);
		fisheye::initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, R,
			getOptimalNewCameraMatrix(intrinsic_matrix, distortion_coeffs, image_size, 1, image_size, 0), image_size, CV_32FC1, mapx, mapy);
		Mat t = image_Seq[i].clone();
		cv::remap(image_Seq[i], t, mapx, mapy, INTER_LINEAR);
		string imageFileName;
		std::stringstream StrStm;
		StrStm << i + 1;
		StrStm >> imageFileName;
		imageFileName += "_d.jpg";
		imwrite(imageFileName, t);
	}
	cout << "保存结束" << endl;


	/************************************************************************
	测试一张图片
	*************************************************************************/
	if (1)
	{
		//cout<<"TestImage ..."<<endl;
		//Mat testImage = imread("a.jpg",1);
		//fisheye::initUndistortRectifyMap(intrinsic_matrix,distortion_coeffs,R,
		//    getOptimalNewCameraMatrix(intrinsic_matrix, distortion_coeffs, image_size, 1, image_size, 0),image_size,CV_32FC1,mapx,mapy);
		//Mat t = testImage.clone();
		//cv::remap(testImage,t,mapx, mapy, INTER_LINEAR);

		//imwrite("TestOutput.jpg",t);
		//cout<<"保存结束"<<endl;

		cout << "TestImage ..." << endl;
		Mat distort_img = imread("a.jpg", 1);
		Mat undistort_img;
		Mat intrinsic_mat(intrinsic_matrix), new_intrinsic_mat;

		intrinsic_mat.copyTo(new_intrinsic_mat);
		//调节视场大小,乘的系数越小视场越大
		new_intrinsic_mat.at<double>(0, 0) *= 0.5;
		new_intrinsic_mat.at<double>(1, 1) *= 0.5;
		//调节校正图中心,建议置于校正图中心
		new_intrinsic_mat.at<double>(0, 2) = 0.5 * distort_img.cols;
		new_intrinsic_mat.at<double>(1, 2) = 0.5 * distort_img.rows;

		fisheye::undistortImage(distort_img, undistort_img, intrinsic_matrix, distortion_coeffs, new_intrinsic_mat);
		imwrite("output.jpg", undistort_img);
		cout << "保存结束" << endl;
	}


	return 0;
}

opencv2中没有鱼眼模型,opencv3中才加入Fisheye camera model by Ilya Krylov,opencv3新加入的功能见链接http://blog.csdn.net/qq_15947787/article/details/50778609

  • 54
    点赞
  • 223
    收藏
    觉得还不错? 一键收藏
  • 89
    评论
鱼眼图像畸变校正的透视变换原理如下: 1. 首先,需要确定图像中的两个灭点,这可以通过球面透视投影得到。 2. 然后,根据灭点的位置,确定仿射变换矩阵,将图像进行仿射变换。 3. 最后,对变换后的图像进行裁剪,得到最终的校正图像。 下面是一个使用OpenCV进行鱼眼图像畸变校正的Python代码示例: ```python import cv2 import numpy as np # 读取鱼眼图像 img = cv2.imread('fisheye.jpg') # 确定灭点 h, w = img.shape[:2] K = np.array([[w, 0, w/2], [0, w, h/2], [0, 0, 1]]) D = np.array([0, 0, 0, 0]) newK = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(K, D, (w, h), np.eye(3)) map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, D, np.eye(3), newK, (w, h), cv2.CV_16SC2) img_undistorted = cv2.remap(img, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT) # 确定仿射变换矩阵 src_points = np.float32([[0, 0], [w-1, 0], [0, h-1], [w-1, h-1]]) dst_points = np.float32([[w/4, h/4], [w*3/4, h/4], [0, h], [w, h]]) M = cv2.getPerspectiveTransform(src_points, dst_points) # 进行仿射变换 img_transformed = cv2.warpPerspective(img_undistorted, M, (w, h)) # 裁剪图像 img_corrected = img_transformed[int(h/4):int(h*3/4), int(w/4):int(w*3/4)] # 显示结果 cv2.imshow('Original Image', img) cv2.imshow('Undistorted Image', img_undistorted) cv2.imshow('Transformed Image', img_transformed) cv2.imshow('Corrected Image', img_corrected) cv2.waitKey(0) cv2.destroyAllWindows() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 89
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值