相机标定
文章目录
1、相机模型
相机模型 | 适用相机范围 | 标定具体参数 | 参考论文(代码) |
---|---|---|---|
pinhole(针孔相机模型) | FOV<180度 | fx,fy,cx,cy | https://docs.opencv.org/4.5.0/d4/d94/tutorial_camera_calibration.html |
Kannala-Brandt | 鱼眼镜头相机以及常规和广角镜头相机的通用相机模型 | 六个参数和八个参数的 | A Generic Camera Model and Calibration Method for Conventional,Wide-Angle, and Fish-Eye Lenses |
mei | 单视角全向相机 | 五个参数 | Single View Point Omnidirectional Camera Calibration from Planar Grids |
Double Sphere(DS) | 鱼眼相机 | 六个参数 | The Double Sphere Camera Modelhttps://vision.in.tum.de/research/vslam/double-sphere |
scaramuzza | 全向相机 | https://sites.google.com/site/scarabotix/ocamcalib-toolbox/ocamcalib-toolbox-download-page | |
improve_scaramuzza | 广角、鱼眼、全向相机 | Improved Wide-Angle, Fisheye and Omnidirectional Camera Calibrationhttps://github.com/urbste/ImprovedOcamCalib |
2、相机标定评测
相机标定评测主要通过两种办法来评估:定性评估,定量评估。
定量评估:重投影误差,计算时间。
定性评估:校正前的图像与校正后的图像对比。
2.1 内参标定程序解读
intrinsic_calib.cc
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
#include <iomanip>
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "camodocal/calib/CameraCalibration.h"
#include "camodocal/chessboard/Chessboard.h"
#include "camodocal/gpl/gpl.h"
int main( int argc, char** argv )
{
cv::Size boardSize;
float squareSize;
std::string inputDir;
std::string cameraModel;
std::string cameraName;
std::string prefix;
std::string fileExtension;
bool useOpenCV;
bool viewResults;
bool verbose;
//========= Handling Program options =========
// print help message
/***************************生成帮助信息******************************/
boost::program_options::options_description desc( "Allowed options" );
desc.add_options( )( "help", "produce help message" )(
"width,w",
boost::program_options::value< int >( &boardSize.width )->default_value( 8 ),
"Number of inner corners on the chessboard pattern in x direction" )(
"height,h",
boost::program_options::value< int >( &boardSize.height )->default_value( 12 ),
"Number of inner corners on the chessboard pattern in y direction" )(
"size,s",
boost::program_options::value< float >( &squareSize )->default_value( 7.f ),
"Size of one square in mm" )( "input,i",
boost::program_options::value< std::string >( &inputDir )->default_value( "calibration_desktop" ),
"Input directory containing chessboard images" )(
"prefix,p",
boost::program_options::value< std::string >( &prefix )->default_value( "frame" ),
"Prefix of images" )( "file-extension,e",
boost::program_options::value< std::string >( &fileExtension )->default_value( ".jpg" ),
"File extension of images" )(
"camera-model",
boost::program_options::value< std::string >( &cameraModel )->default_value( "mei" ),
"Camera model: kannala-brandt | mei | pinhole" )(
"camera-name",
boost::program_options::value< std::string >( &cameraName )->default_value( "camera" ),
"Name of camera" )( "opencv",
boost::program_options::bool_switch( &useOpenCV )->default_value( true ),
"Use OpenCV to detect corners" )(
"view-results",
boost::program_options::bool_switch( &viewResults )->default_value( false ),
"View results" )( "verbose,v",
boost::program_options::bool_switch( &verbose )->default_value( true ),
"Verbose output" );
boost::program_options::positional_options_description pdesc;
pdesc.add( "input", 1 );
boost::program_options::variables_map vm;
boost::program_options::store( boost::program_options::command_line_parser( argc, argv )
.options( desc )
.positional( pdesc )
.run( ),
vm );
boost::program_options::notify( vm );
/***************************生成帮助信息******************************/
// if open help,then print help message.
if ( vm.count( "help" ) )
{
std::cout << desc << std::endl;
return 1;
}
//check file whether exists
//检查文件是否存在
if ( !boost::filesystem::exists( inputDir ) && !boost::filesystem::is_directory( inputDir ) )
{
std::cerr << "# ERROR: Cannot find input directory " << inputDir << "." << std::endl;
return 1;
}
//support camera type
//支持相机模型
camodocal::Camera::ModelType modelType;
if ( boost::iequals( cameraModel, "kannala-brandt" ) )
{
modelType = camodocal::Camera::KANNALA_BRANDT;
}
else if ( boost::iequals( cameraModel, "mei" ) )
{
modelType = camodocal::Camera::MEI;
}
else if ( boost::iequals( cameraModel, "pinhole" ) )
{
modelType = camodocal::Camera::PINHOLE;
}
else if ( boost::iequals( cameraModel, "pinhole_full" ) )
{
modelType = camodocal::Camera::PINHOLE_FULL;
}
else if ( boost::iequals( cameraModel, "scaramuzza" ) )
{
modelType = camodocal::Camera::SCARAMUZZA;
}
else
{
std::cerr << "# ERROR: Unknown camera model: " << cameraModel << std::endl;
return 1;
}
/*********************************打印选择的模型*********************************/
switch ( modelType )
{
case camodocal::Camera::KANNALA_BRANDT:
std::cout << "# INFO: Camera model: Kannala-Brandt" << std::endl;
break;
case camodocal::Camera::MEI:
std::cout << "# INFO: Camera model: Mei" << std::endl;
break;
case camodocal::Camera::PINHOLE:
std::cout << "# INFO: Camera model: Pinhole" << std::endl;
break;
case camodocal::Camera::PINHOLE_FULL:
std::cout << "# INFO: Camera model: PinholeFull" << std::endl;
break;
case camodocal::Camera::SCARAMUZZA:
std::cout << "# INFO: Camera model: Scaramuzza-Omnidirect" << std::endl;
break;
}
/*********************************打印选择的模型*********************************/
// look for images in input directory
std::vector< std::string > imageFilenames;
boost::filesystem::directory_iterator itr;
for ( boost::filesystem::directory_iterator itr( inputDir );
itr != boost::filesystem::directory_iterator( );
++itr )
{
//判断文件的状态信息
if ( !boost::filesystem::is_regular_file( itr->status( ) ) )
{
continue;
}
std::string filename = itr->path( ).filename( ).string( );
// check if prefix matches
if ( !prefix.empty( ) )
{
if ( filena