<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-e2445db1a8.css">
<div class="htmledit_views">
1.摄像机成像原理
成像的过程实质上是4个坐标系的转换。首先空间中的一点由 世界坐标系 转换到 摄像机坐标系 ,然后再将其投影到成像平面 (图像物理坐标系 ) ,最后再将成像平面上的数据转换到图像平面 (图像像素坐标系 ) 。
下文对4个坐标系的 变换做了详细的解释:
http://blog.csdn.net/humanking7/article/details/44756073
2.畸变模型
(uOv坐标系)
下的无畸变坐标
(U, V)
,经过
径向畸变
和
切向畸变
后落在了
uOv坐标系
的
(Ud, Vd)
上。即就是说,
真实图像 imgR
与
畸变图像 imgD
之间的关系为:
imgR(U, V) = imgD(Ud, Vd)
OpenCV的document中介绍如下:
http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/calib3d/camera_calibration/camera_calibration.html#cameracalibrationopencv
所以标定的目标是就是确定这5个参数的值。
3.标定板
标定的最开始阶段最需要的肯定是标定板。可以直接从opencv官网上能下载到:
http://docs.opencv.org/2.4/_downloads/pattern.png
4.图像采集
5.标定
用OpenCV的例程来进行标定,在你的opencv目录下
sources\samples\cpp\tutorial_code\calib3d\camera_calibration
有3个文件 :
camera_calibration.cpp
VID5.xml
in_VID5.xml
第一个是标定程序的源代码。
第二个是配置文件,你可以更改标定图片获取的方式以及标定板的一些参数。
第三个里面可以修改标定图片序列的文件名。
-
#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 and save 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);
-
-
string imageName = format(
“undistorted_%d.jpg”, i);
-
imwrite(imageName,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;
-
}
下面是我的in_VID5.xml文件
-
<?xml version=“1.0”?>
-
<opencv_storage>
-
<Settings>
-
<!– Number of inner corners per a item row and column. (square, circle) –>
-
<BoardSize_Width> 9
</BoardSize_Width>
-
<BoardSize_Height>6
</BoardSize_Height>
-
-
<!– The size of a square in some user defined metric system (pixel, millimeter)–>
-
<Square_Size>50
</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>”E:/wangyuchi/code/calibration/VID5/VID5.xml”
</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. –>
-
<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–>
-
<Calibrate_FixAspectRatio> 1
</Calibrate_FixAspectRatio>
-
<!– If true (non-zero) tangential distortion coefficients are set to zeros and stay zero.–>
-
<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>
只修改了这一行,是VID5.xml的路径:
<Input>"E:/wangyuchi/code/calibration/VID5/VID5.xml"</Input>
我的VID5.xml文件:
-
<?xml version="1.0"?>
-
<opencv_storage>
-
<images>
-
E:/wangyuchi/code/calibration/VID5/2017.05.05/5.jpg
-
E:/wangyuchi/code/calibration/VID5/2017.05.05/6.jpg
-
E:/wangyuchi/code/calibration/VID5/2017.05.05/7.jpg
-
</images>
-
</opencv_storage>
E:/wangyuchi/code/calibration/VID5/2017.05.05/5.jpg E:/wangyuchi/code/calibration/VID5/2017.05.05/6.jpg E:/wangyuchi/code/calibration/VID5/2017.05.05/7.jpg
标定结果:
![](https://i-blog.csdnimg.cn/blog_migrate/17dcd7f947bd5969e0a1c8ee26ab548a.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/5aeac23222302472ae6f884fc53af932.jpeg)
6.校正
-
#include <opencv2/opencv.hpp>
-
#include <opencv2/calib3d/calib3d.hpp>
-
using
namespace
std;
-
using
namespace cv;
-
-
/**
-
* @主函数
-
*/
-
int main( int argc, char** argv )
-
{
-
-
/// 读取一副图片,不改变图片本身的颜色类型(该读取方式为DOS运行模式)
-
Mat src = imread( argv[
1],
1 );
-
Mat distortion = src.clone();
-
Mat camera_matrix = Mat(
3,
3, CV_32FC1);
-
Mat distortion_coefficients;
-
-
-
//导入相机内参和畸变系数矩阵
-
FileStorage file_storage(”out_camera_data.xml”, FileStorage::READ);
-
file_storage[
“Camera_Matrix”] >> camera_matrix;
-
file_storage[
“Distortion_Coefficients”] >> distortion_coefficients;
-
file_storage.release();
-
-
//矫正
-
undistort(src, distortion, camera_matrix, distortion_coefficients);
-
-
imshow(
“img”, src);
-
imshow(
“undistort”, distortion);
-
imwrite(
“undistort.jpg”, distortion);
-
-
waitKey(
0);
-
return
0;
-
}
7.参考
</div>
</div>