照片畸变校正 python_【opencv】鱼眼图像畸变校正——标定校正(示例代码)

参考:

http://docs.opencv.org/3.0.0/db/d58/group__calib3d__fisheye.html#gga91b6a47d784dd47ea2c76ef656d7c3dca0899eaa2f96d6eed9927c4b4f4464e05

http://docs.opencv.org/master/modules/calib3d/doc/calib3d.html

opencv2.4.9 Fisheye camera model reference

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.

鱼眼镜头模型

鱼眼镜头的内参模型可以表示为

,与普通镜头的内参一样,但畸变参数不同,为

,含义如下:

设(X,Y,Z)为一个三维坐标点,投影在图像上的二维坐标为(u,v),如果不考虑畸变,投影关系如下:

R和t分别代表相机外参中的旋转矩阵和平移向量。

标定流程

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

//运行环境 VS2012+opencv2.4.9

#include

#include

using namespace std;

using namespace cv;

int main()

{

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

/************************************************************************

读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化

*************************************************************************/

cout<

int image_count= 4; /**** 图像数量 ****/

Size image_size; /**** 图像的尺寸 ****/

Size board_size = Size(6,9); /**** 定标板上每行、列的角点数 ****/

vector corners; /**** 缓存每幅图像上检测到的角点 ****/

vector> corners_Seq; /**** 保存检测到的所有角点 ****/

vector image_Seq;

int count = 0;

for( int i = 0; i != image_count ; i++)

{

cout<

string imageFileName;

std::stringstream StrStm;

StrStm<

StrStm>>imageFileName;

imageFileName += ".jpg";

cv::Mat image = imread("img"+imageFileName);

image_size = image.size();

//image_size = Size(image.cols , image.rows);

/* 提取角点 */

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<

exit(1);

}

else

{

/* 亚像素精确化 */

cornerSubPix(imageGray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));

count = count + corners.size();

corners_Seq.push_back(corners);

}

image_Seq.push_back(image);

}

cout<

/************************************************************************

摄像机定标

*************************************************************************/

cout<

Size square_size = Size(20,20); /**** 实际测量得到的定标板上每个棋盘格的大小 ****/

vector> object_Points; /**** 保存定标板上角点的三维坐标 ****/

Mat image_points = Mat(1, count , CV_32FC2, Scalar::all(0)); /***** 保存提取的所有角点 *****/

vector point_counts; /***** 每幅图像中角点的数量 ****/

Mat intrinsic_matrix = Mat(3,3, CV_32FC1, Scalar::all(0)); /***** 摄像机内参数矩阵 ****/

Mat distortion_coeffs = Mat(1,4, CV_32FC1, Scalar::all(0)); /* 摄像机的4个畸变系数:k1,k2,p1,p2 */

vector<:mat> rotation_vectors; /* 每幅图像的旋转向量 */

vector<:mat> translation_vectors; /* 每幅图像的平移向量 */

/* 初始化定标板上角点的三维坐标 */

for (int t=0;t

{

vector tempPointSet;

for (int i=0;i

{

for (int j=0;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< image_count; i++)

{

point_counts.push_back(board_size.width*board_size.height);

}

/* 开始定标 */

calibrateCamera(object_Points, corners_Seq, image_size, intrinsic_matrix ,distortion_coeffs, rotation_vectors, translation_vectors, 0);

cout<

/************************************************************************

对定标结果进行评价

*************************************************************************/

cout<

double total_err = 0.0; /* 所有图像的平均误差的总和 */

double err = 0.0; /* 每幅图像的平均误差 */

vector image_points2; /**** 保存重新计算得到的投影点 ****/

cout<

cout<

for (int i=0; i

{

vector tempPointSet = object_Points[i];

/**** 通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点 ****/

projectPoints(tempPointSet, rotation_vectors[i], translation_vectors[i], intrinsic_matrix, distortion_coeffs, image_points2);

/* 计算新的投影点和旧的投影点之间的误差*/

vector 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(0,i) = Vec2f(image_points2[i].x, image_points2[i].y);

tempImagePointMat.at(0,i) = Vec2f(tempImagePoint[i].x, tempImagePoint[i].y);

}

err = norm(image_points2Mat, tempImagePointMat, NORM_L2);

total_err += err/= point_counts[i];

cout<

fout<

}

cout<

fout<

cout<

/************************************************************************

保存定标结果

*************************************************************************/

cout<

Mat rotation_matrix = Mat(3,3,CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */

fout<

fout<

fout<

fout<

for (int i=0; i

{

fout<

fout<

/* 将旋转向量转换为相对应的旋转矩阵 */

Rodrigues(rotation_vectors[i],rotation_matrix);

fout<

fout<

fout<

fout<

}

cout<

fout<

/************************************************************************

显示定标结果

*************************************************************************/

Mat mapx = Mat(image_size,CV_32FC1);

Mat mapy = Mat(image_size,CV_32FC1);

Mat R = Mat::eye(3,3,CV_32F);

cout<

for (int i = 0 ; i != image_count ; i++)

{

cout<

Mat newCameraMatrix = Mat(3,3,CV_32FC1,Scalar::all(0));

initUndistortRectifyMap(intrinsic_matrix,distortion_coeffs,R,intrinsic_matrix,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<

StrStm>>imageFileName;

imageFileName += "_d.jpg";

imwrite(imageFileName,t);

}

cout<

/************************************************************************

测试一张图片

*************************************************************************/

cout<

Mat newCameraMatrix = Mat(3,3,CV_32FC1,Scalar::all(0));

Mat testImage = imread("test.jpg",1);

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

Mat t = testImage.clone();

cv::remap(testImage,t,mapx, mapy, INTER_LINEAR);

imwrite("TestOutput.jpg",t);

cout<

return 0;

}

实验结果:

第1幅图像的平均误差:0.234066像素

第2幅图像的平均误差:0.174135像素

第3幅图像的平均误差:0.230404像素

第4幅图像的平均误差:0.385148像素

总体平均误差:0.255938像素

相机内参数矩阵:

[1526.985633757815, 0, 950.2799160336148;

0, 1524.888027372896, 1626.73459851929;

0, 0, 1]

畸变系数:

[-0.2939854304014771, -0.03809991415256448, -0.0006251660855326396, 0.002477996377628106, 0.08710997961828348]

第1幅图像的旋转向量:

[-2.044082716917989;

2.112604062430628;

-0.4512837261687678]

第1幅图像的旋转矩阵:

[-0.04783928023483552, -0.9443057645861673, 0.3255733807238344;

-0.9949113651213172, 0.01611256042205056, -0.0994573323042737;

0.08867231145656364, -0.3286746238546258, -0.9402713506296841]

第1幅图像的平移向量:

[64.01021865713052;

98.56104619426411;

147.9806640258283]

第2幅图像的旋转向量:

[-1.162650885638092;

2.737696507332989;

0.1448079633779595]

第2幅图像的旋转矩阵:

[-0.6837940150923046, -0.7210082406540599, 0.1121287734387665;

-0.7051562408233225, 0.6924689388697722, 0.1524514503981244;

-0.1875644447966232, 0.02517708500816826, -0.9819295766187237]

第2幅图像的平移向量:

[92.91837801221574;

58.91364372752962;

181.052631025211]

第3幅图像的旋转向量:

[1.684131027388537;

-2.175687329421208;

-0.2403921029056955]

第3幅图像的旋转矩阵:

[-0.2115618190438919, -0.894254676073194, -0.3943984927000438;

-0.9587869203326895, 0.2681969799312525, -0.09379776838876375;

0.1896555776184723, 0.3583000896971452, -0.9141399278016584]

第3幅图像的平移向量:

[35.54570544850407;

64.77270398447031;

122.9118368955376]

第4幅图像的旋转向量:

[2.717206221016452;

1.219573939678138;

0.807283561760737]

第4幅图像的旋转矩阵:

[0.5510728665512401, 0.6808924688738628, 0.4823941765629592;

0.7100594861195663, -0.6862919236796685, 0.1575402223677423;

0.4383311783601724, 0.2557124191800546, -0.8616710142243772]

第4幅图像的平移向量:

[-45.13197759830062;

-19.42296234432086;

113.2028514971537]

畸变图像:

img1.jpg

img2.jpg

img3.jpg

img4.jpg

test.jpg

校正结果:

TestOutput.jpg

你可能感兴趣的:(照片畸变校正,python)