版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013498583/article/details/71703175
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-e2445db1a8.css" target="_blank" rel="external nofollow" >
<div class="htmledit_views">
海尔630冰箱的标定和畸变校正。上篇文章中直接使用OpenCV的例程进行畸变校正的效果不太理想。使用以下方法(张正友)效果更好。
京东链接:
http://item.jd.com/4027713.html#crumb-wrap
标定代码:
- /************************************************************************
- 运行环境:VS2013+OpenCV 2.4.13
- 运行结果:检测拍摄的棋盘畸变图像,获取摄像头的畸变信息
- *************************************************************************/
- #include <opencv2\opencv.hpp>
- #include <fstream>
- #include <iostream>
- using namespace std;
- using namespace cv;
- char dir[ ];
- char fileNames[ ];
- char chess_boardImage_path[] = "E:\\hanxiaoxuan\\distort\\";
- char chess_boardDetect_path[] = "E:\\hanxiaoxuan\\distort_detect\\";
- char chess_boardCorner_path[] = "E:\\hanxiaoxuan\\distort_corner\\";
- char calibrationResult[] = "E:\\hanxiaoxuan\\calibration_result.txt";
- char datFileName[] = "E:\\hanxiaoxuan\\camParam.dat";
- int main()
- {
- string *imageList = new string[ ];
- string *chess_boardList = new string[ ];
- ofstream fout(calibrationResult); //保存标定结果的文件
- // 利用dir命令将当前目录下的.jpg文件名写入names.txt
- sprintf(dir, "%s%s%s%s%s%s", "dir ", chess_boardImage_path, "*.jpg", " /a /b >", chess_boardImage_path, "names.txt");
- system(dir);
- char name[ ] = "";
- // 打开文件读取其中的文件名
- sprintf(fileNames, "%s%s", chess_boardImage_path, "names.txt");
- FILE* fp = fopen(fileNames, "r");
- if ( NULL == fp)
- printf( "error,cannot open the name list");
- // 获得文件数量
- int line = ;
- while (fgets(name, , fp) != NULL)
- {
- char subname[ ];
- sscanf(name, "%[^\n]%s", subname);
- string image_name;
- stringstream stream;
- stream << subname;
- image_name = stream.str();
- imageList[line] = image_name.substr( , image_name.length() - );
- line++;
- }
- //读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
- cout << "开始提取角点………………" << endl;
- int image_count = line; //图像数量
- Size board_size = Size( , ); //棋盘上每行、列的内角点数
- vector<Point2f> corners; //缓存每幅图像上检测到的角点
- vector< vector<Point2f>> corners_Seq; //保存检测到的所有角点
- vector<Mat> image_Seq;
- int successImageNum = ; //成功提取角点的棋盘图数量
- int count = ;
- for ( int i = ; i != image_count; i++)
- {
- cout << "Frame #" << i + << "..." << endl;
- string imageFileName;
- imageFileName = imageList[i]; //图像的文件名
- imageFileName += ".jpg"; //图像的文件名.jpg
- cv::Mat image = imread(chess_boardImage_path + imageFileName);
- //提取角点
- cv::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 << "can not find chessboard corners!\n";
- continue;
- exit( );
- }
- else
- {
- //亚像素精确化
- cornerSubPix(imageGray, corners, Size( , ), Size( , ), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, , ));
- //绘制检测到的角点并保存
- Mat imageTemp = image.clone();
- for ( int j = ; j < corners.size(); j++)
- {
- circle(imageTemp, corners[j], , Scalar( , , ), , , );
- }
- string imageFileName;
- imageFileName = imageList[i];
- imageFileName += "_corner.jpg";
- imwrite(chess_boardCorner_path + imageFileName, imageTemp);
- cout << "Frame corner#" << i + << "...end" << endl;
- imwrite(chess_boardDetect_path + imageFileName, image);
- chess_boardList[successImageNum] = imageList[i];
- count = count + corners.size();
- successImageNum = successImageNum + ;
- corners_Seq.push_back(corners);
- }
- image_Seq.push_back(image);
- }
- cout << "角点提取完成!\n";
- //摄像机标定
- cout << "开始标定………………" << endl;
- Size square_size = Size( , );
- vector< vector<Point3f>> object_Points; //保存标定板上角点的三维坐标
- Mat image_points = Mat( , count, CV_32FC2, Scalar::all( )); //保存提取的所有角点
- vector< int> point_counts;
- //初始化标定板上角点的三维坐标
- for ( int t = ; t < successImageNum; t++)
- {
- vector<Point3f> tempPointSet;
- for ( int i = ; i < board_size.height; i++)
- {
- for ( int j = ; j < board_size.width; j++)
- {
- //假设标定板放在世界坐标系中z=0的平面上
- Point3f tempPoint;
- tempPoint.x = i*square_size.width;
- tempPoint.y = j*square_size.height;
- tempPoint.z = ;
- tempPointSet.push_back(tempPoint);
- }
- }
- object_Points.push_back(tempPointSet);
- }
- for ( int i = ; i < successImageNum; i++)
- {
- point_counts.push_back(board_size.width*board_size.height);
- }
- //开始标定
- Size image_size = image_Seq[ ].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 = ;
- 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( , , ));
- cout << "标定完成!\n";
- FILE *camParam = fopen(datFileName, "wb");
- if (camParam == NULL) {
- std:: cout << "can not create data file: " << datFileName << " !!!" << std:: endl;
- return false;
- }
- fwrite(&intrinsic_matrix, sizeof(cv::Matx33d), , camParam);
- fwrite(&distortion_coeffs, sizeof(cv::Vec4d), , camParam);
- fwrite(&image_size, sizeof(Size), , camParam);
- fclose(camParam);
- //对标定结果进行评价
- cout << "开始评价标定结果………………" << endl;
- double total_err = ; //所有图像的平均误差的总和
- double err = ; //每幅图像的平均误差
- vector<Point2f> image_points2; //保存重新计算得到的投影点
- cout << "每幅图像的标定误差:" << endl;
- cout << "每幅图像的标定误差:" << endl << endl;
- for ( int i = ; i < successImageNum; 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( , tempImagePoint.size(), CV_32FC2);
- Mat image_points2Mat = Mat( , image_points2.size(), CV_32FC2);
- for ( size_t i = ; i != tempImagePoint.size(); i++)
- {
- image_points2Mat.at<Vec2f>( , i) = Vec2f(image_points2[i].x, image_points2[i].y);
- tempImagePointMat.at<Vec2f>( , i) = Vec2f(tempImagePoint[i].x, tempImagePoint[i].y);
- }
- err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
- total_err += err /= point_counts[i];
- cout << "第" << i + << "幅图像的平均误差:" << err << "像素" << endl;
- fout << "第" << i + << "幅图像的平均误差:" << err << "像素" << endl;
- }
- cout << "总体平均误差:" << total_err / image_count << "像素" << endl;
- fout << "总体平均误差:" << total_err / image_count << "像素" << endl << endl;
- cout << "评价完成!" << endl;
- //保存标定结果
- cout << "开始保存标定结果………………" << endl;
- Mat rotation_matrix = Mat( , , CV_32FC1, Scalar::all( )); //保存每幅图像的旋转矩阵
- fout << "相机内参数矩阵:" << endl;
- fout << intrinsic_matrix << endl;
- fout << "畸变系数:\n";
- fout << distortion_coeffs << endl;
- for ( int i = ; i < successImageNum; i++)
- {
- fout << "第" << i + << "幅图像的旋转向量:" << endl;
- fout << rotation_vectors[i] << endl;
- //将旋转向量转换为相对应的旋转矩阵
- Rodrigues(rotation_vectors[i], rotation_matrix);
- fout << "第" << i + << "幅图像的旋转矩阵:" << endl;
- fout << rotation_matrix << endl;
- fout << "第" << i + << "幅图像的平移向量:" << 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( , , CV_32F);
- cout << "保存矫正图像" << endl;
- for ( int i = ; i != successImageNum; i++)
- {
- cout << "Frame #" << i + << "..." << endl;
- Mat newCameraMatrix = Mat( , , CV_32FC1, Scalar::all( ));
- fisheye::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;
- imageFileName = chess_boardList[i];
- imageFileName += "_d.jpg";
- imwrite(chess_boardCorner_path + imageFileName, t);
- }
- cout << "保存结束" << endl;
- delete [] imageList;
- delete [] chess_boardList;
- return ;
- }
得到两组参数,分别是相机的内参矩阵和畸变系数。保存在camPara.dat供calibration代码校正使用。
校正代码:
- /************************************************************************
- 运行环境:VS2013+OpenCV 2.4.13
- 运行结果:根据摄像头的畸变信息,进行相机标定
- *************************************************************************/
- #include <opencv2\opencv.hpp>
- #include <fstream>
- #include <iostream>
- using namespace std;
- using namespace cv;
- char dir[ ];
- char test_fileNames[ ];
- char testFile_path[] = "E:\\hanxiaoxuan\\distort\\";
- char outputFile_path[] = "E:\\hanxiaoxuan\\undistort\\";
- char test_datFileName[] = "E:\\hanxiaoxuan\\camParam.dat";
- //string test_imageList[100];
- int main()
- {
- string *test_imageList = new string[ ];
- // 利用dir命令将当前目录下的.jpg文件名写入test_names.txt
- sprintf(dir, "%s%s%s%s%s%s", "dir ", testFile_path, "*.jpg", " /a /b >", testFile_path, "test_names.txt");
- system(dir);
- char test_name[ ] = "";
- // 打开文件读取其中的文件名
- sprintf(test_fileNames, "%s%s", testFile_path, "test_names.txt");
- FILE* fp_test = fopen(test_fileNames, "r");
- if ( NULL == fp_test)
- printf( "error,cannot open the name list");
- // 获得文件数量
- int line = ;
- while (fgets(test_name, , fp_test) != NULL)
- {
- char subname[ ];
- sscanf(test_name, "%[^\n]%s", subname);
- string image_name;
- stringstream stream;
- stream << subname;
- image_name = stream.str();
- test_imageList[line] = image_name.substr( , image_name.length() - );
- line++;
- }
- string testName;
- //利用摄像机畸变参数对图片进行矫正
- cout << "保存矫正图像" << endl;
- for ( int i = ; i < line; i++)
- {
- cout << "Frame #" << i + << "..." << endl;
- testName = test_imageList[i] + ".jpg";
- Mat testImage = imread(testFile_path + testName);
- cv::Matx33d test_intrinsic_matrix;
- cv::Vec4d test_distortion_coeffs;
- Size test_image_size = testImage.size();
- FILE *test_camParam = fopen(test_datFileName, "rb");
- if (test_camParam == NULL) {
- std:: cout << "can not create data file: " << test_datFileName << " !!!" << std:: endl;
- return false;
- }
- fread(&test_intrinsic_matrix, sizeof(cv::Matx33d), , test_camParam);
- fread(&test_distortion_coeffs, sizeof(cv::Vec4d), , test_camParam);
- fread(&test_image_size, sizeof(Size), , test_camParam);
- fclose(test_camParam);
- Mat test_mapx = Mat(test_image_size, CV_32FC1);
- Mat test_mapy = Mat(test_image_size, CV_32FC1);
- Mat test_R = Mat::eye( , , CV_32F);
- fisheye::initUndistortRectifyMap(test_intrinsic_matrix, test_distortion_coeffs, test_R, test_intrinsic_matrix, test_image_size, CV_32FC1, test_mapx, test_mapy);
- Mat t = testImage.clone();
- cv::remap(testImage, t, test_mapx, test_mapy, INTER_LINEAR);
- imwrite(outputFile_path + testName, t);
- }
- cout << "标定结束" << endl;
- delete [] test_imageList;
- return ;
- }
校正效果如下:
原图1
原图校正后
原图2
校正后
校正效果基本令人满意。
</div>
</div>