摄像机该怎么标定,OpenCV告诉你,500行代码统统搞定。下面直接上代码,注释全在代码中,吧啦吧啦。。。
适用范围:摄像机在拍摄过程中焦距不变
标定数据源:拍摄对象为标定板的---- 多张无序照片 or 单个视频 or 摄像头实时输入
标定板类型:棋盘格 or 圆形阵列 or 环形阵列
调试环境:opencv2.4.6 + VS2010
大致流程:
1.读取配置文件
2.循环开始:获取一张照片,如果照片已足够则进行标定,保存标定结果,跳出循环。不够继续执行3,4步。
3.提取照片中keypoint位置,圆形阵列或环形阵列定位一次即可,单对于棋盘格分为初步定为和精确定位两个阶段
4.显示提取keypoint以后的照片,并标上当前的序号和标定状态。回到2开始下一次循环。
涉及文件:
camera_calibration.cpp:标定主程序
in_VID5.xml:作为输入的配置文件
VID5.xml:存有照片路径信息的文件
out_camera_data.yml:作为输出标定结果的文件
配置文件(in_VID5.xml)中的重要参数:
1.BoardSize_Width 和 BoardSize_Height分别表示横向,纵向棋盘格keypoint个数。
2.Square_Size:以毫米或者像素为单位的keypoint之间间隔距离
3.Calibrate_Pattern:可以设置为CHESSBOARD /CIRCLES_GRID /ASYMMETRIC_CIRCLES_GRID三种格式
4.Input:输入类型,摄像头实时捕捉直接输入摄像机编号(编号从0开始),视频文件直接写入文件名称。照片序列则写入存有照片序列信息的文件名称,这里是VID5.xml
5.Calibrate_NrOfFrameToUse:标定需要用到的图片数量,图片序列标定以实际图片数量为准。
输出文件(out_camera_data.yml)中的一些参数:
<Image_points type_id="opencv-matrix">
<rows>25</rows>
<cols>70</cols>
<dt>"2f"</dt> 这里的2f表示2维浮点数类型的数据
<data>
3.79758453e+002 2.20568024e+002 4.28894653e+002 2.21272049e+002
4.77973450e+002 2.21748367e+002 5.27806030e+002 2.21833710e+002
.
.
.
</data>
</Image_points>
详细注释见代码。。。
//使用opencv2.4.6中samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp
#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>
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_UndistortedIma