main.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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 <opencv2/core.hpp>
  5. #include <opencv2/calib3d.hpp>
  6. #include <opencv2/cvconfig.h>
  7. #include <opencv2/highgui.hpp>
  8. #include <opencv2/videoio/registry.hpp>
  9. #include <string>
  10. #include <vector>
  11. #include <stdexcept>
  12. #include <algorithm>
  13. #include <iostream>
  14. #include "calibCommon.hpp"
  15. #include "calibPipeline.hpp"
  16. #include "frameProcessor.hpp"
  17. #include "calibController.hpp"
  18. #include "parametersController.hpp"
  19. #include "rotationConverters.hpp"
  20. using namespace calib;
  21. static std::string getVideoIoBackendsString()
  22. {
  23. std::string result;
  24. auto backs = cv::videoio_registry::getBackends();
  25. for (const auto& b: backs)
  26. {
  27. if (!result.empty())
  28. result += ", ";
  29. result += cv::videoio_registry::getBackendName(b);
  30. }
  31. return result;
  32. }
  33. const char* keys =
  34. "{v | | Input from video file }"
  35. "{ci | 0 | Camera id }"
  36. "{vb | | Video I/O back-end. One of: %s }"
  37. "{flip | false | Vertical flip of input frames }"
  38. "{t | circles | Template for calibration (circles, chessboard, dualCircles, charuco, symcircles) }"
  39. "{sz | 16.3 | Distance between two nearest centers of circles or squares on calibration board}"
  40. "{dst | 295 | Distance between white and black parts of daulCircles template}"
  41. "{w | | Width of template (in corners or circles)}"
  42. "{h | | Height of template (in corners or circles)}"
  43. "{ad | DICT_4X4_50 | Name of predefined ArUco dictionary. Available ArUco dictionaries: "
  44. "DICT_4X4_50, DICT_4X4_100, DICT_4X4_250, DICT_4X4_1000, DICT_5X5_50, DICT_5X5_100, DICT_5X5_250, "
  45. "DICT_5X5_1000, DICT_6X6_50, DICT_6X6_100, DICT_6X6_250, DICT_6X6_1000, DICT_7X7_50, DICT_7X7_100, "
  46. "DICT_7X7_250, DICT_7X7_1000, DICT_ARUCO_ORIGINAL, DICT_APRILTAG_16h5, DICT_APRILTAG_25h9, "
  47. "DICT_APRILTAG_36h10, DICT_APRILTAG_36h11 }"
  48. "{fad | None | name of file with ArUco dictionary}"
  49. "{of | cameraParameters.xml | Output file name}"
  50. "{ft | true | Auto tuning of calibration flags}"
  51. "{vis | grid | Captured boards visualisation (grid, window)}"
  52. "{d | 0.8 | Min delay between captures}"
  53. "{pf | defaultConfig.xml| Advanced application parameters}"
  54. "{save_frames | false | Save frames that contribute to final calibration}"
  55. "{zoom | 1 | Zoom factor applied to the preview image}"
  56. "{force_reopen | false | Forcefully reopen camera in case of errors}"
  57. "{help | | Print help}";
  58. bool calib::showOverlayMessage(const std::string& message)
  59. {
  60. #ifdef HAVE_QT
  61. cv::displayOverlay(mainWindowName, message, OVERLAY_DELAY);
  62. return true;
  63. #else
  64. std::cout << message << std::endl;
  65. return false;
  66. #endif
  67. }
  68. static void deleteButton(int, void* data)
  69. {
  70. (static_cast<cv::Ptr<calibDataController>*>(data))->get()->deleteLastFrame();
  71. calib::showOverlayMessage("Last frame deleted");
  72. }
  73. static void deleteAllButton(int, void* data)
  74. {
  75. (static_cast<cv::Ptr<calibDataController>*>(data))->get()->deleteAllData();
  76. calib::showOverlayMessage("All frames deleted");
  77. }
  78. static void saveCurrentParamsButton(int, void* data)
  79. {
  80. if((static_cast<cv::Ptr<calibDataController>*>(data))->get()->saveCurrentCameraParameters())
  81. calib::showOverlayMessage("Calibration parameters saved");
  82. }
  83. #ifdef HAVE_QT
  84. static void switchVisualizationModeButton(int, void* data)
  85. {
  86. ShowProcessor* processor = static_cast<ShowProcessor*>(((cv::Ptr<FrameProcessor>*)data)->get());
  87. processor->switchVisualizationMode();
  88. }
  89. static void undistortButton(int state, void* data)
  90. {
  91. ShowProcessor* processor = static_cast<ShowProcessor*>(((cv::Ptr<FrameProcessor>*)data)->get());
  92. processor->setUndistort(static_cast<bool>(state));
  93. calib::showOverlayMessage(std::string("Undistort is ") +
  94. (static_cast<bool>(state) ? std::string("on") : std::string("off")));
  95. }
  96. #endif //HAVE_QT
  97. int main(int argc, char** argv)
  98. {
  99. cv::CommandLineParser parser(argc, argv, cv::format(keys, getVideoIoBackendsString().c_str()));
  100. if(parser.has("help")) {
  101. parser.printMessage();
  102. return 0;
  103. }
  104. std::cout << consoleHelp << std::endl;
  105. parametersController paramsController;
  106. if(!paramsController.loadFromParser(parser))
  107. return 0;
  108. captureParameters capParams = paramsController.getCaptureParameters();
  109. internalParameters intParams = paramsController.getInternalParameters();
  110. cv::TermCriteria solverTermCrit = cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS,
  111. intParams.solverMaxIters, intParams.solverEps);
  112. cv::Ptr<calibrationData> globalData(new calibrationData);
  113. if(!parser.has("v")) globalData->imageSize = capParams.cameraResolution;
  114. int calibrationFlags = 0;
  115. if(intParams.fastSolving) calibrationFlags |= cv::CALIB_USE_QR;
  116. if(intParams.rationalModel) calibrationFlags |= cv::CALIB_RATIONAL_MODEL;
  117. if(intParams.thinPrismModel) calibrationFlags |= cv::CALIB_THIN_PRISM_MODEL;
  118. if(intParams.tiltedModel) calibrationFlags |= cv::CALIB_TILTED_MODEL;
  119. cv::Ptr<calibController> controller(new calibController(globalData, calibrationFlags,
  120. parser.get<bool>("ft"), capParams.minFramesNum));
  121. cv::Ptr<calibDataController> dataController(new calibDataController(globalData, capParams.maxFramesNum,
  122. intParams.filterAlpha));
  123. dataController->setParametersFileName(parser.get<std::string>("of"));
  124. cv::Ptr<FrameProcessor> capProcessor, showProcessor;
  125. capProcessor = cv::Ptr<FrameProcessor>(new CalibProcessor(globalData, capParams));
  126. showProcessor = cv::Ptr<FrameProcessor>(new ShowProcessor(globalData, controller, capParams.board));
  127. if(parser.get<std::string>("vis").find("window") == 0) {
  128. static_cast<ShowProcessor*>(showProcessor.get())->setVisualizationMode(Window);
  129. cv::namedWindow(gridWindowName);
  130. cv::moveWindow(gridWindowName, 1280, 500);
  131. }
  132. cv::Ptr<CalibPipeline> pipeline(new CalibPipeline(capParams));
  133. std::vector<cv::Ptr<FrameProcessor> > processors;
  134. processors.push_back(capProcessor);
  135. processors.push_back(showProcessor);
  136. cv::namedWindow(mainWindowName);
  137. cv::moveWindow(mainWindowName, 10, 10);
  138. #ifdef HAVE_QT
  139. cv::createButton("Delete last frame", deleteButton, &dataController,
  140. cv::QT_PUSH_BUTTON | cv::QT_NEW_BUTTONBAR);
  141. cv::createButton("Delete all frames", deleteAllButton, &dataController,
  142. cv::QT_PUSH_BUTTON | cv::QT_NEW_BUTTONBAR);
  143. cv::createButton("Undistort", undistortButton, &showProcessor,
  144. cv::QT_CHECKBOX | cv::QT_NEW_BUTTONBAR, false);
  145. cv::createButton("Save current parameters", saveCurrentParamsButton, &dataController,
  146. cv::QT_PUSH_BUTTON | cv::QT_NEW_BUTTONBAR);
  147. cv::createButton("Switch visualisation mode", switchVisualizationModeButton, &showProcessor,
  148. cv::QT_PUSH_BUTTON | cv::QT_NEW_BUTTONBAR);
  149. #endif //HAVE_QT
  150. try {
  151. bool pipelineFinished = false;
  152. while(!pipelineFinished)
  153. {
  154. PipelineExitStatus exitStatus = pipeline->start(processors);
  155. if (exitStatus == Finished) {
  156. if(controller->getCommonCalibrationState())
  157. saveCurrentParamsButton(0, &dataController);
  158. pipelineFinished = true;
  159. continue;
  160. }
  161. else if (exitStatus == Calibrate) {
  162. dataController->rememberCurrentParameters();
  163. globalData->imageSize = pipeline->getImageSize();
  164. calibrationFlags = controller->getNewFlags();
  165. globalData->totalAvgErr =
  166. cv::calibrateCamera(globalData->objectPoints, globalData->imagePoints,
  167. globalData->imageSize, globalData->cameraMatrix,
  168. globalData->distCoeffs, cv::noArray(), cv::noArray(),
  169. globalData->stdDeviations, cv::noArray(), globalData->perViewErrors,
  170. calibrationFlags, solverTermCrit);
  171. dataController->updateUndistortMap();
  172. dataController->printParametersToConsole(std::cout);
  173. controller->updateState();
  174. for(int j = 0; j < capParams.calibrationStep; j++)
  175. dataController->filterFrames();
  176. static_cast<ShowProcessor*>(showProcessor.get())->updateBoardsView();
  177. }
  178. else if (exitStatus == DeleteLastFrame) {
  179. deleteButton(0, &dataController);
  180. static_cast<ShowProcessor*>(showProcessor.get())->updateBoardsView();
  181. }
  182. else if (exitStatus == DeleteAllFrames) {
  183. deleteAllButton(0, &dataController);
  184. static_cast<ShowProcessor*>(showProcessor.get())->updateBoardsView();
  185. }
  186. else if (exitStatus == SaveCurrentData) {
  187. saveCurrentParamsButton(0, &dataController);
  188. }
  189. else if (exitStatus == SwitchUndistort)
  190. static_cast<ShowProcessor*>(showProcessor.get())->switchUndistort();
  191. else if (exitStatus == SwitchVisualisation)
  192. static_cast<ShowProcessor*>(showProcessor.get())->switchVisualizationMode();
  193. for (std::vector<cv::Ptr<FrameProcessor> >::iterator it = processors.begin(); it != processors.end(); ++it)
  194. (*it)->resetState();
  195. }
  196. }
  197. catch (const std::runtime_error& exp) {
  198. std::cout << exp.what() << std::endl;
  199. }
  200. return 0;
  201. }