/// it has multithread support under c++ 11 void CameraCalibration::getImagesAndFindPatterns(const string &cameraName) { // set mode mode = CAPTURING; frameCounter = 0; imageCounter = 0; capturedFrame currentImage; // read current path currentPath = boost::filesystem::current_path(); resultsPath = currentPath; cout << "current Results Path" << currentPath << '\n' << endl; //mode = s.inputType == Settings::IMAGE_LIST ? CAPTURING : DETECTION;// check enum type // Capture only the frames settled in the configuration file // in the original code it was a endless loop for (int i = 0;; ++i) { Mat view,currentView; bool blinkOutput = false; // capture the image view = s.nextImage(); frameCounter = frameCounter + 1; //------------------------- Show original distorted image ----------------------------------- Mat originalView = view.clone(); //imshow("original Image", originalView); //----- If no more image, or got enough, then stop calibration and show result ------------- if (mode == CAPTURING && imagePoints.size() >= (unsigned)s.nrFrames) { if (runCalibrationAndSave(s, imageSize, cameraMatrix, distCoeffs, imagePoints)) mode = CALIBRATED; else mode = DETECTION; } if (view.empty()) // If no more images then run calibration, save and stop loop. { if (imagePoints.size() > 0) runCalibrationAndSave(s, imageSize, cameraMatrix, distCoeffs, imagePoints); break; } imageSize = view.size(); // Format input image. if (s.flipVertical) flip(view, view, 0); vector<Point2f> pointBuf; bool found; switch (s.calibrationPattern) // Find feature points on the input format { case Settings::CHESSBOARD: found = findChessboardCorners(view, s.boardSize, pointBuf, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FAST_CHECK | CALIB_CB_NORMALIZE_IMAGE); break; case Settings::CIRCLES_GRID: found = findCirclesGrid(view, s.boardSize, pointBuf); break; case Settings::ASYMMETRIC_CIRCLES_GRID: found = findCirclesGrid(view, s.boardSize, pointBuf, CALIB_CB_ASYMMETRIC_GRID); break; default: found = false; break; } if (found) // If done with success, { // improve the found corners' coordinate accuracy for chessboard if (s.calibrationPattern == Settings::CHESSBOARD) { Mat viewGray; cvtColor(view, viewGray, COLOR_BGR2GRAY); cornerSubPix(viewGray, pointBuf, Size(11, 11), Size(-1, -1), TermCriteria(TermCriteria::EPS+TermCriteria::MAX_ITER, 30, 0.1)); } if (mode == CAPTURING && // For camera only take new samples after delay time (!s.inputCapture.isOpened() || clock() - prevTimestamp > s.delay*1e-3*CLOCKS_PER_SEC)) { imagePoints.push_back(pointBuf); prevTimestamp = clock(); blinkOutput = s.inputCapture.isOpened(); circlePoints = pointBuf; // save ordered circle points } // Draw the corners with ID according order criteria distance(x+y) from origin point 1 savedImage = view.clone(); drawChessboardCorners(view, s.boardSize, Mat(pointBuf), found); // order the points according to d(x+y) from the upper left corner that is used as the origin frame std::sort(pointBuf.begin(), pointBuf.end(), [](const cv::Point2f &a, const cv::Point2f &b) {return ((a.x + a.y) < (b.x + b.y)); }); int pointCounter = 1; for (auto k:pointBuf){ cv::putText(view,std::to_string(pointCounter),cv::Point(k.x,k.y),cv::FONT_HERSHEY_PLAIN,1.0,cv::Scalar(255,0,0),1); pointCounter = pointCounter + 1; } } //----------------------------- Output Text ------------------------------------------------ string msg = (mode == CAPTURING) ? "100/100" : mode == CALIBRATED ? "Calibrated" : "the images are being captured"; int baseLine = 0; Size textSize = getTextSize(msg, 1, 1, 1, &baseLine); Point textOrigin(view.cols - 2 * textSize.width - 10, view.rows - 2 * baseLine - 10); if (mode == CAPTURING) { if (s.showUndistorsed) msg = format("%d/%d Undist", (int)imagePoints.size(), s.nrFrames); else msg = format("%d/%d", (int)imagePoints.size(), s.nrFrames); } putText(view, msg, textOrigin, 1, 1, mode == CALIBRATED ? GREEN : RED); if (blinkOutput){ bitwise_not(view, view); // save the image used for calibration to disk imageCounter = imageCounter + 1; string pathToFile; string filename; if (imageCounter <= s.nrFrames) { string imageName{ "Image" + string(std::to_string(imageCounter)) + cameraName + ".jpg" }; boost::filesystem::path p{ "/" }; // add a slash to generate a portable string filename.assign(resultsPath.string() + p.generic_string() + imageName); vector<int> compression_params; compression_params.push_back(IMWRITE_JPEG_QUALITY); compression_params.push_back(100); // check if the file already exist? if yes, erase it bool found = getPathForThisFile(imageName,pathToFile); if (found){ boost::filesystem::remove(pathToFile); } // write the new version of the file cv::imwrite(filename, savedImage); // save the points use to estimate the scale factor int currentBufferPosition = imagePoints.size(); int pointCounter = 1; circlePatternInfo currentCircle; circlesDataPerImage dataCurrentImage; vector<circlePatternInfo> circlesInfoFromThisImage; for (auto k : circlePoints){ currentCircle.circleID = pointCounter; currentCircle.circlePosition = cv::Point2f(k.x, k.y); currentCircle.circle3DPosition = circle_Mis_Positions.at(pointCounter - 1); circlesInfoFromThisImage.push_back(currentCircle); pointCounter = pointCounter + 1; } circlePoints.clear(); dataCurrentImage.imageID= imageCounter; dataCurrentImage.cameraID = s.cameraID; dataCurrentImage.circlesData = circlesInfoFromThisImage; // save all the data from the asymetric circles pattern DataFromCirclesPattern.push_back(dataCurrentImage); } } //------------------------- Video capture output undistorted ------------------------------ if (mode == CALIBRATED && s.showUndistorsed) { Mat temp = view.clone(); undistort(temp, view, cameraMatrix, distCoeffs); string msgEsckey = "Press 'esc' key to quit"; putText(view, msgEsckey, textOrigin, 1, 1, GREEN, 2); } //------------------------------ Show image and check for input commands ------------------- imshow(cameraName, view); //delay 30ms so that screen can refresh. //image will not appear without this waitKey() command cv::waitKey(30); char c = waitKey(1); if (c == ESC_KEY) // Escape key break; // Breaks the capture loop } }
void CameraCalibration::calibrate() { const string inputSettingsFile = "default.xml"; // Read the settings FileStorage fs( inputSettingsFile, FileStorage::READ ); if ( !fs.isOpened() ) { FileStorage fs( inputSettingsFile, FileStorage::WRITE ); fs.release(); cerr << "Could not open the configuration file: \"" << inputSettingsFile << "\"" << endl; return; } else { s.read( fs["Settings"] ); // close Settings file fs.release(); } if ( !s.goodInput ) { cerr << "Invalid input detected. Application stopping." << endl; return; } vector<vector<Point2f> > imagePoints; Mat distCoeffs; Size imageSize; int mode = s.inputType == Settings::IMAGE_LIST ? CAPTURING : DETECTION; clock_t prevTimestamp = 0; const Scalar RED( 0, 0, 255 ), GREEN( 0, 255, 0 ); const char ESC_KEY = 27; for ( int i = 0; ; ++i ) { Mat view; bool blinkOutput = false; view = s.nextImage(); //----- If no more image, or got enough, then stop calibration and show result ------------- if ( mode == CAPTURING && imagePoints.size() >= (unsigned)s.nrFrames ) { if ( runCalibrationAndSave(s, imageSize, cameraMatrix, distCoeffs, imagePoints ) ) { mode = CALIBRATED; } else { mode = DETECTION; } } // If no more images then run calibration, save and stop loop. if ( view.empty() ) { if ( imagePoints.size() > 0 ) { runCalibrationAndSave(s, imageSize, cameraMatrix, distCoeffs, imagePoints); } break; } imageSize = view.size(); // Format input image. if ( s.flipVertical ) { flip( view, view, 0 ); } vector<Point2f> pointBuf; bool found; // Find feature points on the input format switch ( s.calibrationPattern ) { case Settings::CHESSBOARD: found = findChessboardCorners( view, s.boardSize, pointBuf, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FAST_CHECK | CALIB_CB_NORMALIZE_IMAGE); break; case Settings::CIRCLES_GRID: found = findCirclesGrid( view, s.boardSize, pointBuf ); break; case Settings::ASYMMETRIC_CIRCLES_GRID: found = findCirclesGrid( view, s.boardSize, pointBuf, CALIB_CB_ASYMMETRIC_GRID ); break; default: found = false; break; } // If done with success, improve the found corners' coordinate accuracy for chessboard if ( found ) { if ( s.calibrationPattern == Settings::CHESSBOARD ) { Mat viewGray; cvtColor( view, viewGray, COLOR_BGR2GRAY ); cornerSubPix( viewGray, pointBuf, Size( 11,11 ), Size(-1,-1), TermCriteria( TermCriteria::EPS + TermCriteria::MAX_ITER, 30, 0.1 ) ); } // For camera only take new samples after delay time if ( mode == CAPTURING && (!s.inputCapture.isOpened() || clock() - prevTimestamp > s.delay*1e-3*CLOCKS_PER_SEC) ) { imagePoints.push_back( pointBuf ); prevTimestamp = clock(); blinkOutput = s.inputCapture.isOpened(); } // Draw the corners. drawChessboardCorners( view, s.boardSize, Mat( pointBuf ), found ); } //----------------------------- Output Text ------------------------------------------------ string msg = ( mode == CAPTURING ) ? "100/100" : mode == CALIBRATED ? "Calibrated" : "Press 'g' to start"; int baseLine = 0; Size textSize = getTextSize( msg, 1, 1, 1, &baseLine ); Point textOrigin( view.cols - 2*textSize.width - 10, view.rows - 2*baseLine - 10 ); if ( mode == CAPTURING ) { if ( s.showUndistorsed ) { msg = format( "%d/%d Undist", (int)imagePoints.size(), s.nrFrames ); } else { msg = format( "%d/%d", (int)imagePoints.size(), s.nrFrames ); } } putText( view, msg, textOrigin, 1, 1, mode == CALIBRATED ? GREEN : RED ); if ( blinkOutput ) { bitwise_not( view, view ); } //------------------------- Video capture output undistorted ------------------------------ if ( mode == CALIBRATED && s.showUndistorsed ) { Mat temp = view.clone(); undistort( temp, view, cameraMatrix, distCoeffs ); } //------------------------------ Show image and check for input commands ------------------- imshow( "Image View", view ); char key = (char)waitKey( s.inputCapture.isOpened() ? 50 : s.delay ); if ( key == ESC_KEY ) { break; } if ( key == 'u' && mode == CALIBRATED ) { s.showUndistorsed = !s.showUndistorsed; } if ( s.inputCapture.isOpened() && key == 'g' ) { mode = CAPTURING; imagePoints.clear(); } } // -----------------------Show the undistorted image for the image list ------------------------ if ( s.inputType == Settings::IMAGE_LIST && s.showUndistorsed ) { Mat view, rview, map1, map2; initUndistortRectifyMap( cameraMatrix, distCoeffs, Mat(), getOptimalNewCameraMatrix( cameraMatrix, distCoeffs, imageSize, 1, imageSize, 0 ), imageSize, CV_16SC2, map1, map2 ); for ( int i = 0; i < (int)s.imageList.size(); i++ ) { view = imread( s.imageList[i], 1 ); if ( view.empty() ) { continue; } remap( view, rview, map1, map2, INTER_LINEAR ); imshow( "Image View", rview ); char c = (char)waitKey(); if ( c == ESC_KEY || c == 'q' || c == 'Q' ) { break; } } } }
/////////////////////////////////////////////////////// // Panel::CalibrateCamera() Description /////////////////////////////////////////////////////// void Panel::CalibrateCamera(string sFilePath) { help(); //! [file_read] Settings s; const string inputSettingsFile = sFilePath; FileStorage fs(inputSettingsFile, FileStorage::READ); // Read the settings if (!fs.isOpened()) { cout << "Could not open the configuration file: \"" << inputSettingsFile << "\"" << endl; // return -1; } fs["Settings"] >> s; fs.release(); // close Settings file //! [file_read] //FileStorage fout("settings.yml", FileStorage::WRITE); // write config as YAML //fout << "Settings" << s; if (!s.goodInput) { cout << "Invalid input detected. Application stopping. " << endl; // return -1; } vector<vector<Point2f> > imagePoints; Mat cameraMatrix, distCoeffs; Size imageSize; int mode = s.inputType == Settings::IMAGE_LIST ? CAPTURING : DETECTION; clock_t prevTimestamp = 0; const Scalar RED(0, 0, 255), GREEN(0, 255, 0); const char ESC_KEY = 27; int counter = 1; //! [get_input] for (;;) { Mat view; bool blinkOutput = false; view = s.nextImage(); //----- If no more image, or got enough, then stop calibration and show result ------------- if (mode == CAPTURING && imagePoints.size() >= (size_t)s.nrFrames) { if (runCalibrationAndSave(s, imageSize, cameraMatrix, distCoeffs, imagePoints)) mode = CALIBRATED; else mode = DETECTION; } if (view.empty()) // If there are no more images stop the loop { // if calibration threshold was not reached yet, calibrate now if (mode != CALIBRATED && !imagePoints.empty()) runCalibrationAndSave(s, imageSize, cameraMatrix, distCoeffs, imagePoints); break; } //! [get_input] imageSize = view.size(); // Format input image. if (s.flipVertical) flip(view, view, 0); //! [find_pattern] vector<Point2f> pointBuf; bool found; switch (s.calibrationPattern) // Find feature points on the input format { case Settings::CHESSBOARD: found = findChessboardCorners(view, s.boardSize, pointBuf, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FAST_CHECK | CALIB_CB_NORMALIZE_IMAGE); break; case Settings::CIRCLES_GRID: found = findCirclesGrid(view, s.boardSize, pointBuf); break; case Settings::ASYMMETRIC_CIRCLES_GRID: found = findCirclesGrid(view, s.boardSize, pointBuf, CALIB_CB_ASYMMETRIC_GRID); break; default: found = false; break; } //! [find_pattern] //! [pattern_found] if (found) // If done with success, { // improve the found corners' coordinate accuracy for chessboard if (s.calibrationPattern == Settings::CHESSBOARD) { Mat viewGray; cvtColor(view, viewGray, COLOR_BGR2GRAY); cornerSubPix(viewGray, pointBuf, Size(11, 11), Size(-1, -1), TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1)); } if (mode == CAPTURING && // For camera only take new samples after delay time (!s.inputCapture.isOpened() || clock() - prevTimestamp > s.delay*1e-3*CLOCKS_PER_SEC)) { imagePoints.push_back(pointBuf); prevTimestamp = clock(); blinkOutput = s.inputCapture.isOpened(); } // Draw the corners. drawChessboardCorners(view, s.boardSize, Mat(pointBuf), found); } //! [pattern_found] //----------------------------- Output Text ------------------------------------------------ //! [output_text] string msg = (mode == CAPTURING) ? "100/100" : mode == CALIBRATED ? "Calibrated" : "Press 'g' to start"; int baseLine = 0; Size textSize = getTextSize(msg, 1, 1, 1, &baseLine); Point textOrigin(view.cols - 2 * textSize.width - 10, view.rows - 2 * baseLine - 10); if (mode == CAPTURING) { if (s.showUndistorsed) msg = format("%d/%d Undist", (int)imagePoints.size(), s.nrFrames); else msg = format("%d/%d", (int)imagePoints.size(), s.nrFrames); } putText(view, msg, textOrigin, 1, 1, mode == CALIBRATED ? GREEN : RED); if (blinkOutput) bitwise_not(view, view); //! [output_text] //------------------------- Video capture output undistorted ------------------------------ //! [output_undistorted] if (mode == CALIBRATED && s.showUndistorsed) { Mat temp = view.clone(); undistort(temp, view, cameraMatrix, distCoeffs); } //! [output_undistorted] //------------------------------ Show image and check for input commands ------------------- //! [await_input] namedWindow("Image View" + to_string(counter), WINDOW_NORMAL); resizeWindow("Image View" + to_string(counter), 640, 480); imshow("Image View" + to_string(counter), view); char key = (char)waitKey(s.inputCapture.isOpened() ? 50 : s.delay); cout << "Image " << to_string(counter) << " Completed" << endl; counter++; if (key == ESC_KEY) break; if (key == 'u' && mode == CALIBRATED) s.showUndistorsed = !s.showUndistorsed; if (s.inputCapture.isOpened() && key == 'g') { mode = CAPTURING; imagePoints.clear(); } //! [await_input] } // -----------------------Show the undistorted image for the image list ------------------------ //! [show_results] if (s.inputType == Settings::IMAGE_LIST && s.showUndistorsed) { Mat view, rview, map1, map2; initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(), getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, imageSize, 0), imageSize, CV_16SC2, map1, map2); m_mainMap1 = map1; m_mainMap2 = map2; for (size_t i = 0; i < s.imageList.size(); i++) { view = imread(s.imageList[i], 1); if (view.empty()) continue; remap(view, rview, map1, map2, INTER_LINEAR); imshow("Image View", rview); char c = (char)waitKey(); if (c == ESC_KEY || c == 'q' || c == 'Q') break; } } //! [show_results] // return 0; }