版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013498583/article/details/71703175
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-e2445db1a8.css">
<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[
64];
-
char fileNames[
64];
-
-
-
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[
100];
-
string *chess_boardList =
new
string[
100];
-
-
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[
64] =
"";
-
// 打开文件读取其中的文件名
-
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 =
0;
-
while (fgets(name,
64, fp) !=
NULL)
-
{
-
char subname[
64];
-
sscanf(name,
"%[^\n]%s", subname);
-
string image_name;
-
stringstream stream;
-
stream << subname;
-
image_name = stream.str();
-
imageList[line] = image_name.substr(
0, image_name.length() -
4);
-
line++;
-
}
-
-
-
//读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
-
cout <<
"开始提取角点………………" <<
endl;
-
int image_count = line;
//图像数量
-
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;
-
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(
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;
-
imageFileName = imageList[i];
-
imageFileName +=
"_corner.jpg";
-
imwrite(chess_boardCorner_path + imageFileName, imageTemp);
-
cout <<
"Frame corner#" << i +
1 <<
"...end" <<
endl;
-
-
imwrite(chess_boardDetect_path + imageFileName, image);
-
chess_boardList[successImageNum] = imageList[i];
-
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(
30,
30);
-
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";
-
-
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),
1, camParam);
-
fwrite(&distortion_coeffs,
sizeof(cv::Vec4d),
1, camParam);
-
fwrite(&image_size,
sizeof(Size),
1, camParam);
-
fclose(camParam);
-
-
//对标定结果进行评价
-
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 < 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(
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 < successImageNum; 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 != successImageNum; i++)
-
{
-
cout <<
"Frame #" << i +
1 <<
"..." <<
endl;
-
Mat newCameraMatrix = Mat(
3,
3, CV_32FC1, Scalar::all(
0));
-
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
0;
-
}
得到两组参数,分别是相机的内参矩阵和畸变系数。保存在camPara.dat供calibration代码校正使用。
校正代码:
-
/************************************************************************
-
运行环境:VS2013+OpenCV 2.4.13
-
运行结果:根据摄像头的畸变信息,进行相机标定
-
*************************************************************************/
-
-
#include <opencv2\opencv.hpp>
-
#include <fstream>
-
#include <iostream>
-
using
namespace
std;
-
using
namespace cv;
-
-
char dir[
64];
-
char test_fileNames[
64];
-
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[
100];
-
-
// 利用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[
64] =
"";
-
// 打开文件读取其中的文件名
-
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 =
0;
-
while (fgets(test_name,
64, fp_test) !=
NULL)
-
{
-
char subname[
64];
-
sscanf(test_name,
"%[^\n]%s", subname);
-
string image_name;
-
stringstream stream;
-
stream << subname;
-
image_name = stream.str();
-
test_imageList[line] = image_name.substr(
0, image_name.length() -
4);
-
line++;
-
}
-
-
string testName;
-
-
//利用摄像机畸变参数对图片进行矫正
-
cout <<
"保存矫正图像" <<
endl;
-
for (
int i =
0; i < line; i++)
-
{
-
cout <<
"Frame #" << i +
1 <<
"..." <<
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),
1, test_camParam);
-
fread(&test_distortion_coeffs,
sizeof(cv::Vec4d),
1, test_camParam);
-
fread(&test_image_size,
sizeof(Size),
1, 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(
3,
3, 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
0;
-
}
校正效果如下:
原图1
原图校正后
原图2
校正后
校正效果基本令人满意。
</div>
</div>