Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/apps/interactive-calibration/calibController.cpp
16337 views
1
// This file is part of OpenCV project.
2
// It is subject to the license terms in the LICENSE file found in the top-level directory
3
// of this distribution and at http://opencv.org/license.html.
4
5
#include "calibController.hpp"
6
7
#include <algorithm>
8
#include <cmath>
9
#include <ctime>
10
11
#include <opencv2/calib3d.hpp>
12
#include <opencv2/imgproc.hpp>
13
14
double calib::calibController::estimateCoverageQuality()
15
{
16
int gridSize = 10;
17
int xGridStep = mCalibData->imageSize.width / gridSize;
18
int yGridStep = mCalibData->imageSize.height / gridSize;
19
std::vector<int> pointsInCell(gridSize*gridSize);
20
21
std::fill(pointsInCell.begin(), pointsInCell.end(), 0);
22
23
for(std::vector<std::vector<cv::Point2f> >::iterator it = mCalibData->imagePoints.begin(); it != mCalibData->imagePoints.end(); ++it)
24
for(std::vector<cv::Point2f>::iterator pointIt = (*it).begin(); pointIt != (*it).end(); ++pointIt) {
25
int i = (int)((*pointIt).x / xGridStep);
26
int j = (int)((*pointIt).y / yGridStep);
27
pointsInCell[i*gridSize + j]++;
28
}
29
30
for(std::vector<cv::Mat>::iterator it = mCalibData->allCharucoCorners.begin(); it != mCalibData->allCharucoCorners.end(); ++it)
31
for(int l = 0; l < (*it).size[0]; l++) {
32
int i = (int)((*it).at<float>(l, 0) / xGridStep);
33
int j = (int)((*it).at<float>(l, 1) / yGridStep);
34
pointsInCell[i*gridSize + j]++;
35
}
36
37
cv::Mat mean, stdDev;
38
cv::meanStdDev(pointsInCell, mean, stdDev);
39
40
return mean.at<double>(0) / (stdDev.at<double>(0) + 1e-7);
41
}
42
43
calib::calibController::calibController()
44
{
45
mCalibFlags = 0;
46
}
47
48
calib::calibController::calibController(cv::Ptr<calib::calibrationData> data, int initialFlags, bool autoTuning, int minFramesNum) :
49
mCalibData(data)
50
{
51
mCalibFlags = initialFlags;
52
mNeedTuning = autoTuning;
53
mMinFramesNum = minFramesNum;
54
mConfIntervalsState = false;
55
mCoverageQualityState = false;
56
}
57
58
void calib::calibController::updateState()
59
{
60
if(mCalibData->cameraMatrix.total()) {
61
const double relErrEps = 0.05;
62
bool fConfState = false, cConfState = false, dConfState = true;
63
if(sigmaMult*mCalibData->stdDeviations.at<double>(0) / mCalibData->cameraMatrix.at<double>(0,0) < relErrEps &&
64
sigmaMult*mCalibData->stdDeviations.at<double>(1) / mCalibData->cameraMatrix.at<double>(1,1) < relErrEps)
65
fConfState = true;
66
if(sigmaMult*mCalibData->stdDeviations.at<double>(2) / mCalibData->cameraMatrix.at<double>(0,2) < relErrEps &&
67
sigmaMult*mCalibData->stdDeviations.at<double>(3) / mCalibData->cameraMatrix.at<double>(1,2) < relErrEps)
68
cConfState = true;
69
70
for(int i = 0; i < 5; i++)
71
if(mCalibData->stdDeviations.at<double>(4+i) / fabs(mCalibData->distCoeffs.at<double>(i)) > 1)
72
dConfState = false;
73
74
mConfIntervalsState = fConfState && cConfState && dConfState;
75
}
76
77
if(getFramesNumberState())
78
mCoverageQualityState = estimateCoverageQuality() > 1.8 ? true : false;
79
80
if (getFramesNumberState() && mNeedTuning) {
81
if( !(mCalibFlags & cv::CALIB_FIX_ASPECT_RATIO) &&
82
mCalibData->cameraMatrix.total()) {
83
double fDiff = fabs(mCalibData->cameraMatrix.at<double>(0,0) -
84
mCalibData->cameraMatrix.at<double>(1,1));
85
86
if (fDiff < 3*mCalibData->stdDeviations.at<double>(0) &&
87
fDiff < 3*mCalibData->stdDeviations.at<double>(1)) {
88
mCalibFlags |= cv::CALIB_FIX_ASPECT_RATIO;
89
mCalibData->cameraMatrix.at<double>(0,0) =
90
mCalibData->cameraMatrix.at<double>(1,1);
91
}
92
}
93
94
if(!(mCalibFlags & cv::CALIB_ZERO_TANGENT_DIST)) {
95
const double eps = 0.005;
96
if(fabs(mCalibData->distCoeffs.at<double>(2)) < eps &&
97
fabs(mCalibData->distCoeffs.at<double>(3)) < eps)
98
mCalibFlags |= cv::CALIB_ZERO_TANGENT_DIST;
99
}
100
101
if(!(mCalibFlags & cv::CALIB_FIX_K1)) {
102
const double eps = 0.005;
103
if(fabs(mCalibData->distCoeffs.at<double>(0)) < eps)
104
mCalibFlags |= cv::CALIB_FIX_K1;
105
}
106
107
if(!(mCalibFlags & cv::CALIB_FIX_K2)) {
108
const double eps = 0.005;
109
if(fabs(mCalibData->distCoeffs.at<double>(1)) < eps)
110
mCalibFlags |= cv::CALIB_FIX_K2;
111
}
112
113
if(!(mCalibFlags & cv::CALIB_FIX_K3)) {
114
const double eps = 0.005;
115
if(fabs(mCalibData->distCoeffs.at<double>(4)) < eps)
116
mCalibFlags |= cv::CALIB_FIX_K3;
117
}
118
119
}
120
}
121
122
bool calib::calibController::getCommonCalibrationState() const
123
{
124
int rating = (int)getFramesNumberState() + (int)getConfidenceIntrervalsState() +
125
(int)getRMSState() + (int)mCoverageQualityState;
126
return rating == 4;
127
}
128
129
bool calib::calibController::getFramesNumberState() const
130
{
131
return std::max(mCalibData->imagePoints.size(), mCalibData->allCharucoCorners.size()) > mMinFramesNum;
132
}
133
134
bool calib::calibController::getConfidenceIntrervalsState() const
135
{
136
return mConfIntervalsState;
137
}
138
139
bool calib::calibController::getRMSState() const
140
{
141
return mCalibData->totalAvgErr < 0.5;
142
}
143
144
int calib::calibController::getNewFlags() const
145
{
146
return mCalibFlags;
147
}
148
149
150
//////////////////// calibDataController
151
152
double calib::calibDataController::estimateGridSubsetQuality(size_t excludedIndex)
153
{
154
{
155
int gridSize = 10;
156
int xGridStep = mCalibData->imageSize.width / gridSize;
157
int yGridStep = mCalibData->imageSize.height / gridSize;
158
std::vector<int> pointsInCell(gridSize*gridSize);
159
160
std::fill(pointsInCell.begin(), pointsInCell.end(), 0);
161
162
for(size_t k = 0; k < mCalibData->imagePoints.size(); k++)
163
if(k != excludedIndex)
164
for(std::vector<cv::Point2f>::iterator pointIt = mCalibData->imagePoints[k].begin(); pointIt != mCalibData->imagePoints[k].end(); ++pointIt) {
165
int i = (int)((*pointIt).x / xGridStep);
166
int j = (int)((*pointIt).y / yGridStep);
167
pointsInCell[i*gridSize + j]++;
168
}
169
170
for(size_t k = 0; k < mCalibData->allCharucoCorners.size(); k++)
171
if(k != excludedIndex)
172
for(int l = 0; l < mCalibData->allCharucoCorners[k].size[0]; l++) {
173
int i = (int)(mCalibData->allCharucoCorners[k].at<float>(l, 0) / xGridStep);
174
int j = (int)(mCalibData->allCharucoCorners[k].at<float>(l, 1) / yGridStep);
175
pointsInCell[i*gridSize + j]++;
176
}
177
178
cv::Mat mean, stdDev;
179
cv::meanStdDev(pointsInCell, mean, stdDev);
180
181
return mean.at<double>(0) / (stdDev.at<double>(0) + 1e-7);
182
}
183
}
184
185
calib::calibDataController::calibDataController(cv::Ptr<calib::calibrationData> data, int maxFrames, double convParameter) :
186
mCalibData(data), mParamsFileName("CamParams.xml")
187
{
188
mMaxFramesNum = maxFrames;
189
mAlpha = convParameter;
190
}
191
192
calib::calibDataController::calibDataController()
193
{
194
195
}
196
197
void calib::calibDataController::filterFrames()
198
{
199
size_t numberOfFrames = std::max(mCalibData->allCharucoIds.size(), mCalibData->imagePoints.size());
200
CV_Assert(numberOfFrames == mCalibData->perViewErrors.total());
201
if(numberOfFrames >= mMaxFramesNum) {
202
203
double worstValue = -HUGE_VAL, maxQuality = estimateGridSubsetQuality(numberOfFrames);
204
size_t worstElemIndex = 0;
205
for(size_t i = 0; i < numberOfFrames; i++) {
206
double gridQDelta = estimateGridSubsetQuality(i) - maxQuality;
207
double currentValue = mCalibData->perViewErrors.at<double>((int)i)*mAlpha + gridQDelta*(1. - mAlpha);
208
if(currentValue > worstValue) {
209
worstValue = currentValue;
210
worstElemIndex = i;
211
}
212
}
213
showOverlayMessage(cv::format("Frame %zu is worst", worstElemIndex + 1));
214
215
if(mCalibData->imagePoints.size()) {
216
mCalibData->imagePoints.erase(mCalibData->imagePoints.begin() + worstElemIndex);
217
mCalibData->objectPoints.erase(mCalibData->objectPoints.begin() + worstElemIndex);
218
}
219
else {
220
mCalibData->allCharucoCorners.erase(mCalibData->allCharucoCorners.begin() + worstElemIndex);
221
mCalibData->allCharucoIds.erase(mCalibData->allCharucoIds.begin() + worstElemIndex);
222
}
223
224
cv::Mat newErrorsVec = cv::Mat((int)numberOfFrames - 1, 1, CV_64F);
225
std::copy(mCalibData->perViewErrors.ptr<double>(0),
226
mCalibData->perViewErrors.ptr<double>((int)worstElemIndex), newErrorsVec.ptr<double>(0));
227
if((int)worstElemIndex < (int)numberOfFrames-1) {
228
std::copy(mCalibData->perViewErrors.ptr<double>((int)worstElemIndex + 1), mCalibData->perViewErrors.ptr<double>((int)numberOfFrames),
229
newErrorsVec.ptr<double>((int)worstElemIndex));
230
}
231
mCalibData->perViewErrors = newErrorsVec;
232
}
233
}
234
235
void calib::calibDataController::setParametersFileName(const std::string &name)
236
{
237
mParamsFileName = name;
238
}
239
240
void calib::calibDataController::deleteLastFrame()
241
{
242
if( !mCalibData->imagePoints.empty()) {
243
mCalibData->imagePoints.pop_back();
244
mCalibData->objectPoints.pop_back();
245
}
246
247
if (!mCalibData->allCharucoCorners.empty()) {
248
mCalibData->allCharucoCorners.pop_back();
249
mCalibData->allCharucoIds.pop_back();
250
}
251
252
if(!mParamsStack.empty()) {
253
mCalibData->cameraMatrix = (mParamsStack.top()).cameraMatrix;
254
mCalibData->distCoeffs = (mParamsStack.top()).distCoeffs;
255
mCalibData->stdDeviations = (mParamsStack.top()).stdDeviations;
256
mCalibData->totalAvgErr = (mParamsStack.top()).avgError;
257
mParamsStack.pop();
258
}
259
}
260
261
void calib::calibDataController::rememberCurrentParameters()
262
{
263
cv::Mat oldCameraMat, oldDistcoeefs, oldStdDevs;
264
mCalibData->cameraMatrix.copyTo(oldCameraMat);
265
mCalibData->distCoeffs.copyTo(oldDistcoeefs);
266
mCalibData->stdDeviations.copyTo(oldStdDevs);
267
mParamsStack.push(cameraParameters(oldCameraMat, oldDistcoeefs, oldStdDevs, mCalibData->totalAvgErr));
268
}
269
270
void calib::calibDataController::deleteAllData()
271
{
272
mCalibData->imagePoints.clear();
273
mCalibData->objectPoints.clear();
274
mCalibData->allCharucoCorners.clear();
275
mCalibData->allCharucoIds.clear();
276
mCalibData->cameraMatrix = mCalibData->distCoeffs = cv::Mat();
277
mParamsStack = std::stack<cameraParameters>();
278
rememberCurrentParameters();
279
}
280
281
bool calib::calibDataController::saveCurrentCameraParameters() const
282
{
283
bool success = false;
284
if(mCalibData->cameraMatrix.total()) {
285
cv::FileStorage parametersWriter(mParamsFileName, cv::FileStorage::WRITE);
286
if(parametersWriter.isOpened()) {
287
time_t rawtime;
288
time(&rawtime);
289
char buf[256];
290
strftime(buf, sizeof(buf)-1, "%c", localtime(&rawtime));
291
292
parametersWriter << "calibrationDate" << buf;
293
parametersWriter << "framesCount" << std::max((int)mCalibData->objectPoints.size(), (int)mCalibData->allCharucoCorners.size());
294
parametersWriter << "cameraResolution" << mCalibData->imageSize;
295
parametersWriter << "cameraMatrix" << mCalibData->cameraMatrix;
296
parametersWriter << "cameraMatrix_std_dev" << mCalibData->stdDeviations.rowRange(cv::Range(0, 4));
297
parametersWriter << "dist_coeffs" << mCalibData->distCoeffs;
298
parametersWriter << "dist_coeffs_std_dev" << mCalibData->stdDeviations.rowRange(cv::Range(4, 9));
299
parametersWriter << "avg_reprojection_error" << mCalibData->totalAvgErr;
300
301
parametersWriter.release();
302
success = true;
303
}
304
}
305
return success;
306
}
307
308
void calib::calibDataController::printParametersToConsole(std::ostream &output) const
309
{
310
const char* border = "---------------------------------------------------";
311
output << border << std::endl;
312
output << "Frames used for calibration: " << std::max(mCalibData->objectPoints.size(), mCalibData->allCharucoCorners.size())
313
<< " \t RMS = " << mCalibData->totalAvgErr << std::endl;
314
if(mCalibData->cameraMatrix.at<double>(0,0) == mCalibData->cameraMatrix.at<double>(1,1))
315
output << "F = " << mCalibData->cameraMatrix.at<double>(1,1) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(1) << std::endl;
316
else
317
output << "Fx = " << mCalibData->cameraMatrix.at<double>(0,0) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(0) << " \t "
318
<< "Fy = " << mCalibData->cameraMatrix.at<double>(1,1) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(1) << std::endl;
319
output << "Cx = " << mCalibData->cameraMatrix.at<double>(0,2) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(2) << " \t"
320
<< "Cy = " << mCalibData->cameraMatrix.at<double>(1,2) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(3) << std::endl;
321
output << "K1 = " << mCalibData->distCoeffs.at<double>(0) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(4) << std::endl;
322
output << "K2 = " << mCalibData->distCoeffs.at<double>(1) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(5) << std::endl;
323
output << "K3 = " << mCalibData->distCoeffs.at<double>(4) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(8) << std::endl;
324
output << "TD1 = " << mCalibData->distCoeffs.at<double>(2) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(6) << std::endl;
325
output << "TD2 = " << mCalibData->distCoeffs.at<double>(3) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(7) << std::endl;
326
}
327
328
void calib::calibDataController::updateUndistortMap()
329
{
330
cv::initUndistortRectifyMap(mCalibData->cameraMatrix, mCalibData->distCoeffs, cv::noArray(),
331
cv::getOptimalNewCameraMatrix(mCalibData->cameraMatrix, mCalibData->distCoeffs, mCalibData->imageSize, 0.0, mCalibData->imageSize),
332
mCalibData->imageSize, CV_16SC2, mCalibData->undistMap1, mCalibData->undistMap2);
333
334
}
335
336