Repository navigation
Expand file tree
/
Copy pathmain.cpp
More file actions
161 lines (134 loc) · 5.29 KB
/
Copy pathmain.cpp
File metadata and controls
161 lines (134 loc) · 5.29 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
#include <opencv2/opencv.hpp>
#include <vector>
#include <iostream>
#include <filesystem> // C++17 标准需开启
using namespace cv;
using namespace std;
namespace fs = std::filesystem;
// 配置参数
const Size chessboardSize(9, 6); // 棋盘格内角点数量(列数-1, 行数-1)
const float squareSize = 2.5f; // 棋盘格实际尺寸(单位:厘米)
const string savePath = "./calib_images/"; // 标定图像保存路径
const int requiredImages = 15; // 需要采集的有效图像数量
const int captureInterval = 1000; // 自动拍摄间隔(毫秒)
// 生成标定板三维坐标
vector<Point3f> generateObjectPoints() {
vector<Point3f> objp;
for (int i = 0; i < chessboardSize.height; i++) {
for (int j = 0; j < chessboardSize.width; j++) {
objp.push_back(Point3f(j * squareSize, i * squareSize, 0));
}
}
return objp;
}
// 实时拍摄标定图像
int captureCalibrationImages() {
// 创建保存目录
if (!fs::exists(savePath)) fs::create_directory(savePath);
VideoCapture cap(0);
if (!cap.isOpened()) {
cerr << "无法打开摄像头!" << endl;
return -1;
}
Mat frame;
int savedCount = 0;
auto lastCaptureTime = chrono::steady_clock::now();
cout << "按 ESC 退出拍摄" << endl;
cout << "请移动标定板至不同角度和距离..." << endl;
while (savedCount < requiredImages) {
cap >> frame;
if (frame.empty()) break;
Mat gray;
cvtColor(frame, gray, COLOR_BGR2GRAY);
vector<Point2f> corners;
bool found = findChessboardCorners(gray, chessboardSize, corners,
CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE);
// 绘制检测状态
string status = "找到棋盘格: " + string(found ? "是" : "否");
putText(frame, status, Point(10,30), FONT_HERSHEY_SIMPLEX, 0.7,
found ? Scalar(0,255,0) : Scalar(0,0,255), 2);
// 自动保存有效图像
auto now = chrono::steady_clock::now();
if (found && chrono::duration_cast<chrono::milliseconds>
(now - lastCaptureTime).count() > captureInterval) {
string filename = savePath + "calib_" + to_string(savedCount) + ".jpg";
imwrite(filename, frame);
savedCount++;
lastCaptureTime = now;
cout << "已保存图像: " << savedCount << "/" << requiredImages << endl;
}
// 显示剩余拍摄数量
string counter = "剩余拍摄: " + to_string(requiredImages - savedCount);
putText(frame, counter, Point(10,70), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(255,255,0), 2);
imshow("实时标定拍摄", frame);
if (waitKey(30) == 27) break; // ESC退出
}
destroyAllWindows();
return savedCount;
}
// 执行标定并保存参数
bool calibrateAndSave() {
vector<vector<Point3f>> objectPoints;
vector<vector<Point2f>> imagePoints;
auto objp = generateObjectPoints();
vector<String> images;
glob(savePath + "*.jpg", images);
if (images.empty()) {
cerr << "未找到标定图像!" << endl;
return false;
}
Size imageSize;
for (const auto& imgPath : images) {
Mat img = imread(imgPath);
imageSize = img.size();
Mat gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
vector<Point2f> corners;
bool found = findChessboardCorners(gray, chessboardSize, corners);
if (found) {
cornerSubPix(gray, corners, Size(11,11), Size(-1,-1),
TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1));
imagePoints.push_back(corners);
objectPoints.push_back(objp);
}
}
if (imagePoints.size() < 5) {
cerr << "有效图像不足,至少需要5张!" << endl;
return false;
}
Mat cameraMatrix, distCoeffs;
vector<Mat> rvecs, tvecs;
double rms = calibrateCamera(objectPoints, imagePoints, imageSize,
cameraMatrix, distCoeffs, rvecs, tvecs);
cout << "标定完成,重投影误差: " << rms << endl;
FileStorage fs("camera_calib.yml", FileStorage::WRITE);
fs << "camera_matrix" << cameraMatrix;
fs << "distortion_coefficients" << distCoeffs;
fs.release();
return true;
}
int main() {
int captured = captureCalibrationImages();
if (captured >= 5) { // 至少需要5张有效图像
if (calibrateAndSave()) {
cout << "标定参数已保存至 camera_calib.yml" << endl;
// 实时测试校正效果
VideoCapture cap(0);
Mat frame, undistorted;
FileStorage fs("camera_calib.yml", FileStorage::READ);
Mat cameraMatrix, distCoeffs;
fs["camera_matrix"] >> cameraMatrix;
fs["distortion_coefficients"] >> distCoeffs;
fs.release();
while (cap.read(frame)) {
undistort(frame, undistorted, cameraMatrix, distCoeffs);
hconcat(frame, undistorted, frame);
imshow("校正前 vs 校正后", frame);
if (waitKey(10) == 27) break;
}
}
} else {
cerr << "标定失败:采集的有效图像不足!" << endl;
}
return 0;
}