frameProcessor.cpp 22 KB

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