Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Tetragramm
GitHub Repository: Tetragramm/opencv
Path: blob/master/apps/interactive-calibration/frameProcessor.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 "frameProcessor.hpp"
6
#include "rotationConverters.hpp"
7
8
#include <opencv2/calib3d.hpp>
9
#include <opencv2/imgproc.hpp>
10
#include <opencv2/highgui.hpp>
11
12
#include <vector>
13
#include <string>
14
#include <algorithm>
15
#include <limits>
16
17
using namespace calib;
18
19
#define VIDEO_TEXT_SIZE 4
20
#define POINT_SIZE 5
21
22
static cv::SimpleBlobDetector::Params getDetectorParams()
23
{
24
cv::SimpleBlobDetector::Params detectorParams;
25
26
detectorParams.thresholdStep = 40;
27
detectorParams.minThreshold = 20;
28
detectorParams.maxThreshold = 500;
29
detectorParams.minRepeatability = 2;
30
detectorParams.minDistBetweenBlobs = 5;
31
32
detectorParams.filterByColor = true;
33
detectorParams.blobColor = 0;
34
35
detectorParams.filterByArea = true;
36
detectorParams.minArea = 5;
37
detectorParams.maxArea = 5000;
38
39
detectorParams.filterByCircularity = false;
40
detectorParams.minCircularity = 0.8f;
41
detectorParams.maxCircularity = std::numeric_limits<float>::max();
42
43
detectorParams.filterByInertia = true;
44
detectorParams.minInertiaRatio = 0.1f;
45
detectorParams.maxInertiaRatio = std::numeric_limits<float>::max();
46
47
detectorParams.filterByConvexity = true;
48
detectorParams.minConvexity = 0.8f;
49
detectorParams.maxConvexity = std::numeric_limits<float>::max();
50
51
return detectorParams;
52
}
53
54
FrameProcessor::~FrameProcessor()
55
{
56
57
}
58
59
bool CalibProcessor::detectAndParseChessboard(const cv::Mat &frame)
60
{
61
int chessBoardFlags = cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_NORMALIZE_IMAGE | cv::CALIB_CB_FAST_CHECK;
62
bool isTemplateFound = cv::findChessboardCorners(frame, mBoardSize, mCurrentImagePoints, chessBoardFlags);
63
64
if (isTemplateFound) {
65
cv::Mat viewGray;
66
cv::cvtColor(frame, viewGray, cv::COLOR_BGR2GRAY);
67
cv::cornerSubPix(viewGray, mCurrentImagePoints, cv::Size(11,11),
68
cv::Size(-1,-1), cv::TermCriteria( cv::TermCriteria::EPS+cv::TermCriteria::COUNT, 30, 0.1 ));
69
cv::drawChessboardCorners(frame, mBoardSize, cv::Mat(mCurrentImagePoints), isTemplateFound);
70
mTemplateLocations.insert(mTemplateLocations.begin(), mCurrentImagePoints[0]);
71
}
72
return isTemplateFound;
73
}
74
75
bool CalibProcessor::detectAndParseChAruco(const cv::Mat &frame)
76
{
77
#ifdef HAVE_OPENCV_ARUCO
78
cv::Ptr<cv::aruco::Board> board = mCharucoBoard.staticCast<cv::aruco::Board>();
79
80
std::vector<std::vector<cv::Point2f> > corners, rejected;
81
std::vector<int> ids;
82
cv::aruco::detectMarkers(frame, mArucoDictionary, corners, ids, cv::aruco::DetectorParameters::create(), rejected);
83
cv::aruco::refineDetectedMarkers(frame, board, corners, ids, rejected);
84
cv::Mat currentCharucoCorners, currentCharucoIds;
85
if(ids.size() > 0)
86
cv::aruco::interpolateCornersCharuco(corners, ids, frame, mCharucoBoard, currentCharucoCorners,
87
currentCharucoIds);
88
if(ids.size() > 0) cv::aruco::drawDetectedMarkers(frame, corners);
89
90
if(currentCharucoCorners.total() > 3) {
91
float centerX = 0, centerY = 0;
92
for (int i = 0; i < currentCharucoCorners.size[0]; i++) {
93
centerX += currentCharucoCorners.at<float>(i, 0);
94
centerY += currentCharucoCorners.at<float>(i, 1);
95
}
96
centerX /= currentCharucoCorners.size[0];
97
centerY /= currentCharucoCorners.size[0];
98
99
mTemplateLocations.insert(mTemplateLocations.begin(), cv::Point2f(centerX, centerY));
100
cv::aruco::drawDetectedCornersCharuco(frame, currentCharucoCorners, currentCharucoIds);
101
mCurrentCharucoCorners = currentCharucoCorners;
102
mCurrentCharucoIds = currentCharucoIds;
103
return true;
104
}
105
#else
106
CV_UNUSED(frame);
107
#endif
108
return false;
109
}
110
111
bool CalibProcessor::detectAndParseACircles(const cv::Mat &frame)
112
{
113
bool isTemplateFound = findCirclesGrid(frame, mBoardSize, mCurrentImagePoints, cv::CALIB_CB_ASYMMETRIC_GRID, mBlobDetectorPtr);
114
if(isTemplateFound) {
115
mTemplateLocations.insert(mTemplateLocations.begin(), mCurrentImagePoints[0]);
116
cv::drawChessboardCorners(frame, mBoardSize, cv::Mat(mCurrentImagePoints), isTemplateFound);
117
}
118
return isTemplateFound;
119
}
120
121
bool CalibProcessor::detectAndParseDualACircles(const cv::Mat &frame)
122
{
123
std::vector<cv::Point2f> blackPointbuf;
124
125
cv::Mat invertedView;
126
cv::bitwise_not(frame, invertedView);
127
bool isWhiteGridFound = cv::findCirclesGrid(frame, mBoardSize, mCurrentImagePoints, cv::CALIB_CB_ASYMMETRIC_GRID, mBlobDetectorPtr);
128
if(!isWhiteGridFound)
129
return false;
130
bool isBlackGridFound = cv::findCirclesGrid(invertedView, mBoardSize, blackPointbuf, cv::CALIB_CB_ASYMMETRIC_GRID, mBlobDetectorPtr);
131
132
if(!isBlackGridFound)
133
{
134
mCurrentImagePoints.clear();
135
return false;
136
}
137
cv::drawChessboardCorners(frame, mBoardSize, cv::Mat(mCurrentImagePoints), isWhiteGridFound);
138
cv::drawChessboardCorners(frame, mBoardSize, cv::Mat(blackPointbuf), isBlackGridFound);
139
mCurrentImagePoints.insert(mCurrentImagePoints.end(), blackPointbuf.begin(), blackPointbuf.end());
140
mTemplateLocations.insert(mTemplateLocations.begin(), mCurrentImagePoints[0]);
141
142
return true;
143
}
144
145
void CalibProcessor::saveFrameData()
146
{
147
std::vector<cv::Point3f> objectPoints;
148
149
switch(mBoardType)
150
{
151
case Chessboard:
152
objectPoints.reserve(mBoardSize.height*mBoardSize.width);
153
for( int i = 0; i < mBoardSize.height; ++i )
154
for( int j = 0; j < mBoardSize.width; ++j )
155
objectPoints.push_back(cv::Point3f(j*mSquareSize, i*mSquareSize, 0));
156
mCalibData->imagePoints.push_back(mCurrentImagePoints);
157
mCalibData->objectPoints.push_back(objectPoints);
158
break;
159
case chAruco:
160
mCalibData->allCharucoCorners.push_back(mCurrentCharucoCorners);
161
mCalibData->allCharucoIds.push_back(mCurrentCharucoIds);
162
break;
163
case AcirclesGrid:
164
objectPoints.reserve(mBoardSize.height*mBoardSize.width);
165
for( int i = 0; i < mBoardSize.height; i++ )
166
for( int j = 0; j < mBoardSize.width; j++ )
167
objectPoints.push_back(cv::Point3f((2*j + i % 2)*mSquareSize, i*mSquareSize, 0));
168
mCalibData->imagePoints.push_back(mCurrentImagePoints);
169
mCalibData->objectPoints.push_back(objectPoints);
170
break;
171
case DoubleAcirclesGrid:
172
{
173
float gridCenterX = (2*((float)mBoardSize.width - 1) + 1)*mSquareSize + mTemplDist / 2;
174
float gridCenterY = (mBoardSize.height - 1)*mSquareSize / 2;
175
objectPoints.reserve(2*mBoardSize.height*mBoardSize.width);
176
177
//white part
178
for( int i = 0; i < mBoardSize.height; i++ )
179
for( int j = 0; j < mBoardSize.width; j++ )
180
objectPoints.push_back(
181
cv::Point3f(-float((2*j + i % 2)*mSquareSize + mTemplDist +
182
(2*(mBoardSize.width - 1) + 1)*mSquareSize - gridCenterX),
183
-float(i*mSquareSize) - gridCenterY,
184
0));
185
//black part
186
for( int i = 0; i < mBoardSize.height; i++ )
187
for( int j = 0; j < mBoardSize.width; j++ )
188
objectPoints.push_back(cv::Point3f(-float((2*j + i % 2)*mSquareSize - gridCenterX),
189
-float(i*mSquareSize) - gridCenterY, 0));
190
191
mCalibData->imagePoints.push_back(mCurrentImagePoints);
192
mCalibData->objectPoints.push_back(objectPoints);
193
}
194
break;
195
}
196
}
197
198
void CalibProcessor::showCaptureMessage(const cv::Mat& frame, const std::string &message)
199
{
200
cv::Point textOrigin(100, 100);
201
double textSize = VIDEO_TEXT_SIZE * frame.cols / (double) IMAGE_MAX_WIDTH;
202
cv::bitwise_not(frame, frame);
203
cv::putText(frame, message, textOrigin, 1, textSize, cv::Scalar(0,0,255), 2, cv::LINE_AA);
204
cv::imshow(mainWindowName, frame);
205
cv::waitKey(300);
206
}
207
208
bool CalibProcessor::checkLastFrame()
209
{
210
bool isFrameBad = false;
211
cv::Mat tmpCamMatrix;
212
const double badAngleThresh = 40;
213
214
if(!mCalibData->cameraMatrix.total()) {
215
tmpCamMatrix = cv::Mat::eye(3, 3, CV_64F);
216
tmpCamMatrix.at<double>(0,0) = 20000;
217
tmpCamMatrix.at<double>(1,1) = 20000;
218
tmpCamMatrix.at<double>(0,2) = mCalibData->imageSize.height/2;
219
tmpCamMatrix.at<double>(1,2) = mCalibData->imageSize.width/2;
220
}
221
else
222
mCalibData->cameraMatrix.copyTo(tmpCamMatrix);
223
224
if(mBoardType != chAruco) {
225
cv::Mat r, t, angles;
226
cv::solvePnP(mCalibData->objectPoints.back(), mCurrentImagePoints, tmpCamMatrix, mCalibData->distCoeffs, r, t);
227
RodriguesToEuler(r, angles, CALIB_DEGREES);
228
229
if(fabs(angles.at<double>(0)) > badAngleThresh || fabs(angles.at<double>(1)) > badAngleThresh) {
230
mCalibData->objectPoints.pop_back();
231
mCalibData->imagePoints.pop_back();
232
isFrameBad = true;
233
}
234
}
235
else {
236
#ifdef HAVE_OPENCV_ARUCO
237
cv::Mat r, t, angles;
238
std::vector<cv::Point3f> allObjPoints;
239
allObjPoints.reserve(mCurrentCharucoIds.total());
240
for(size_t i = 0; i < mCurrentCharucoIds.total(); i++) {
241
int pointID = mCurrentCharucoIds.at<int>((int)i);
242
CV_Assert(pointID >= 0 && pointID < (int)mCharucoBoard->chessboardCorners.size());
243
allObjPoints.push_back(mCharucoBoard->chessboardCorners[pointID]);
244
}
245
246
cv::solvePnP(allObjPoints, mCurrentCharucoCorners, tmpCamMatrix, mCalibData->distCoeffs, r, t);
247
RodriguesToEuler(r, angles, CALIB_DEGREES);
248
249
if(180.0 - fabs(angles.at<double>(0)) > badAngleThresh || fabs(angles.at<double>(1)) > badAngleThresh) {
250
isFrameBad = true;
251
mCalibData->allCharucoCorners.pop_back();
252
mCalibData->allCharucoIds.pop_back();
253
}
254
#endif
255
}
256
return isFrameBad;
257
}
258
259
CalibProcessor::CalibProcessor(cv::Ptr<calibrationData> data, captureParameters &capParams) :
260
mCalibData(data), mBoardType(capParams.board), mBoardSize(capParams.boardSize)
261
{
262
mCapuredFrames = 0;
263
mNeededFramesNum = capParams.calibrationStep;
264
mDelayBetweenCaptures = static_cast<int>(capParams.captureDelay * capParams.fps);
265
mMaxTemplateOffset = std::sqrt(static_cast<float>(mCalibData->imageSize.height * mCalibData->imageSize.height) +
266
static_cast<float>(mCalibData->imageSize.width * mCalibData->imageSize.width)) / 20.0;
267
mSquareSize = capParams.squareSize;
268
mTemplDist = capParams.templDst;
269
270
switch(mBoardType)
271
{
272
case chAruco:
273
#ifdef HAVE_OPENCV_ARUCO
274
mArucoDictionary = cv::aruco::getPredefinedDictionary(
275
cv::aruco::PREDEFINED_DICTIONARY_NAME(capParams.charucoDictName));
276
mCharucoBoard = cv::aruco::CharucoBoard::create(mBoardSize.width, mBoardSize.height, capParams.charucoSquareLenght,
277
capParams.charucoMarkerSize, mArucoDictionary);
278
#endif
279
break;
280
case AcirclesGrid:
281
mBlobDetectorPtr = cv::SimpleBlobDetector::create();
282
break;
283
case DoubleAcirclesGrid:
284
mBlobDetectorPtr = cv::SimpleBlobDetector::create(getDetectorParams());
285
break;
286
case Chessboard:
287
break;
288
}
289
}
290
291
cv::Mat CalibProcessor::processFrame(const cv::Mat &frame)
292
{
293
cv::Mat frameCopy;
294
frame.copyTo(frameCopy);
295
bool isTemplateFound = false;
296
mCurrentImagePoints.clear();
297
298
switch(mBoardType)
299
{
300
case Chessboard:
301
isTemplateFound = detectAndParseChessboard(frameCopy);
302
break;
303
case chAruco:
304
isTemplateFound = detectAndParseChAruco(frameCopy);
305
break;
306
case AcirclesGrid:
307
isTemplateFound = detectAndParseACircles(frameCopy);
308
break;
309
case DoubleAcirclesGrid:
310
isTemplateFound = detectAndParseDualACircles(frameCopy);
311
break;
312
}
313
314
if(mTemplateLocations.size() > mDelayBetweenCaptures)
315
mTemplateLocations.pop_back();
316
if(mTemplateLocations.size() == mDelayBetweenCaptures && isTemplateFound) {
317
if(cv::norm(mTemplateLocations.front() - mTemplateLocations.back()) < mMaxTemplateOffset) {
318
saveFrameData();
319
bool isFrameBad = checkLastFrame();
320
if (!isFrameBad) {
321
std::string displayMessage = cv::format("Frame # %zu captured", std::max(mCalibData->imagePoints.size(),
322
mCalibData->allCharucoCorners.size()));
323
if(!showOverlayMessage(displayMessage))
324
showCaptureMessage(frame, displayMessage);
325
mCapuredFrames++;
326
}
327
else {
328
std::string displayMessage = "Frame rejected";
329
if(!showOverlayMessage(displayMessage))
330
showCaptureMessage(frame, displayMessage);
331
}
332
mTemplateLocations.clear();
333
mTemplateLocations.reserve(mDelayBetweenCaptures);
334
}
335
}
336
337
return frameCopy;
338
}
339
340
bool CalibProcessor::isProcessed() const
341
{
342
if(mCapuredFrames < mNeededFramesNum)
343
return false;
344
else
345
return true;
346
}
347
348
void CalibProcessor::resetState()
349
{
350
mCapuredFrames = 0;
351
mTemplateLocations.clear();
352
}
353
354
CalibProcessor::~CalibProcessor()
355
{
356
357
}
358
359
////////////////////////////////////////////
360
361
void ShowProcessor::drawBoard(cv::Mat &img, cv::InputArray points)
362
{
363
cv::Mat tmpView = cv::Mat::zeros(img.rows, img.cols, CV_8UC3);
364
std::vector<cv::Point2f> templateHull;
365
std::vector<cv::Point> poly;
366
cv::convexHull(points, templateHull);
367
poly.resize(templateHull.size());
368
for(size_t i=0; i<templateHull.size();i++)
369
poly[i] = cv::Point((int)(templateHull[i].x*mGridViewScale), (int)(templateHull[i].y*mGridViewScale));
370
cv::fillConvexPoly(tmpView, poly, cv::Scalar(0, 255, 0), cv::LINE_AA);
371
cv::addWeighted(tmpView, .2, img, 1, 0, img);
372
}
373
374
void ShowProcessor::drawGridPoints(const cv::Mat &frame)
375
{
376
if(mBoardType != chAruco)
377
for(std::vector<std::vector<cv::Point2f> >::iterator it = mCalibdata->imagePoints.begin(); it != mCalibdata->imagePoints.end(); ++it)
378
for(std::vector<cv::Point2f>::iterator pointIt = (*it).begin(); pointIt != (*it).end(); ++pointIt)
379
cv::circle(frame, *pointIt, POINT_SIZE, cv::Scalar(0, 255, 0), 1, cv::LINE_AA);
380
else
381
for(std::vector<cv::Mat>::iterator it = mCalibdata->allCharucoCorners.begin(); it != mCalibdata->allCharucoCorners.end(); ++it)
382
for(int i = 0; i < (*it).size[0]; i++)
383
cv::circle(frame, cv::Point((int)(*it).at<float>(i, 0), (int)(*it).at<float>(i, 1)),
384
POINT_SIZE, cv::Scalar(0, 255, 0), 1, cv::LINE_AA);
385
}
386
387
ShowProcessor::ShowProcessor(cv::Ptr<calibrationData> data, cv::Ptr<calibController> controller, TemplateType board) :
388
mCalibdata(data), mController(controller), mBoardType(board)
389
{
390
mNeedUndistort = true;
391
mVisMode = Grid;
392
mGridViewScale = 0.5;
393
mTextSize = VIDEO_TEXT_SIZE;
394
}
395
396
cv::Mat ShowProcessor::processFrame(const cv::Mat &frame)
397
{
398
if (!mCalibdata->cameraMatrix.empty() && !mCalibdata->distCoeffs.empty())
399
{
400
mTextSize = VIDEO_TEXT_SIZE * (double) frame.cols / IMAGE_MAX_WIDTH;
401
cv::Scalar textColor = cv::Scalar(0,0,255);
402
cv::Mat frameCopy;
403
404
if (mNeedUndistort && mController->getFramesNumberState()) {
405
if(mVisMode == Grid)
406
drawGridPoints(frame);
407
cv::remap(frame, frameCopy, mCalibdata->undistMap1, mCalibdata->undistMap2, cv::INTER_LINEAR);
408
int baseLine = 100;
409
cv::Size textSize = cv::getTextSize("Undistorted view", 1, mTextSize, 2, &baseLine);
410
cv::Point textOrigin(baseLine, frame.rows - (int)(2.5*textSize.height));
411
cv::putText(frameCopy, "Undistorted view", textOrigin, 1, mTextSize, textColor, 2, cv::LINE_AA);
412
}
413
else {
414
frame.copyTo(frameCopy);
415
if(mVisMode == Grid)
416
drawGridPoints(frameCopy);
417
}
418
std::string displayMessage;
419
if(mCalibdata->stdDeviations.at<double>(0) == 0)
420
displayMessage = cv::format("F = %d RMS = %.3f", (int)mCalibdata->cameraMatrix.at<double>(0,0), mCalibdata->totalAvgErr);
421
else
422
displayMessage = cv::format("Fx = %d Fy = %d RMS = %.3f", (int)mCalibdata->cameraMatrix.at<double>(0,0),
423
(int)mCalibdata->cameraMatrix.at<double>(1,1), mCalibdata->totalAvgErr);
424
if(mController->getRMSState() && mController->getFramesNumberState())
425
displayMessage.append(" OK");
426
427
int baseLine = 100;
428
cv::Size textSize = cv::getTextSize(displayMessage, 1, mTextSize - 1, 2, &baseLine);
429
cv::Point textOrigin = cv::Point(baseLine, 2*textSize.height);
430
cv::putText(frameCopy, displayMessage, textOrigin, 1, mTextSize - 1, textColor, 2, cv::LINE_AA);
431
432
if(mCalibdata->stdDeviations.at<double>(0) == 0)
433
displayMessage = cv::format("DF = %.2f", mCalibdata->stdDeviations.at<double>(1)*sigmaMult);
434
else
435
displayMessage = cv::format("DFx = %.2f DFy = %.2f", mCalibdata->stdDeviations.at<double>(0)*sigmaMult,
436
mCalibdata->stdDeviations.at<double>(1)*sigmaMult);
437
if(mController->getConfidenceIntrervalsState() && mController->getFramesNumberState())
438
displayMessage.append(" OK");
439
cv::putText(frameCopy, displayMessage, cv::Point(baseLine, 4*textSize.height), 1, mTextSize - 1, textColor, 2, cv::LINE_AA);
440
441
if(mController->getCommonCalibrationState()) {
442
displayMessage = cv::format("Calibration is done");
443
cv::putText(frameCopy, displayMessage, cv::Point(baseLine, 6*textSize.height), 1, mTextSize - 1, textColor, 2, cv::LINE_AA);
444
}
445
int calibFlags = mController->getNewFlags();
446
displayMessage = "";
447
if(!(calibFlags & cv::CALIB_FIX_ASPECT_RATIO))
448
displayMessage.append(cv::format("AR=%.3f ", mCalibdata->cameraMatrix.at<double>(0,0)/mCalibdata->cameraMatrix.at<double>(1,1)));
449
if(calibFlags & cv::CALIB_ZERO_TANGENT_DIST)
450
displayMessage.append("TD=0 ");
451
displayMessage.append(cv::format("K1=%.2f K2=%.2f K3=%.2f", mCalibdata->distCoeffs.at<double>(0), mCalibdata->distCoeffs.at<double>(1),
452
mCalibdata->distCoeffs.at<double>(4)));
453
cv::putText(frameCopy, displayMessage, cv::Point(baseLine, frameCopy.rows - (int)(1.5*textSize.height)),
454
1, mTextSize - 1, textColor, 2, cv::LINE_AA);
455
return frameCopy;
456
}
457
458
return frame;
459
}
460
461
bool ShowProcessor::isProcessed() const
462
{
463
return false;
464
}
465
466
void ShowProcessor::resetState()
467
{
468
469
}
470
471
void ShowProcessor::setVisualizationMode(visualisationMode mode)
472
{
473
mVisMode = mode;
474
}
475
476
void ShowProcessor::switchVisualizationMode()
477
{
478
if(mVisMode == Grid) {
479
mVisMode = Window;
480
updateBoardsView();
481
}
482
else {
483
mVisMode = Grid;
484
cv::destroyWindow(gridWindowName);
485
}
486
}
487
488
void ShowProcessor::clearBoardsView()
489
{
490
cv::imshow(gridWindowName, cv::Mat());
491
}
492
493
void ShowProcessor::updateBoardsView()
494
{
495
if(mVisMode == Window) {
496
cv::Size originSize = mCalibdata->imageSize;
497
cv::Mat altGridView = cv::Mat::zeros((int)(originSize.height*mGridViewScale), (int)(originSize.width*mGridViewScale), CV_8UC3);
498
if(mBoardType != chAruco)
499
for(std::vector<std::vector<cv::Point2f> >::iterator it = mCalibdata->imagePoints.begin(); it != mCalibdata->imagePoints.end(); ++it)
500
if(mBoardType != DoubleAcirclesGrid)
501
drawBoard(altGridView, *it);
502
else {
503
size_t pointsNum = (*it).size()/2;
504
std::vector<cv::Point2f> points(pointsNum);
505
std::copy((*it).begin(), (*it).begin() + pointsNum, points.begin());
506
drawBoard(altGridView, points);
507
std::copy((*it).begin() + pointsNum, (*it).begin() + 2*pointsNum, points.begin());
508
drawBoard(altGridView, points);
509
}
510
else
511
for(std::vector<cv::Mat>::iterator it = mCalibdata->allCharucoCorners.begin(); it != mCalibdata->allCharucoCorners.end(); ++it)
512
drawBoard(altGridView, *it);
513
cv::imshow(gridWindowName, altGridView);
514
}
515
}
516
517
void ShowProcessor::switchUndistort()
518
{
519
mNeedUndistort = !mNeedUndistort;
520
}
521
522
void ShowProcessor::setUndistort(bool isEnabled)
523
{
524
mNeedUndistort = isEnabled;
525
}
526
527
ShowProcessor::~ShowProcessor()
528
{
529
530
}
531
532