This repository has been archived by the owner on Jun 25, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Calibration.cpp
177 lines (153 loc) · 5.09 KB
/
Calibration.cpp
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
#include "Calibration.h"
Calibration::Calibration()
{
}
Calibration::~Calibration()
{
}
void Calibration::initCalibration(int x_dims, int y_dims, float square_size, int target_type, cv::Size image_size, string calib_name, int min_req_samples)
{
this->target_type = target_type;
this->image_size = image_size;
this->calib_name = calib_name;
this->min_req_samples = min_req_samples;
tg_x = x_dims;
tg_y = y_dims;
tg_n = x_dims * y_dims;
tg_square_size = square_size;
samples = 0;
calibration_initialised = true;
calibration_completed = false;
}
bool Calibration::addCalibrationImage(cv::Mat image)
{
bool ret_bool = false;
cv::Mat image_in = image;
cv::Mat image_gray;
// Vector of 2d corner coords
vector<cv::Point2f> corners;
cv::Size tg_size = cv::Size(tg_x, tg_y);
// Check calibration is in progress & image is correct size
cv::Size input_size = image_in.size();
if ((!calibration_initialised)||(input_size.width != this->image_size.width)||(input_size.height != this->image_size.height))
return false;
// Use grayscale image for finding chessboard corners
cvtColor(image_in, image_gray, CV_BGR2GRAY);
bool found_corners = false;
if (target_type == TARGET_CHESSBOARD)
{
found_corners = findChessboardCorners(image_gray, tg_size, corners,
CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_NORMALIZE_IMAGE | CV_CALIB_CB_FAST_CHECK);
}
else if (target_type == TARGET_CIRCLES)
{
found_corners = findCirclesGrid(image_gray, tg_size, corners,
cv::CALIB_CB_SYMMETRIC_GRID);
}
if (found_corners)
{
// For further accuracy, parameters taken from OPENCV calibration docs
cornerSubPix(image_gray, corners, cv::Size(11, 11), cv::Size(-1, -1),
cvTermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 30, 0.01));
// Doesn't check for square chessboards. Add in later?
// Draw located corners on image
drawChessboardCorners(image_in, tg_size, corners, true);
// Add the corner points to the calibration points array
image_points_vec.push_back(corners);
// Save the image for calibration
//string filename = "calib_image_";
//filename = filename + to_string(samples) + ".png";
//imwrite(filename, image_in);
// Increment the number of calibration samples
samples++;
ret_bool = true;
}
return ret_bool;
}
bool Calibration::performCalibration()
{
bool ret_bool = false;
cv::Mat camera_matrix;
cv::Mat dist_coeffs;
vector<cv::Mat> rot_mats;
vector<cv::Mat> trans_mats;
if (calibration_initialised && (!calibration_completed) && (samples >= min_req_samples))
{
// Compile vector of chessboard positions for each sample
// (the top level elements should all be identical if same board used)
tg_points_vec.resize(samples, vector<cv::Point3f>(tg_n));
if (target_type != TARGET_ASYMMETRIC_CIRCLES)
{
for (int i = 0; i < samples; i++)
{
for (int j = 0; j < tg_y; j++)
{
for (int k = 0; k < tg_x; k++)
{
tg_points_vec[i][j*tg_x + k] = cv::Point3f(k * tg_square_size, j * tg_square_size, 0);
}
}
}
}
else
{
for (int i = 0; i < samples; i++)
{
bool odd = false;
float ofset = 0.0;
for (int j = 0; j < tg_y; j++)
{
for (int k = 0; k < tg_x; k++)
{
if (odd)
ofset = tg_square_size / 2.0;
else
ofset = 0.0;
tg_points_vec[i][j*tg_x + k] = cv::Point3f((k * tg_square_size) + ofset, j * (tg_square_size / 2), 0);
}
odd = !odd;
}
}
}
// Calibrate the camera:
// INPUTS: tg_points - vector of vector of chessboard corner positions
// image_points_vec - vector of vector of chessboard corner position
// found in samples
// image_size - the size of the image samples
// flags - no clue whatsoever which to chose, so none atm.
// Term - the terms for finishing the optimisation. Again, no clue
// guessed at 100 iterations or change < 0.001
// OUTPUTS:camera_matrix - matrix of the camera intrinsics
// dist_coeffs - matrix of distortion coefficients
// rot_mats - vector of rotation matrices
// trans_mats - vector of translation matrices
int flags = CV_CALIB_ZERO_TANGENT_DIST;
calibrateCamera(tg_points_vec, image_points_vec, image_size,
camera_matrix, dist_coeffs,
rot_mats, trans_mats, flags,
cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 100, 0.001));
// empty matrix R defaults to identity transform. DON'T use a matrix of 0's
cv::Mat R;
cv::Mat new_cam_mat = getOptimalNewCameraMatrix(camera_matrix, dist_coeffs, image_size, 1, image_size);
// Create the maps for undistortion. Used in remap_image()
initUndistortRectifyMap(camera_matrix, dist_coeffs, R, new_cam_mat, image_size, CV_32FC1, map1, map2);
calibration_initialised = false;
calibration_completed = true;
ret_bool = true;
}
else
ret_bool = false;
return ret_bool;
}
cv::Mat Calibration::remapImage(cv::Mat input_image)
{
cv::Mat output_image;
// If a calibration has been completed, use it to remap an image.
if (calibration_completed)
{
remap(input_image, output_image, map1, map2, cv::INTER_LINEAR);
}
else
output_image = input_image;
return output_image;
}