-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCalibration_Undistort.cpp
More file actions
268 lines (241 loc) · 9.1 KB
/
Calibration_Undistort.cpp
File metadata and controls
268 lines (241 loc) · 9.1 KB
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
#include<bits/stdc++.h>
#include<opencv.hpp>
#include<calib3d/calib3d_c.h>
#include<imgproc/types_c.h>
#include<io.h>
#include<direct.h>
using namespace std;
using namespace cv;
/*
获取某个目录下制定文件类型的文件
将数组FileNames中原有元素清空
将所有符合要求的文件放置到FileNames数组中
*/
void GetFile(string& Path, string& Type, vector<string>& FileNames) {
struct _finddata_t FileInfo;//查询到的文件信息
intptr_t lfile = 0;//查询到的long类型文件句柄
string sfile_r;//搜索文件时用到的正则表达式
lfile = _findfirst(sfile_r.assign(Path).append("\\*").append(Type).c_str(), &FileInfo);
if (lfile != -1L) {//查找存在符合要求的文件
do {
if (FileInfo.attrib != _A_SUBDIR) {//如果不是文件夹
FileNames.push_back(sfile_r.assign(Path).append("\\").append(FileInfo.name));
}
} while (_findnext(lfile, &FileInfo) == 0);
}
else {//未查到符合要求的文件, 提示后退出
_findclose(lfile);
cout << "No such type files!" << endl;
exit(0);
}
return;
}
/*
根据一组图片标定相机
要求输入图片的角点信息一致、像素尺寸一致
*/
void MyCalibration(
vector<string>& FilesName,//文件名
Size corner_size,//角点矩阵尺寸
Size square_size,//角点矩形尺寸
Mat& cameraMatrix,
Mat& distCoeffs,
vector<Mat>& rvecsMat,
vector<Mat>& tvecsMat,
Size& SizeImage
)
{
ofstream fout("标定结果.txt");
cout << "==================提取角点=============================================" << endl;
int image_count = 0;
Size image_size;//图像大小
vector<Point2f> image_corner;
vector<vector<Point2f> > image_corners;
for (int i = 0; i < FilesName.size(); ++i) {
++image_count;
cout << "提取第 " << i + 1 << " 幅图像角点" << endl;
cout << FilesName.at(i) << endl;
Mat imageInput = imread(FilesName.at(i));//读取第i+1幅图像
if (image_count == 1) {//获取图像像素矩阵尺寸
image_size.width = imageInput.cols;
image_size.height = imageInput.rows;
SizeImage = Size(imageInput.cols, imageInput.rows);
}
bool ok = findChessboardCorners(imageInput, corner_size, image_corner, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_NORMALIZE_IMAGE);
string cornersfind("cornersfind");
if (!ok) {
cout << " 第 " << i+1 << " 张照片提取角点失败,请删除后,重新标定!" << endl; //找不到角点
imshow("失败照片", imageInput);
waitKey(1000);
destroyWindow("失败照片");
}
else {
Mat View_gray;
//cout << " 第 " << i + 1 << " 张照片是 " << imageInput.channels() << " 位图" << endl;
cvtColor(imageInput, View_gray, CV_RGB2GRAY);//如果输入是RGB图像,则输出为灰度图
/*亚像素精细化*/
cornerSubPix(View_gray, image_corner, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 20, 0.01));
image_corners.push_back(image_corner);
/*在图像上显示角点的位置*/
drawChessboardCorners(View_gray, corner_size, image_corner, true);
//显示找到的角点
cout << " 保存显示找到的角点" << endl;
//保存找到角点后的图片
string filename(cornersfind);
stringstream ss;
string s;
ss << i + 1;
ss >> s;
filename.append("\\"+cornersfind);
filename.append(s);
filename.append(".jpg");
imwrite(filename.c_str(), View_gray);
ss.clear();
s.clear();
}
}
cout << "==================提取角点完成=========================================" << endl << endl << endl;
/*三维棋盘信息*/
vector<vector<Point3f> > object_points_seq;
for (int t = 0; t < image_count; ++t) {
vector<Point3f> object_points;
for (int i = 0; i < corner_size.height; ++i) {
for (int j = 0; j < corner_size.width; ++j) {
Point3f realpoint;
/*假设标定板放在世界坐标系中z=0的平面上*/
realpoint.x = i * square_size.width;
realpoint.y = j * square_size.height;
realpoint.z = 0;
object_points.push_back(realpoint);
}
}
object_points_seq.push_back(object_points);
}
/*运行标定函数*/
cout << "==================相机标定=============================================" << endl;
double err_first = calibrateCamera(
object_points_seq,
image_corners,
image_size,
cameraMatrix,
distCoeffs,
rvecsMat,
tvecsMat,
CV_CALIB_FIX_K3
);
fout << "重投影误差1:" << err_first << "像素" << endl << endl;
cout << "==================标定完成=============================================" << endl << endl << endl;
cout << "==================评价标定结果==========================================" << endl;
double total_err = 0.0;//所有图像的平均误差的总和
double err = 0.0;//每幅图像的平均误差
double totalErr = 0.0;
double totalPoints = 0.0;
vector<Point2f> image_points_pro;//保存重新计算得到的投影点
for (int i = 0; i < image_count; ++i) {
projectPoints(
object_points_seq.at(i),
rvecsMat.at(i),
tvecsMat.at(i),
cameraMatrix,
distCoeffs,
image_points_pro
);
err = norm(Mat(image_corners.at(i)), Mat(image_points_pro), NORM_L2);
totalErr += err * err;
totalPoints += object_points_seq.at(i).size();
err /= object_points_seq.at(i).size();
fout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
total_err += err;
}
fout << "重投影误差2:" << sqrt(totalErr / totalPoints) << "像素" << endl << endl;
fout << "重投影误差3:" << total_err / image_count << "像素" << endl << endl;
cout << "==================评价标定结果完成======================================" << endl << endl << endl;
cout << "==================保存标定结果==========================================" << endl;
Mat rotation_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0));/*保存每幅图像的旋转矩阵*/
fout << "相机内参数矩阵:" << endl;
fout << cameraMatrix << endl << endl;
fout << "畸变系数:" << endl;
fout << distCoeffs << endl << endl << endl;
for (int i = 0; i < image_count; ++i) {
fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
fout << rvecsMat.at(i) << endl;
/* 将旋转向量转换为相对应的旋转矩阵 */
Rodrigues(rvecsMat.at(i), rotation_matrix);
fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
fout << rotation_matrix << endl;
fout << "第" << i + 1 << "幅图像的平移向量:" << endl;
fout << tvecsMat.at(i) << endl << endl;
}
cout << "==================保存标定结果完成======================================" << endl << endl << endl;
fout.close();
return;
}
//根据标定相机的结果校正图片
void MyUndistort(
vector<string>& FilesName,
Size image_size,
Mat& cameraMatrix,
Mat& distCoeffs
)
{
Mat mapx = Mat(image_size, CV_32FC1);//X坐标重映射参数
Mat mapy = Mat(image_size, CV_32FC1);//Y坐标重映射参数
Mat R = Mat::eye(3, 3, CV_32F);
cout << "==================保存矫正图像==========================================" << endl;
string imageFileName; //校正后图像的保存路径
stringstream ss;
string s;
string filename("undistorted");
for (int i = 0; i < FilesName.size(); ++i) {
Mat imageSource = imread(FilesName[i]);
Mat newimage = imageSource.clone();
//方法一:使用initUndistortRectifyMap和remap两个函数配合实现
/*initUndistortRectifyMap(cameraMatrix,distCoeffs,R, Mat(),image_size,CV_32FC1,mapx,mapy);
remap(imageSource,newimage,mapx, mapy, INTER_LINEAR);*/
//方法二:不需要转换矩阵的方式,使用undistort函数实现
undistort(imageSource, newimage, cameraMatrix, distCoeffs);
ss << i + 1;
ss >> s;
filename.append("\\" + filename);
filename.append(s);
filename.append(".jpg");
cout << filename << endl;
imwrite(filename.c_str(), newimage);
ss.clear();
s.clear();
filename.clear();
filename.assign("undistorted");
}
cout << "==================保存结束==============================================" << endl << endl << endl;
return;
}
int main(void)
{
/*=====================文件获取========================================================*/
string Image_Directory("exp1");
string Image_Type(".jpg");
vector<string> ImageNames;
//获取文件
GetFile(Image_Directory, Image_Type, ImageNames);
/*=====================相机标定========================================================*/
Size image_Size;
Size board_size = Size(9, 6);//标定板上每行、列的角点数
Size square_size = Size(30, 30);//实际测量得到的标定板上每个棋盘格的物理尺寸,单位mm
Mat cameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));//摄像机内参数矩阵
Mat distCoeffs = Mat(1, 5, CV_32FC1, Scalar::all(0));//摄像机的5个畸变系数:k1,k2,p1,p2,k3
vector<Mat> rvecsMat;//存放所有图像的旋转向量,每一副图像的旋转向量为一个mat
vector<Mat> tvecsMat;// 存放所有图像的平移向量,每一副图像的平移向量为一个mat
MyCalibration(
ImageNames,
board_size,
square_size,
cameraMatrix,
distCoeffs,
rvecsMat,
tvecsMat,
image_Size
);
/*=====================图像校正========================================================*/
MyUndistort(ImageNames, image_Size, cameraMatrix, distCoeffs);
return 0;
}