Path: blob/master/apps/interactive-calibration/calibController.cpp
16337 views
// This file is part of OpenCV project.1// It is subject to the license terms in the LICENSE file found in the top-level directory2// of this distribution and at http://opencv.org/license.html.34#include "calibController.hpp"56#include <algorithm>7#include <cmath>8#include <ctime>910#include <opencv2/calib3d.hpp>11#include <opencv2/imgproc.hpp>1213double calib::calibController::estimateCoverageQuality()14{15int gridSize = 10;16int xGridStep = mCalibData->imageSize.width / gridSize;17int yGridStep = mCalibData->imageSize.height / gridSize;18std::vector<int> pointsInCell(gridSize*gridSize);1920std::fill(pointsInCell.begin(), pointsInCell.end(), 0);2122for(std::vector<std::vector<cv::Point2f> >::iterator it = mCalibData->imagePoints.begin(); it != mCalibData->imagePoints.end(); ++it)23for(std::vector<cv::Point2f>::iterator pointIt = (*it).begin(); pointIt != (*it).end(); ++pointIt) {24int i = (int)((*pointIt).x / xGridStep);25int j = (int)((*pointIt).y / yGridStep);26pointsInCell[i*gridSize + j]++;27}2829for(std::vector<cv::Mat>::iterator it = mCalibData->allCharucoCorners.begin(); it != mCalibData->allCharucoCorners.end(); ++it)30for(int l = 0; l < (*it).size[0]; l++) {31int i = (int)((*it).at<float>(l, 0) / xGridStep);32int j = (int)((*it).at<float>(l, 1) / yGridStep);33pointsInCell[i*gridSize + j]++;34}3536cv::Mat mean, stdDev;37cv::meanStdDev(pointsInCell, mean, stdDev);3839return mean.at<double>(0) / (stdDev.at<double>(0) + 1e-7);40}4142calib::calibController::calibController()43{44mCalibFlags = 0;45}4647calib::calibController::calibController(cv::Ptr<calib::calibrationData> data, int initialFlags, bool autoTuning, int minFramesNum) :48mCalibData(data)49{50mCalibFlags = initialFlags;51mNeedTuning = autoTuning;52mMinFramesNum = minFramesNum;53mConfIntervalsState = false;54mCoverageQualityState = false;55}5657void calib::calibController::updateState()58{59if(mCalibData->cameraMatrix.total()) {60const double relErrEps = 0.05;61bool fConfState = false, cConfState = false, dConfState = true;62if(sigmaMult*mCalibData->stdDeviations.at<double>(0) / mCalibData->cameraMatrix.at<double>(0,0) < relErrEps &&63sigmaMult*mCalibData->stdDeviations.at<double>(1) / mCalibData->cameraMatrix.at<double>(1,1) < relErrEps)64fConfState = true;65if(sigmaMult*mCalibData->stdDeviations.at<double>(2) / mCalibData->cameraMatrix.at<double>(0,2) < relErrEps &&66sigmaMult*mCalibData->stdDeviations.at<double>(3) / mCalibData->cameraMatrix.at<double>(1,2) < relErrEps)67cConfState = true;6869for(int i = 0; i < 5; i++)70if(mCalibData->stdDeviations.at<double>(4+i) / fabs(mCalibData->distCoeffs.at<double>(i)) > 1)71dConfState = false;7273mConfIntervalsState = fConfState && cConfState && dConfState;74}7576if(getFramesNumberState())77mCoverageQualityState = estimateCoverageQuality() > 1.8 ? true : false;7879if (getFramesNumberState() && mNeedTuning) {80if( !(mCalibFlags & cv::CALIB_FIX_ASPECT_RATIO) &&81mCalibData->cameraMatrix.total()) {82double fDiff = fabs(mCalibData->cameraMatrix.at<double>(0,0) -83mCalibData->cameraMatrix.at<double>(1,1));8485if (fDiff < 3*mCalibData->stdDeviations.at<double>(0) &&86fDiff < 3*mCalibData->stdDeviations.at<double>(1)) {87mCalibFlags |= cv::CALIB_FIX_ASPECT_RATIO;88mCalibData->cameraMatrix.at<double>(0,0) =89mCalibData->cameraMatrix.at<double>(1,1);90}91}9293if(!(mCalibFlags & cv::CALIB_ZERO_TANGENT_DIST)) {94const double eps = 0.005;95if(fabs(mCalibData->distCoeffs.at<double>(2)) < eps &&96fabs(mCalibData->distCoeffs.at<double>(3)) < eps)97mCalibFlags |= cv::CALIB_ZERO_TANGENT_DIST;98}99100if(!(mCalibFlags & cv::CALIB_FIX_K1)) {101const double eps = 0.005;102if(fabs(mCalibData->distCoeffs.at<double>(0)) < eps)103mCalibFlags |= cv::CALIB_FIX_K1;104}105106if(!(mCalibFlags & cv::CALIB_FIX_K2)) {107const double eps = 0.005;108if(fabs(mCalibData->distCoeffs.at<double>(1)) < eps)109mCalibFlags |= cv::CALIB_FIX_K2;110}111112if(!(mCalibFlags & cv::CALIB_FIX_K3)) {113const double eps = 0.005;114if(fabs(mCalibData->distCoeffs.at<double>(4)) < eps)115mCalibFlags |= cv::CALIB_FIX_K3;116}117118}119}120121bool calib::calibController::getCommonCalibrationState() const122{123int rating = (int)getFramesNumberState() + (int)getConfidenceIntrervalsState() +124(int)getRMSState() + (int)mCoverageQualityState;125return rating == 4;126}127128bool calib::calibController::getFramesNumberState() const129{130return std::max(mCalibData->imagePoints.size(), mCalibData->allCharucoCorners.size()) > mMinFramesNum;131}132133bool calib::calibController::getConfidenceIntrervalsState() const134{135return mConfIntervalsState;136}137138bool calib::calibController::getRMSState() const139{140return mCalibData->totalAvgErr < 0.5;141}142143int calib::calibController::getNewFlags() const144{145return mCalibFlags;146}147148149//////////////////// calibDataController150151double calib::calibDataController::estimateGridSubsetQuality(size_t excludedIndex)152{153{154int gridSize = 10;155int xGridStep = mCalibData->imageSize.width / gridSize;156int yGridStep = mCalibData->imageSize.height / gridSize;157std::vector<int> pointsInCell(gridSize*gridSize);158159std::fill(pointsInCell.begin(), pointsInCell.end(), 0);160161for(size_t k = 0; k < mCalibData->imagePoints.size(); k++)162if(k != excludedIndex)163for(std::vector<cv::Point2f>::iterator pointIt = mCalibData->imagePoints[k].begin(); pointIt != mCalibData->imagePoints[k].end(); ++pointIt) {164int i = (int)((*pointIt).x / xGridStep);165int j = (int)((*pointIt).y / yGridStep);166pointsInCell[i*gridSize + j]++;167}168169for(size_t k = 0; k < mCalibData->allCharucoCorners.size(); k++)170if(k != excludedIndex)171for(int l = 0; l < mCalibData->allCharucoCorners[k].size[0]; l++) {172int i = (int)(mCalibData->allCharucoCorners[k].at<float>(l, 0) / xGridStep);173int j = (int)(mCalibData->allCharucoCorners[k].at<float>(l, 1) / yGridStep);174pointsInCell[i*gridSize + j]++;175}176177cv::Mat mean, stdDev;178cv::meanStdDev(pointsInCell, mean, stdDev);179180return mean.at<double>(0) / (stdDev.at<double>(0) + 1e-7);181}182}183184calib::calibDataController::calibDataController(cv::Ptr<calib::calibrationData> data, int maxFrames, double convParameter) :185mCalibData(data), mParamsFileName("CamParams.xml")186{187mMaxFramesNum = maxFrames;188mAlpha = convParameter;189}190191calib::calibDataController::calibDataController()192{193194}195196void calib::calibDataController::filterFrames()197{198size_t numberOfFrames = std::max(mCalibData->allCharucoIds.size(), mCalibData->imagePoints.size());199CV_Assert(numberOfFrames == mCalibData->perViewErrors.total());200if(numberOfFrames >= mMaxFramesNum) {201202double worstValue = -HUGE_VAL, maxQuality = estimateGridSubsetQuality(numberOfFrames);203size_t worstElemIndex = 0;204for(size_t i = 0; i < numberOfFrames; i++) {205double gridQDelta = estimateGridSubsetQuality(i) - maxQuality;206double currentValue = mCalibData->perViewErrors.at<double>((int)i)*mAlpha + gridQDelta*(1. - mAlpha);207if(currentValue > worstValue) {208worstValue = currentValue;209worstElemIndex = i;210}211}212showOverlayMessage(cv::format("Frame %zu is worst", worstElemIndex + 1));213214if(mCalibData->imagePoints.size()) {215mCalibData->imagePoints.erase(mCalibData->imagePoints.begin() + worstElemIndex);216mCalibData->objectPoints.erase(mCalibData->objectPoints.begin() + worstElemIndex);217}218else {219mCalibData->allCharucoCorners.erase(mCalibData->allCharucoCorners.begin() + worstElemIndex);220mCalibData->allCharucoIds.erase(mCalibData->allCharucoIds.begin() + worstElemIndex);221}222223cv::Mat newErrorsVec = cv::Mat((int)numberOfFrames - 1, 1, CV_64F);224std::copy(mCalibData->perViewErrors.ptr<double>(0),225mCalibData->perViewErrors.ptr<double>((int)worstElemIndex), newErrorsVec.ptr<double>(0));226if((int)worstElemIndex < (int)numberOfFrames-1) {227std::copy(mCalibData->perViewErrors.ptr<double>((int)worstElemIndex + 1), mCalibData->perViewErrors.ptr<double>((int)numberOfFrames),228newErrorsVec.ptr<double>((int)worstElemIndex));229}230mCalibData->perViewErrors = newErrorsVec;231}232}233234void calib::calibDataController::setParametersFileName(const std::string &name)235{236mParamsFileName = name;237}238239void calib::calibDataController::deleteLastFrame()240{241if( !mCalibData->imagePoints.empty()) {242mCalibData->imagePoints.pop_back();243mCalibData->objectPoints.pop_back();244}245246if (!mCalibData->allCharucoCorners.empty()) {247mCalibData->allCharucoCorners.pop_back();248mCalibData->allCharucoIds.pop_back();249}250251if(!mParamsStack.empty()) {252mCalibData->cameraMatrix = (mParamsStack.top()).cameraMatrix;253mCalibData->distCoeffs = (mParamsStack.top()).distCoeffs;254mCalibData->stdDeviations = (mParamsStack.top()).stdDeviations;255mCalibData->totalAvgErr = (mParamsStack.top()).avgError;256mParamsStack.pop();257}258}259260void calib::calibDataController::rememberCurrentParameters()261{262cv::Mat oldCameraMat, oldDistcoeefs, oldStdDevs;263mCalibData->cameraMatrix.copyTo(oldCameraMat);264mCalibData->distCoeffs.copyTo(oldDistcoeefs);265mCalibData->stdDeviations.copyTo(oldStdDevs);266mParamsStack.push(cameraParameters(oldCameraMat, oldDistcoeefs, oldStdDevs, mCalibData->totalAvgErr));267}268269void calib::calibDataController::deleteAllData()270{271mCalibData->imagePoints.clear();272mCalibData->objectPoints.clear();273mCalibData->allCharucoCorners.clear();274mCalibData->allCharucoIds.clear();275mCalibData->cameraMatrix = mCalibData->distCoeffs = cv::Mat();276mParamsStack = std::stack<cameraParameters>();277rememberCurrentParameters();278}279280bool calib::calibDataController::saveCurrentCameraParameters() const281{282bool success = false;283if(mCalibData->cameraMatrix.total()) {284cv::FileStorage parametersWriter(mParamsFileName, cv::FileStorage::WRITE);285if(parametersWriter.isOpened()) {286time_t rawtime;287time(&rawtime);288char buf[256];289strftime(buf, sizeof(buf)-1, "%c", localtime(&rawtime));290291parametersWriter << "calibrationDate" << buf;292parametersWriter << "framesCount" << std::max((int)mCalibData->objectPoints.size(), (int)mCalibData->allCharucoCorners.size());293parametersWriter << "cameraResolution" << mCalibData->imageSize;294parametersWriter << "cameraMatrix" << mCalibData->cameraMatrix;295parametersWriter << "cameraMatrix_std_dev" << mCalibData->stdDeviations.rowRange(cv::Range(0, 4));296parametersWriter << "dist_coeffs" << mCalibData->distCoeffs;297parametersWriter << "dist_coeffs_std_dev" << mCalibData->stdDeviations.rowRange(cv::Range(4, 9));298parametersWriter << "avg_reprojection_error" << mCalibData->totalAvgErr;299300parametersWriter.release();301success = true;302}303}304return success;305}306307void calib::calibDataController::printParametersToConsole(std::ostream &output) const308{309const char* border = "---------------------------------------------------";310output << border << std::endl;311output << "Frames used for calibration: " << std::max(mCalibData->objectPoints.size(), mCalibData->allCharucoCorners.size())312<< " \t RMS = " << mCalibData->totalAvgErr << std::endl;313if(mCalibData->cameraMatrix.at<double>(0,0) == mCalibData->cameraMatrix.at<double>(1,1))314output << "F = " << mCalibData->cameraMatrix.at<double>(1,1) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(1) << std::endl;315else316output << "Fx = " << mCalibData->cameraMatrix.at<double>(0,0) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(0) << " \t "317<< "Fy = " << mCalibData->cameraMatrix.at<double>(1,1) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(1) << std::endl;318output << "Cx = " << mCalibData->cameraMatrix.at<double>(0,2) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(2) << " \t"319<< "Cy = " << mCalibData->cameraMatrix.at<double>(1,2) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(3) << std::endl;320output << "K1 = " << mCalibData->distCoeffs.at<double>(0) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(4) << std::endl;321output << "K2 = " << mCalibData->distCoeffs.at<double>(1) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(5) << std::endl;322output << "K3 = " << mCalibData->distCoeffs.at<double>(4) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(8) << std::endl;323output << "TD1 = " << mCalibData->distCoeffs.at<double>(2) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(6) << std::endl;324output << "TD2 = " << mCalibData->distCoeffs.at<double>(3) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(7) << std::endl;325}326327void calib::calibDataController::updateUndistortMap()328{329cv::initUndistortRectifyMap(mCalibData->cameraMatrix, mCalibData->distCoeffs, cv::noArray(),330cv::getOptimalNewCameraMatrix(mCalibData->cameraMatrix, mCalibData->distCoeffs, mCalibData->imageSize, 0.0, mCalibData->imageSize),331mCalibData->imageSize, CV_16SC2, mCalibData->undistMap1, mCalibData->undistMap2);332333}334335336