Opencv 相机内参标定及使用 一、功能描述 1.本文用于记录通过 Opencv 进行相机内参标定和对内参的使用来进行图像畸变矫正。
1)相机矩阵:包括焦距(fx,fy),光学中心(Cx,Cy),完全取决于相机本身,是相机的固有属性,只需要计算一次,可用矩阵表示如下:[fx, 0, Cx; 0, fy, cy; 0,0,1];
畸变系数:畸变数学模型的5个参数 D = (k1,k2, P1, P2, k3);
3)相机内参:相机矩阵和畸变系数统称为相机内参,在不考虑畸变的时候,相机矩阵也会被称为相机内参;
4) 相机外参:通过旋转和平移变换将3D的坐标转换为相机2维的坐标,其中的旋转矩阵和平移矩阵就被称为相机的外参;描述的是将世界坐标系转换成相机坐标系的过程。
二、标定板制作 方法一: 标定板可以直接从opencv官网下载:标定板
方法二:Matlab DIY 制作
1 2 J = (checkerboard(300,4,5)>0.5); figure, imshow(J);
打印完成后,测量实际打印出的网格边长,备用(本人制作的标定板网格边长为 26mm)。将打印纸贴附在硬纸板上(粘贴的尽可能平整),如下图所示。
三、图像采集 运行以下参考程序按q键即可保存图像,注意尽量把镜头的每个方格都覆盖到,最好拍到整张打印纸。保存大约20到25张,通过 Matlab 标定软件可能会剔除部分图片。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include "opencv2/opencv.hpp" #include <string> #include <iostream> using namespace cv; using namespace std ; int main () { Mat frame; string imgname; int f = 1 ; VideoCapture inputVideo (0 ) ; if (!inputVideo.isOpened()){ cout << "Could not open the input video " << endl ; return -1 ; } else { cout << "video is opened!" << endl ; } while (1 ){ inputVideo >> frame; if (frame.empty()) continue ; imshow("Camera" , frame); char key = waitKey(1 ); if (key == 27 ) break ; if (key == 'q' || key == 'Q' ){ imgname = to_string(f++) + ".jpg" ; imwrite(imgname, frame); } } cout << "Finished writing" << endl ; return 0 ; }
四、标定内参 方法一:Matlab标定 **步骤1:**在Matlab的Command Window里面输入cameraCalibrator即可调用标定应用程序。
**步骤2:**选择from file 在自己的图片集全选待标定的图片,输入自己实际测量打印的标定板方格实际长度(本人的标定板方格边长26mm),导入后我的有2张图片被拒绝。
**步骤3:**关键步骤
畸变参数,总共有五个,径向畸变3个(k1,k2,k3)和切向畸变2个(p1,p2)。
径向畸变:
实验表明,在MATLAB中选择使用三个参数,并且选择错切和桶形畸变,关于三个参数还是两个参数,可以根据自己的试验效果选择 。点击 Calibrate 后等待一段时间即可完成标定,标定完成后可通过点击 show Undistorted 对比校正前后效果。
右上角平均误差推荐在0.5以下时,表明该标定数据可信(本人此次平均误差为0.47 )。
**步骤4:**导出参数,即可把参数进行保存,保存后可退出标定应用,在MATLAB主界面中将保存的Mat文件打开。
**步骤5:**记录、保存数据
上图中,RadialDistortion对应k1,k2,k3,TangentialDistortion对应p1,p2。
IntrinsicMatrix对应相机矩阵,注意具体数值和OpenCV中数据是互为转置的关系。
此次本人测得的数据为:
方法二:C++程序标定 简单粗暴直接上程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 #include <opencv2/imgproc/types_c.h> #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std ; Mat image, img_gray; int BOARDSIZE[2 ]{ 6 ,9 };int main () { vector <vector <Point3f>> objpoints_img; vector <Point3f> obj_world_pts; vector <vector <Point2f>> images_points; vector <Point2f> img_corner_points; vector <String> images_path; string image_path = "/home/titan/Calibration/image/pictures/*.jpg" ; glob(image_path, images_path); for (int i = 0 ; i < BOARDSIZE[1 ]; i++) { for (int j = 0 ; j < BOARDSIZE[0 ]; j++) { obj_world_pts.push_back(Point3f(j, i, 0 )); } } for (int i = 0 ; i < images_path.size(); i++) { image = imread(images_path[i]); cvtColor(image, img_gray, COLOR_BGR2GRAY); bool found_success = findChessboardCorners(img_gray, Size(BOARDSIZE[0 ], BOARDSIZE[1 ]), img_corner_points, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FAST_CHECK | CALIB_CB_NORMALIZE_IMAGE); if (found_success) { TermCriteria criteria (CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 30 , 0.001 ) ; cornerSubPix(img_gray, img_corner_points, Size(11 , 11 ), Size(-1 , -1 ), criteria); drawChessboardCorners(image, Size(BOARDSIZE[0 ], BOARDSIZE[1 ]), img_corner_points, found_success); objpoints_img.push_back(obj_world_pts); images_points.push_back(img_corner_points); } char text[] = "image" ; char *output = text; imshow(output, image); waitKey(200 ); } Mat cameraMatrix, distCoeffs, R, T; calibrateCamera(objpoints_img, images_points, img_gray.size(), cameraMatrix, distCoeffs, R, T); cout << "cameraMatrix:" << endl ; cout << cameraMatrix << endl ; cout << "*****************************" << endl ; cout << "distCoeffs:" << endl ; cout << distCoeffs << endl ; cout << "*****************************" << endl ; cout << "Rotation vector:" << endl ; cout << R << endl ; cout << "*****************************" << endl ; cout << "Translation vector:" << endl ; cout << T << endl ; Mat src, dst; src = imread("/home/titan/Calibration/image/pictures/02.jpg" ); undistort(src, dst, cameraMatrix, distCoeffs); char texts[] = "image_dst" ; char *dst_output = texts; imshow(dst_output, dst); waitKey(100 ); imwrite("/home/titan/Calibration/image/pictures/002.jpg" , dst); destroyAllWindows(); system("pause" ); return 0 ; }
运行上述程序,经过一番图片处理与切换,最终通过终端得到获取相机内参及畸变系数。
五、使用内参 简单粗暴直接上程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 #include <iostream> #include <ctime> #include <opencv2/opencv.hpp> using namespace cv; using namespace std ; int main () { VideoCapture inputVideo (0 ) ; if (!inputVideo.isOpened()){ std ::cout << "video is not opened\n\n" <<endl ; } else { std ::cout << "video is opened \n\n" <<endl ; } Mat frame, frameCalibration; inputVideo >> frame; Mat cameraMatrix = Mat::eye(3 , 3 , CV_64F); cameraMatrix.at<double >(0 ,0 ) = 1982.56844306278 ; cameraMatrix.at<double >(0 ,1 ) = 1.79099355543064 ; cameraMatrix.at<double >(0 ,2 ) = 1042.90384922068 ; cameraMatrix.at<double >(1 ,1 ) = 1983.84445594899 ; cameraMatrix.at<double >(1 ,2 ) = 480.442502729538 ; Mat distCoeffs = Mat::zeros(5 , 1 , CV_64F); distCoeffs.at<double >(0 ,0 ) = -0.515906663211726 ; distCoeffs.at<double >(1 ,0 ) = 0.201811855093355 ; distCoeffs.at<double >(2 ,0 ) = 0.00228453839673728 ; distCoeffs.at<double >(3 ,0 ) = -0.00134697993045861 ; distCoeffs.at<double >(4 ,0 ) = -0.0572379026696125 ; Mat view, rview, map1, map2; Size image_Size; image_Size = frame.size(); initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(), cameraMatrix, image_Size, CV_16SC2, map1, map2); while (1 ){ inputVideo >> frame; if (frame.empty()) break ; remap(frame, frameCalibration, map1, map2, INTER_LINEAR); imshow("Original_image" ,frame); imshow("Calibrated_image" , frameCalibration); char key =waitKey(1 ); if (key == 27 || key == 'q' || key == 'Q' ) break ; } return 0 ; }
测试效果如下:
Ref Opencv 相机内参标定及使用(C++,Matlab)
Python+OpenCV实现相机标定的方法详解_python_脚本之家
双目相机标定+去畸变+获得视差+深度(一次解决所有问题)(python+openCV)_双目相机视差怎么解决-CSDN博客