二 ubuntu下Opencv的相機標定
一般直接用Opencv的源碼就可以進行相機的標定,但是可能只是會實現結果,卻不懂實現的過程,我也是模模糊糊的看了《計算機視覺中的多視圖幾何》以及實現一些經典的算法,對Opencv有一些了解才開始做相機的標定,可以先看看源碼:

#include <iostream> #include <sstream> #include <time.h> #include <stdio.h> #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/calib3d/calib3d.hpp> #include <opencv2/highgui/highgui.hpp> #ifndef _CRT_SECURE_NO_WARNINGS # define _CRT_SECURE_NO_WARNINGS #endif using namespace cv; using namespace std; static void help() { cout << "This is a camera calibration sample." << endl << "Usage: calibration configurationFile" << endl << "Near the sample file you'll find the configuration file, which has detailed help of " "how to edit it. It may be any OpenCV supported file format XML/YAML." << endl; } class Settings { public: Settings() : goodInput(false) {} enum Pattern { NOT_EXISTING, CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID }; enum InputType {INVALID, CAMERA, VIDEO_FILE, IMAGE_LIST}; void write(FileStorage& fs) const //Write serialization for this class { fs << "{" << "BoardSize_Width" << boardSize.width << "BoardSize_Height" << boardSize.height << "Square_Size" << squareSize << "Calibrate_Pattern" << patternToUse << "Calibrate_NrOfFrameToUse" << nrFrames << "Calibrate_FixAspectRatio" << aspectRatio << "Calibrate_AssumeZeroTangentialDistortion" << calibZeroTangentDist << "Calibrate_FixPrincipalPointAtTheCenter" << calibFixPrincipalPoint << "Write_DetectedFeaturePoints" << bwritePoints << "Write_extrinsicParameters" << bwriteExtrinsics << "Write_outputFileName" << outputFileName << "Show_UndistortedImage" << showUndistorsed << "Input_FlipAroundHorizontalAxis" << flipVertical << "Input_Delay" << delay << "Input" << input << "}"; } void read(const FileNode& node) //Read serialization for this class { node["BoardSize_Width" ] >> boardSize.width; node["BoardSize_Height"] >> boardSize.height; node["Calibrate_Pattern"] >> patternToUse; node["Square_Size"] >> squareSize; node["Calibrate_NrOfFrameToUse"] >> nrFrames; node["Calibrate_FixAspectRatio"] >> aspectRatio; node["Write_DetectedFeaturePoints"] >> bwritePoints; node["Write_extrinsicParameters"] >> bwriteExtrinsics; node["Write_outputFileName"] >> outputFileName; node["Calibrate_AssumeZeroTangentialDistortion"] >> calibZeroTangentDist; node["Calibrate_FixPrincipalPointAtTheCenter"] >> calibFixPrincipalPoint; node["Input_FlipAroundHorizontalAxis"] >> flipVertical; node["Show_UndistortedImage"] >> showUndistorsed; node["Input"] >> input; node["Input_Delay"] >> delay; interprate(); } void interprate() { goodInput = true; if (boardSize.width <= 0 || boardSize.height <= 0) { cerr << "Invalid Board size: " << boardSize.width << " " << boardSize.height << endl; goodInput = false; } if (squareSize <= 10e-6) { cerr << "Invalid square size " << squareSize << endl; goodInput = false; } if (nrFrames <= 0) { cerr << "Invalid number of frames " << nrFrames << endl; goodInput = false; } if (input.empty()) // Check for valid input inputType = INVALID; else { if (input[0] >= '0' && input[0] <= '9') { stringstream ss(input); ss >> cameraID; inputType = CAMERA; } else { if (readStringList(input, imageList)) { inputType = IMAGE_LIST; nrFrames = (nrFrames < (int)imageList.size()) ? nrFrames : (int)imageList.size(); } else inputType = VIDEO_FILE; } if (inputType == CAMERA) inputCapture.open(cameraID); if (inputType == VIDEO_FILE) inputCapture.open(input); if (inputType != IMAGE_LIST && !inputCapture.isOpened()) inputType = INVALID; } if (inputType == INVALID) { cerr << " Inexistent input: " << input; goodInput = false; } flag = 0; if(calibFixPrincipalPoint) flag |= CV_CALIB_FIX_PRINCIPAL_POINT; if(calibZeroTangentDist) flag |= CV_CALIB_ZERO_TANGENT_DIST; if(aspectRatio) flag |= CV_CALIB_FIX_ASPECT_RATIO; calibrationPattern = NOT_EXISTING; if (!patternToUse.compare("CHESSBOARD")) calibrationPattern = CHESSBOARD; if (!patternToUse.compare("CIRCLES_GRID")) calibrationPattern = CIRCLES_GRID; if (!patternToUse.compare("ASYMMETRIC_CIRCLES_GRID")) calibrationPattern = ASYMMETRIC_CIRCLES_GRID; if (calibrationPattern == NOT_EXISTING) { cerr << " Inexistent camera calibration mode: " << patternToUse << endl; goodInput = false; } atImageList = 0; } Mat nextImage() { Mat result; if( inputCapture.isOpened() ) { Mat view0; inputCapture >> view0; view0.copyTo(result); } else if( atImageList < (int)imageList.size() ) result = imread(imageList[atImageList++], CV_LOAD_IMAGE_COLOR); return result; } static bool readStringList( const string& filename, vector<string>& l ) { l.clear(); FileStorage fs(filename, FileStorage::READ); if( !fs.isOpened() ) return false; FileNode n = fs.getFirstTopLevelNode(); if( n.type() != FileNode::SEQ ) return false; FileNodeIterator it = n.begin(), it_end = n.end(); for( ; it != it_end; ++it ) l.push_back((string)*it); return true; } public: Size boardSize; // The size of the board -> Number of items by width and height Pattern calibrationPattern;// One of the Chessboard, circles, or asymmetric circle pattern float squareSize; // The size of a square in your defined unit (point, millimeter,etc). int nrFrames; // The number of frames to use from the input for calibration float aspectRatio; // The aspect ratio int delay; // In case of a video input bool bwritePoints; // Write detected feature points bool bwriteExtrinsics; // Write extrinsic parameters bool calibZeroTangentDist; // Assume zero tangential distortion bool calibFixPrincipalPoint;// Fix the principal point at the center bool flipVertical; // Flip the captured images around the horizontal axis string outputFileName; // The name of the file where to write bool showUndistorsed; // Show undistorted images after calibration string input; // The input -> int cameraID; vector<string> imageList; int atImageList; VideoCapture inputCapture; InputType inputType; bool goodInput; int flag; private: string patternToUse; }; static void read(const FileNode& node, Settings& x, const Settings& default_value = Settings()) { if(node.empty()) x = default_value; else x.read(node); } enum { DETECTION = 0, CAPTURING = 1, CALIBRATED = 2 }; bool runCalibrationAndSave(Settings& s, Size imageSize, Mat& cameraMatrix, Mat& distCoeffs, vector<vector<Point2f> > imagePoints ); int main(int argc, char* argv[]) { help(); Settings s; const string inputSettingsFile = argc > 1 ? argv[1] : "default.xml"; 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 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; 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(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, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FAST_CHECK | CV_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( CV_TERMCRIT_EPS+CV_TERMCRIT_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(); } // 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; } } return 0; } static double computeReprojectionErrors( const vector<vector<Point3f> >& objectPoints, const vector<vector<Point2f> >& imagePoints, const vector<Mat>& rvecs, const vector<Mat>& tvecs, const Mat& cameraMatrix , const Mat& distCoeffs, vector<float>& perViewErrors) { vector<Point2f> imagePoints2; int i, totalPoints = 0; double totalErr = 0, err; perViewErrors.resize(objectPoints.size()); for( i = 0; i < (int)objectPoints.size(); ++i ) { projectPoints( Mat(objectPoints[i]), rvecs[i], tvecs[i], cameraMatrix, distCoeffs, imagePoints2); err = norm(Mat(imagePoints[i]), Mat(imagePoints2), CV_L2); int n = (int)objectPoints[i].size(); perViewErrors[i] = (float) std::sqrt(err*err/n); totalErr += err*err; totalPoints += n; } return std::sqrt(totalErr/totalPoints); } static void calcBoardCornerPositions(Size boardSize, float squareSize, vector<Point3f>& corners, Settings::Pattern patternType /*= Settings::CHESSBOARD*/) { corners.clear(); switch(patternType) { case Settings::CHESSBOARD: case Settings::CIRCLES_GRID: for( int i = 0; i < boardSize.height; ++i ) for( int j = 0; j < boardSize.width; ++j ) corners.push_back(Point3f(float( j*squareSize ), float( i*squareSize ), 0)); break; case Settings::ASYMMETRIC_CIRCLES_GRID: for( int i = 0; i < boardSize.height; i++ ) for( int j = 0; j < boardSize.width; j++ ) corners.push_back(Point3f(float((2*j + i % 2)*squareSize), float(i*squareSize), 0)); break; default: break; } } static bool runCalibration( Settings& s, Size& imageSize, Mat& cameraMatrix, Mat& distCoeffs, vector<vector<Point2f> > imagePoints, vector<Mat>& rvecs, vector<Mat>& tvecs, vector<float>& reprojErrs, double& totalAvgErr) { cameraMatrix = Mat::eye(3, 3, CV_64F); if( s.flag & CV_CALIB_FIX_ASPECT_RATIO ) cameraMatrix.at<double>(0,0) = 1.0; distCoeffs = Mat::zeros(8, 1, CV_64F); vector<vector<Point3f> > objectPoints(1); calcBoardCornerPositions(s.boardSize, s.squareSize, objectPoints[0], s.calibrationPattern); objectPoints.resize(imagePoints.size(),objectPoints[0]); //Find intrinsic and extrinsic camera parameters double rms = calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, s.flag|CV_CALIB_FIX_K4|CV_CALIB_FIX_K5); cout << "Re-projection error reported by calibrateCamera: "<< rms << endl; bool ok = checkRange(cameraMatrix) && checkRange(distCoeffs); totalAvgErr = computeReprojectionErrors(objectPoints, imagePoints, rvecs, tvecs, cameraMatrix, distCoeffs, reprojErrs); return ok; } // Print camera parameters to the output file static void saveCameraParams( Settings& s, Size& imageSize, Mat& cameraMatrix, Mat& distCoeffs, const vector<Mat>& rvecs, const vector<Mat>& tvecs, const vector<float>& reprojErrs, const vector<vector<Point2f> >& imagePoints, double totalAvgErr ) { FileStorage fs( s.outputFileName, FileStorage::WRITE ); time_t tm; time( &tm ); struct tm *t2 = localtime( &tm ); char buf[1024]; strftime( buf, sizeof(buf)-1, "%c", t2 ); fs << "calibration_Time" << buf; if( !rvecs.empty() || !reprojErrs.empty() ) fs << "nrOfFrames" << (int)std::max(rvecs.size(), reprojErrs.size()); fs << "image_Width" << imageSize.width; fs << "image_Height" << imageSize.height; fs << "board_Width" << s.boardSize.width; fs << "board_Height" << s.boardSize.height; fs << "square_Size" << s.squareSize; if( s.flag & CV_CALIB_FIX_ASPECT_RATIO ) fs << "FixAspectRatio" << s.aspectRatio; if( s.flag ) { sprintf( buf, "flags: %s%s%s%s", s.flag & CV_CALIB_USE_INTRINSIC_GUESS ? " +use_intrinsic_guess" : "", s.flag & CV_CALIB_FIX_ASPECT_RATIO ? " +fix_aspectRatio" : "", s.flag & CV_CALIB_FIX_PRINCIPAL_POINT ? " +fix_principal_point" : "", s.flag & CV_CALIB_ZERO_TANGENT_DIST ? " +zero_tangent_dist" : "" ); cvWriteComment( *fs, buf, 0 ); } fs << "flagValue" << s.flag; fs << "Camera_Matrix" << cameraMatrix; fs << "Distortion_Coefficients" << distCoeffs; fs << "Avg_Reprojection_Error" << totalAvgErr; if( !reprojErrs.empty() ) fs << "Per_View_Reprojection_Errors" << Mat(reprojErrs); if( !rvecs.empty() && !tvecs.empty() ) { CV_Assert(rvecs[0].type() == tvecs[0].type()); Mat bigmat((int)rvecs.size(), 6, rvecs[0].type()); for( int i = 0; i < (int)rvecs.size(); i++ ) { Mat r = bigmat(Range(i, i+1), Range(0,3)); Mat t = bigmat(Range(i, i+1), Range(3,6)); CV_Assert(rvecs[i].rows == 3 && rvecs[i].cols == 1); CV_Assert(tvecs[i].rows == 3 && tvecs[i].cols == 1); //*.t() is MatExpr (not Mat) so we can use assignment operator r = rvecs[i].t(); t = tvecs[i].t(); } cvWriteComment( *fs, "a set of 6-tuples (rotation vector + translation vector) for each view", 0 ); fs << "Extrinsic_Parameters" << bigmat; } if( !imagePoints.empty() ) { Mat imagePtMat((int)imagePoints.size(), (int)imagePoints[0].size(), CV_32FC2); for( int i = 0; i < (int)imagePoints.size(); i++ ) { Mat r = imagePtMat.row(i).reshape(2, imagePtMat.cols); Mat imgpti(imagePoints[i]); imgpti.copyTo(r); } fs << "Image_points" << imagePtMat; } } bool runCalibrationAndSave(Settings& s, Size imageSize, Mat& cameraMatrix, Mat& distCoeffs,vector<vector<Point2f> > imagePoints ) { vector<Mat> rvecs, tvecs; vector<float> reprojErrs; double totalAvgErr = 0; bool ok = runCalibration(s,imageSize, cameraMatrix, distCoeffs, imagePoints, rvecs, tvecs, reprojErrs, totalAvgErr); cout << (ok ? "Calibration succeeded" : "Calibration failed") << ". avg re projection error = " << totalAvgErr ; if( ok ) saveCameraParams( s, imageSize, cameraMatrix, distCoeffs, rvecs ,tvecs, reprojErrs, imagePoints, totalAvgErr); return ok; }
網上有很多關於相機標定的代碼,但都是沒有官方網站的源文件更詳細,給源文件同時寫一個Makefile文件
#Makefile for camera_calibrateion EXE =camera_calibration OBJS += camera_calibration.o CC = g++ CFLAGS += -g -O3 -Wall INC += -I. `pkg-config --cflags opencv` LIBS += `pkg-config --libs opencv` all:$(EXE) $(EXE):$(OBJS) $(CC) $(INC) $(CFLAGS) $(OBJS) -o $(EXE) $(LIBS) $(OBJS):%.o:%.cpp $(CC) $(INC) $(CFLAGS) -c $< -o $@ .PHONY:clean clean: rm -r *.o $(EXE)
然后make一下就會生成可執行文件,那么同時還要有一個配置文件 .xml 要在同一個目錄文件下,原文件提供了三種方式進行標定,
(1) 直接輸入攝像頭信息
(2)采用已經采集好的多照不同位置的標定模板
(3 )使用采集下的視頻流文件
那么我這里只做了(1) (2)並且標定不同的攝像頭
(1)采用攝像頭的輸入方式的mycamera.xml 代碼如下:(同時要在camera_calibration.cpp文件里更改讀取的.xml文件)
(這里的標定模板我是用A3紙張打印出來,為8*6 35mm的標定棋盤)
<?xml version="1.0"?> <opencv_storage> <!--設置標定參數--> <Settings> <!-- Number of inner corners per a item row and column. 寬度和高度的設置(square, circle) --> <BoardSize_Width> 8</BoardSize_Width> <BoardSize_Height>6</BoardSize_Height> <!-- The size of a square in some user defined metric system 每個方格的邊長的長度單位一般是mm(pixel, millimeter)--> <Square_Size>35</Square_Size> <!-- The type of input used for camera calibration. 標定模板的樣式(棋盤) 這里一共有三種模板One of: CHESSBOARD CIRCLES_GRID ASYMMETRIC_CIRCLES_GRID --> <Calibrate_Pattern>"CHESSBOARD"</Calibrate_Pattern> <!-- The input to use for calibration. To use an input camera -> give the ID of the camera, like "1" To use an input video -> give the path of the input video, like "/tmp/x.avi" To use an image list -> give the path to the XML or YAML file containing the list of the images, like "/tmp/circles_list.xml" 輸入標定模板的方式有三種方式:攝像頭輸入;視頻輸入;照片文件流輸入--> <Input>"1"</Input> <!-- If true (non-zero) we flip the input images around the horizontal axis. 如果為真(非零),安照垂直方向翻轉輸入圖像,這里選擇為零,即不翻轉--> <Input_FlipAroundHorizontalAxis>0</Input_FlipAroundHorizontalAxis> <!-- Time delay between frames in case of camera.在使用相機的情況下的幀之間的時間延遲 --> <Input_Delay>100</Input_Delay> <!-- How many frames to use, for calibration.用多少幀照片去校准,可以自己設置,一般不能低於20個 --> <Calibrate_NrOfFrameToUse>25</Calibrate_NrOfFrameToUse> <!-- Consider only fy as a free parameter, the ratio fx/fy stays the same as in the input cameraMatrix. Use or not setting. 0 - False Non-Zero - True 假設fy是一個自由參數,而fx/fy是一個固定的比例參數,使用或者不設置 0 假 非零 真--> <Calibrate_FixAspectRatio> 1 </Calibrate_FixAspectRatio> <!-- If true (non-zero) tangential distortion coefficients are set to zeros and stay zero. 如果設置為真,表示切向畸變系數被設置為0 保持為零--> <Calibrate_AssumeZeroTangentialDistortion>1</Calibrate_AssumeZeroTangentialDistortion> <!-- If true (non-zero) the principal point(攝像機坐標系下真實的坐標原點) is not changed during the global optimization.--> <Calibrate_FixPrincipalPointAtTheCenter> 1 </Calibrate_FixPrincipalPointAtTheCenter> <!-- The name of the output log file. 輸出文件的名稱--> <Write_outputFileName>"out_camera_data.xml"</Write_outputFileName> <!-- If true (non-zero) we write to the output file the feature points.(如果為真我們向輸出文件寫入特征點)--> <Write_DetectedFeaturePoints>1</Write_DetectedFeaturePoints> <!-- If true (non-zero) we write to the output file the extrinsic camera parameters.(寫入相機的外部參數)--> <Write_extrinsicParameters>1</Write_extrinsicParameters> <!-- If true (non-zero) we show after calibration the undistorted images.展示校准后不失真的照片--> <Show_UndistortedImage>1</Show_UndistortedImage> </Settings> </opencv_storage>
里面的漢字是我寫的標注,其中有幾個地方需要修改的與我們的實際標定模板一致
<BoardSize_Width> 8</BoardSize_Width> :表示標定模板的寬度 實際一共有9個黑白方格
<BoardSize_Height>6</BoardSize_Height> :實際有7個黑白方格
<Calibrate_Pattern>"CHESSBOARD"</Calibrate_Pattern> :選擇棋盤形式,一共有 CHESSBOARD ,CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID三種
<Square_Size>35</Square_Size> :每個黑白方格的邊長35mm(根據實際情況)
<Input>"1"</Input> :選擇標定模板的輸入種類 1. To use an input camera -> give the ID of the camera, like "1"
2. To use an input video -> give the path of the input video, like "/tmp/x.avi"
3. To use an image list -> give the path to the XML or YAML file containing the list of the images, <Write_outputFileName>"out_camera_data.xml"</Write_outputFileName>
<Write_outputFileName>"out_camera_data.xml"</Write_outputFileName> :表示標定輸出文件
運行文件夾下運行./camera_calibration 會啟動攝像頭,然后選擇“g”開始標定 ,但是如果上面的這些參數沒有設置的與實際相符合,是不會開始采集標定模板的,(我剛開始就出現了這個錯誤,所以一定亞設置與實際的標定模板一致)
就會開始采集25個不同角度和位置的標定模板,如下圖:
注意(我這樣直接拿着標定模板來標定是不正確的,應該用一個平面模板把標定模板固定住,這樣的標定的結果才是更加准確的,因為這樣只是做實驗,)
每采集成功一次就會變為二圖,顏色略有變化,采集完成就會自動開始校准如下:
此時在工程文件夾下就會生成out_camera_data.xml,就是相機的標定結果報告
(2)使用Opencv 提供的標定模板進行標定
我們只需要更改
<BoardSize_Width> 8</BoardSize_Width> 改為 <BoardSize_Width> 6</BoardSize_Width> <BoardSize_Height>6</BoardSize_Height> 改為 <BoardSize_Height>4</BoardSize_Height>
<Square_Size>35</Square_Size> 改為 <Square_Size108</Square_Size>
<Input>"1"</Input> 改為 <Input>"/home/salm/myopencv/calibrate/VID.xml"</Input>
這里就是指定了另一個.xml文件,就是標定模板的圖片,其中VID.xml內容為:
<?xml version="1.0"?> <opencv_storage> <images> /home/salm/myopencv/images/chessboards/chessboard01.jpg /home/salm/myopencv/images/chessboards/chessboard02.jpg /home/salm/myopencv/images/chessboards/chessboard03.jpg /home/salm/myopencv/images/chessboards/chessboard04.jpg /home/salm/myopencv/images/chessboards/chessboard05.jpg /home/salm/myopencv/images/chessboards/chessboard06.jpg /home/salm/myopencv/images/chessboards/chessboard07.jpg /home/salm/myopencv/images/chessboards/chessboard08.jpg /home/salm/myopencv/images/chessboards/chessboard09.jpg /home/salm/myopencv/images/chessboards/chessboard10.jpg /home/salm/myopencv/images/chessboards/chessboard11.jpg /home/salm/myopencv/images/chessboards/chessboard12.jpg /home/salm/myopencv/images/chessboards/chessboard13.jpg /home/salm/myopencv/images/chessboards/chessboard14.jpg /home/salm/myopencv/images/chessboards/chessboard15.jpg /home/salm/myopencv/images/chessboards/chessboard16.jpg /home/salm/myopencv/images/chessboards/chessboard17.jpg /home/salm/myopencv/images/chessboards/chessboard18.jpg /home/salm/myopencv/images/chessboards/chessboard19.jpg /home/salm/myopencv/images/chessboards/chessboard20.jpg /home/salm/myopencv/images/chessboards/chessboard21.jpg /home/salm/myopencv/images/chessboards/chessboard22.jpg /home/salm/myopencv/images/chessboards/chessboard23.jpg /home/salm/myopencv/images/chessboards/chessboard24.jpg /home/salm/myopencv/images/chessboards/chessboard25.jpg </images> </opencv_storage>
運行文件夾下運行./camera_calibration 會啟動VID.xml文件下的圖片,這是標定過程中的截圖文件 如圖
此時在工程文件夾下就會生成out_camera_data.xml
后續還有其他相關的只是待我學習完了再寫出來,只是為了記錄我的實驗過程,如果能有人從中獲取幫助,那就更好了
(如果很不幸,被大神們看見了,就直接嗤之以鼻吧,因為沒有什么創新的東西,謝謝)
如果您覺得看完有所收獲,可以資助一分,幾分money,不在乎多少(我也是跟網上的大神們學的),不想掙錢娶媳婦的程序員不是好程序員(同時我也看看到底有沒有人認可),謝謝
版權所有,轉載請注明出處 http://www.cnblogs.com/li-yao7758258/p/5933653.html