张正友驾校棋盘格的世界坐标怎是8个一组呢

张正友摄像机标定的研究(MATLAB+OpenCV)
张正友摄像机标定的研究(MATLAB+OpenCV)
张正友 本科浙大,现为微软高级工程师
张正友的主页:
/en-us/um/people/zhang/Calib/
不过里面的棋盘格跟我的不一样啊,why???,我决定先看看中文的论文吧,我的首要任务是弄清楚输入输出,流程,怎么用吧
matlab 跟 opencv上都有张正友的实现
matlab calibration主页 :
http://www.vision.caltech.edu/bouguetj/calib_doc/
GML C++ Camera Calibration Toolbox:
http://graphics.cs.msu.ru/en/science/research/calibration/cpp
因为cvCalibrateCamera2
函数主要是用张正友的平面标定方法的,所以首先我建议大家看一下张正友的那篇经典的论文
1) 完整版 22页 里面分析的非常详细《A Flexible New Technique for Camera
Calibration.rar》(/~zhang/Papers/TR98-71.pdf)
2) 精简版 8页《Flexible Camera Calibration by Viewing a Plane from
Unknown Orientations》 - Zhang, ICCV99,
(http://www.vision.caltech.edu/bouguetj/ ... zhan99.pdf)
&http://www./forum/viewtopic.php?t=4603
piao 在opencv论坛上的帖子
在OpenCV中用cvCalibrateCamera2进行相机标定(附程序)
看到论坛里有不少人在用OpenCV中的标定函数cvCalibrateCamera2
进行相机标定时遇到不少问题,说一些自己的看法。
1)因为cvCalibrateCamera2
函数主要是用张正友的平面标定方法的,所以首先我建议大家看一下张正友的那篇经典的论文
完整版 22页 里面分析的非常详细《A Flexible New Technique for Camera
Calibration.rar》(/~zhang/Papers/TR98-71.pdf)
精简版 8页《Flexible Camera Calibration by Viewing a Plane from
Unknown Orientations》 - Zhang, ICCV99,
(http://www.vision.caltech.edu/bouguetj/ ... zhan99.pdf)
2)至于不少人说OpenCV中用cvCalibrateCamera2
进行相机标定的精度差,标定结果不稳定,我想可能的原因有:
原因之一)可能是在标定的时候标定板所在平面与成像平面(image
plane)之间的夹角太小,张正友论文里的仿真数据(有噪声的数据)说明当两者夹角太小误差
从张正友的论文里给出的5幅图中(/~zhang/Calib/)其中标定平面与成像平面的夹角分别为:&
8.5 24.5 9.5829(单位:度)。
而且张正友的论文中也提到两幅标定板之间的位置平行放置的话,相关相当于一幅
因此在实际标定中平行放置的情况最好避免,可能有时你无形之中就犯了这
原因之二)标定时拍摄的图片太少,虽然张正友的论文里只用了5幅图片,但是我建议搞个10来幅左右还是必要的,因为我们实际中可能标定板用A4的纸打印出
来贴在一块板上的,标定板上的世界坐标精度就不是特别高,多拍摄几幅图像能减少这方面带来的误差,而且多个角度拍摄也可能解决了问题一:标定板和成像
平面夹角小的问题。这个家伙用20幅来标定(http://www.vision.caltech.edu/bouguetj/
... ample.html)
原因之三)图像上角点提取的不准确,我认为用cvFindChessboardCorners函数找角点不是很好,假如拍到的图像不是完整的棋盘格的时候肯定会有问题的,而
且也不少人反应用这个函数提取不出角点,建议可以用其他工具 比如:
OpenCV and MatLab Camera Calibration Toolboxes
Enhancement(http://graphics.cs.msu.ru/en/research/calibration/)
Camera Calibration Toolbox for
Matlab(http://www.vision.caltech.edu/bouguetj/calib_doc/htmls/example.html)★★★★★强烈推荐
当然还有可能其他人为的什么原因。
3)建议用其他方法比如Tsai的标定方法或其他的标定工具进行标定
★★★★★强烈推荐 用这个matlab标定工具箱来进行标定,可以和OpenCV做个对比嘛
,它也是基于张正友的平面标定方法的,做得非常人性化,呵呵,
有误差分析、标定结果三维重建、重投影计算角点等功能 。
Camera Calibration Toolbox for
Matlab(http://www.vision.caltech.edu/bouguetj/calib_doc/)
4)三个OpenCV下的标定程序
程序1)《基于OpenCV的计算机视觉技术实现》(/s_single.php?id=14881)这本书上的相机标定程序
(有标定图片 改下参数 可以直接运行)
&from《基于OpenCV的计算机视觉技术实现 》.rar
摄像机定标from《基于OpenCV的计算机视觉技术实现 》.rar
(525.67 KiB) 被下载 17063 次
程序2) 自己写的一个简单的标定程序:plane_calibration_opencv(要先准备好
角点的图像坐标和对应的世界坐标 )
download/file.php?id=284
程序3)http://www.主页上的例子
http://www./index.php?titl ... iant=zh-tw
程序4) &plane_calibration_opencv.rar
opencv+cvut 实现
/view/e88cc989d0d233d4b14e691c.html
单应性矩阵在摄像机标定时的作用
在计算机视觉中单应性矩阵的求解在摄像机标定的过程中有重要的意义,单应性矩阵中包含着摄像机的内参数矩阵,旋转向量和平移向量。
& 我们设3维空间有一点Q=[X Y Z 1]T(齐次坐标系表示),到成像仪上的q[x y
1]T映射,设单应性矩阵为H,s为比例系数。则Q和q之间的关系可表示为q=ShQ.
& 在点映射过程中,点要经过旋转和平移的物理变换,所以设物理变换坐标W=[R
T],R为旋转向量,T为平移向量。然后再投射过程中,根据得到的摄像机的内参矩阵M,所以q=sMWQ,从而推算出H=sMW.
通过单应性矩阵,我们把源图像平面上的点击位置与目标图像平面的伤的点击位置联系了起来,而opencv
中有一个函数提供了单应性矩阵的计算:cvFindHomography().而opencv中是采用从多个视场,采集图片,并计算相应的单应性矩阵,从而求解摄像机的内参数(内参数相对于摄像机的视场是不变的)。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。OpenCV(41)
使用Opencv实现张正友法相机标定之前,有几个问题事先要确认一下,那就是相机为什么需要标定,标定需要的输入和输出分别是哪些?
相机标定的目的:获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的选择和平移矩阵),内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像。
相机标定的输入:标定图像上所有内角点的图像坐标,标定板图像上所有内角点的空间三维坐标(一般情况下假定图像位于Z=0平面上)。
相机标定的输出:摄像机的内参、外参系数。
这三个基础的问题就决定了使用Opencv实现张正友法标定相机的标定流程、标定结果评价以及使用标定结果矫正原始图像的完整流程:
1. 准备标定图片
2. 对每一张标定图片,提取角点信息
3. 对每一张标定图片,进一步提取亚像素角点信息
4. 在棋盘标定图上绘制找到的内角点(非必须,仅为了显示)
5. 相机标定
6. 对标定结果进行评价
7. 查看标定效果——利用标定结果对棋盘图进行矫正
1. 准备标定图片
标定图片需要使用标定板在不同位置、不同角度、不同姿态下拍摄,最少需要3张,以10~20张为宜。标定板需要是黑白相间的矩形构成的棋盘图,制作精度要求较高,如下图所示:
2.对每一张标定图片,提取角点信息
需要使用findChessboardCorners函数提取角点,这里的角点专指的是标定板上的内角点,这些角点与标定板的边缘不接触。
&findChessboardCorners函数原型:
//! finds checkerboard pattern of the specified size in the image
CV_EXPORTS_W bool findChessboardCorners( InputArray image, Size patternSize,
OutputArray corners,
int flags=CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE );
第一个参数Image,传入拍摄的棋盘图Mat图像,必须是8位的灰度或者彩色图像;
第二个参数patternSize,每个棋盘图上内角点的行列数,一般情况下,行列数不要相同,便于后续标定程序识别标定板的方向;
第三个参数corners,用于存储检测到的内角点图像坐标位置,一般用元素是Point2f的向量来表示:vector&Point2f& image_points_
第四个参数flage:用于定义棋盘图上内角点查找的不同处理方式,有默认值。
3. 对每一张标定图片,进一步提取亚像素角点信息
为了提高标定精度,需要在初步提取的角点信息上进一步提取亚像素信息,降低相机标定偏差,常用的方法是cornerSubPix,另一个方法是使用find4QuadCornerSubpix函数,这个方法是专门用来获取棋盘图上内角点的精确位置的,或许在相机标定的这个特殊场合下它的检测精度会比cornerSubPix更高?
cornerSubPix函数原型:
//! adjusts the corner locations with sub-pixel accuracy to maximize the certain cornerness criteria
CV_EXPORTS_W void cornerSubPix( InputArray image, InputOutputArray corners,
Size winSize, Size zeroZone,
TermCriteria criteria );
第一个参数image,输入的Mat矩阵,最好是8位灰度图像,检测效率更高;
第二个参数corners,初始的角点坐标向量,同时作为亚像素坐标位置的输出,所以需要是浮点型数据,一般用元素是Pointf2f/Point2d的向量来表示:vector&Point2f/Point2d& iamgePointsBuf;
第三个参数winSize,大小为搜索窗口的一半;
第四个参数zeroZone,死区的一半尺寸,死区为不对搜索区的中央位置做求和运算的区域。它是用来避免自相关矩阵出现某些可能的奇异性。当值为(-1,-1)时表示没有死区;
第五个参数criteria,定义求角点的迭代过程的终止条件,可以为迭代次数和角点精度两者的组合;
find4QuadCornerSubpix函数原型:
//! finds subpixel-accurate positions of the chessboard corners
CV_EXPORTS bool find4QuadCornerSubpix(InputArray img, InputOutputArray corners, Size region_size);
第一个参数img,输入的Mat矩阵,最好是8位灰度图像,检测效率更高;
第二个参数corners,初始的角点坐标向量,同时作为亚像素坐标位置的输出,所以需要是浮点型数据,一般用元素是Pointf2f/Point2d的向量来表示:vector&Point2f/Point2d& iamgePointsBuf;
第三个参数region_size,角点搜索窗口的尺寸;
在其中一个标定的棋盘图上分别运行cornerSubPix和find4QuadCornerSubpix寻找亚像素角点,两者定位到的亚像素角点坐标分别为:
& &cornerSubPix: & & & & & & & & & & & & & & & & & & & & & & & &&find4QuadCornerSubpix:
& & & & & & & & & &
虽然有一定差距,但偏差基本都控制在0.5个像素之内。
4. 在棋盘标定图上绘制找到的内角点(非必须,仅为了显示)
drawChessboardCorners函数用于绘制被成功标定的角点,函数原型:
//! draws the checkerboard pattern (found or partly found) in the image
CV_EXPORTS_W void drawChessboardCorners( InputOutputArray image, Size patternSize,
InputArray corners, bool patternWasFound );
第一个参数image,8位灰度或者彩色图像;
第二个参数patternSize,每张标定棋盘上内角点的行列数;
第三个参数corners,初始的角点坐标向量,同时作为亚像素坐标位置的输出,所以需要是浮点型数据,一般用元素是Pointf2f/Point2d的向量来表示:vector&Point2f/Point2d&
iamgePointsBuf;
第四个参数patternWasFound,标志位,用来指示定义的棋盘内角点是否被完整的探测到,true表示别完整的探测到,函数会用直线依次连接所有的内角点,作为一个整体,false表示有未被探测到的内角点,这时候函数会以(红色)圆圈标记处检测到的内角点;
以下是drawChessboardCorners函数中第四个参数patternWasFound设置为true和false时内角点的绘制效果:
patternWasFound=ture时,依次连接各个内角点:
patternWasFound=false时,以(红色)圆圈标记处角点位置:
5. 相机标定
获取到棋盘标定图的内角点图像坐标之后,就可以使用calibrateCamera函数进行标定,计算相机内参和外参系数,
calibrateCamera函数原型:
//! finds intrinsic and extrinsic camera parameters from several fews of a known calibration pattern.
CV_EXPORTS_W double calibrateCamera( InputArrayOfArrays objectPoints,
InputArrayOfArrays imagePoints,
Size imageSize,
CV_OUT InputOutputArray cameraMatrix,
CV_OUT InputOutputArray distCoeffs,
OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
int flags=0, TermCriteria criteria = TermCriteria(
TermCriteria::COUNT+TermCriteria::EPS, 30, DBL_EPSILON) );
第一个参数objectPoints,为世界坐标系中的三维点。在使用时,应该输入一个三维坐标点的向量的向量,即vector&vector&Point3f&& object_points。需要依据棋盘上单个黑白矩阵的大小,计算出(初始化)每一个内角点的世界坐标。
第二个参数imagePoints,为每一个内角点对应的图像坐标点。和objectPoints一样,应该输入vector&vector&Point2f&& image_points_seq形式的变量;
第三个参数imageSize,为图像的像素尺寸大小,在计算相机的内参和畸变矩阵时需要使用到该参数;
第四个参数cameraMatrix为相机的内参矩阵。输入一个Mat cameraMatrix即可,如Mat cameraMatrix=Mat(3,3,CV_32FC1,Scalar::all(0));
第五个参数distCoeffs为畸变矩阵。输入一个Mat distCoeffs=Mat(1,5,CV_32FC1,Scalar::all(0))即可;
第六个参数rvecs为旋转向量;应该输入一个Mat类型的vector,即vector&Mat&
第七个参数tvecs为位移向量,和rvecs一样,应该为vector&Mat& tvecs;
第八个参数flags为标定时所采用的算法。有如下几个参数:
CV_CALIB_USE_INTRINSIC_GUESS:使用该参数时,在cameraMatrix矩阵中应该有fx,fy,u0,v0的估计值。否则的话,将初始化(u0,v0)图像的中心点,使用最小二乘估算出fx,fy。&
CV_CALIB_FIX_PRINCIPAL_POINT:在进行优化时会固定光轴点。当CV_CALIB_USE_INTRINSIC_GUESS参数被设置,光轴点将保持在中心或者某个输入的值。&
CV_CALIB_FIX_ASPECT_RATIO:固定fx/fy的比值,只将fy作为可变量,进行优化计算。当CV_CALIB_USE_INTRINSIC_GUESS没有被设置,fx和fy将会被忽略。只有fx/fy的比值在计算中会被用到。&
CV_CALIB_ZERO_TANGENT_DIST:设定切向畸变参数(p1,p2)为零。&
CV_CALIB_FIX_K1,…,CV_CALIB_FIX_K6:对应的径向畸变在优化中保持不变。&
CV_CALIB_RATIONAL_MODEL:计算k4,k5,k6三个畸变参数。如果没有设置,则只计算其它5个畸变参数。
第九个参数criteria是最优迭代终止条件设定。
在使用该函数进行标定运算之前,需要对棋盘上每一个内角点的空间坐标系的位置坐标进行初始化,标定的结果是生成相机的内参矩阵cameraMatrix、相机的5个畸变系数distCoeffs,另外每张图像都会生成属于自己的平移向量和旋转向量。
6. 对标定结果进行评价
对标定结果进行评价的方法是通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到空间三维点在图像上新的投影点的坐标,计算投影坐标和亚像素角点坐标之间的偏差,偏差越小,标定结果越好。
对空间三维坐标点进行反向投影的函数是projectPoints,函数原型是:
//! projects points from the model coordinate space to the image coordinates. Also computes derivatives of the image coordinates w.r.t the intrinsic and extrinsic camera parameters
CV_EXPORTS_W void projectPoints( InputArray objectPoints,
InputArray rvec, InputArray tvec,
InputArray cameraMatrix, InputArray distCoeffs,
OutputArray imagePoints,
OutputArray jacobian=noArray(),
double aspectRatio=0 );
第一个参数objectPoints,为相机坐标系中的三维点坐标;
第二个参数rvec为旋转向量,每一张图像都有自己的选择向量;
第三个参数tvec为位移向量,每一张图像都有自己的平移向量;
第四个参数cameraMatrix为求得的相机的内参数矩阵;
第五个参数distCoeffs为相机的畸变矩阵;
第六个参数iamgePoints为每一个内角点对应的图像上的坐标点;
第七个参数jacobian是雅可比行列式;
第八个参数aspectRatio是跟相机传感器的感光单元有关的可选参数,如果设置为非0,则函数默认感光单元的dx/dy是固定的,会依此对雅可比矩阵进行调整;
下边显示了某一张标定图片上的亚像素角点坐标和根据标定结果把空间三维坐标点映射回图像坐标点的对比:
find4QuadCornerSubpix查找到的亚像素点坐标: & & & & & & & & & & & & &&projectPoints映射的坐标:
& & & & & & && & & & & & & & & & & & & & & & & & &&&&
以下是每一幅图像上24个内角点的平均误差统计数据:
7. 查看标定效果——利用标定结果对棋盘图进行矫正
利用求得的相机的内参和外参数据,可以对图像进行畸变的矫正,这里有两种方法可以达到矫正的目的,分别说明一下。
方法一:使用initUndistortRectifyMap和remap两个函数配合实现。
initUndistortRectifyMap用来计算畸变映射,remap把求得的映射应用到图像上。
initUndistortRectifyMap的函数原型:
//! initializes maps for cv::remap() to correct lens distortion and optionally rectify the image
CV_EXPORTS_W void initUndistortRectifyMap( InputArray cameraMatrix, InputArray distCoeffs,
InputArray R, InputArray newCameraMatrix,
Size size, int m1type, OutputArray map1, OutputArray map2 );
第一个参数cameraMatrix为之前求得的相机的内参矩阵;
第二个参数distCoeffs为之前求得的相机畸变矩阵;
第三个参数R,可选的输入,是第一和第二相机坐标之间的旋转矩阵;
第四个参数newCameraMatrix,输入的校正后的3X3摄像机矩阵;
第五个参数size,摄像机采集的无失真的图像尺寸;
第六个参数m1type,定义map1的数据类型,可以是CV_32FC1或者CV_16SC2;
第七个参数map1和第八个参数map2,输出的X/Y坐标重映射参数;
remap函数原型:
//! warps the image using the precomputed maps. The maps are stored in either floating-point or integer fixed-point format
CV_EXPORTS_W void remap( InputArray src, OutputArray dst,
InputArray map1, InputArray map2,
int interpolation, int borderMode=BORDER_CONSTANT,
const Scalar& borderValue=Scalar());
第一个参数src,输入参数,代表畸变的原始图像;
第二个参数dst,矫正后的输出图像,跟输入图像具有相同的类型和大小;
第三个参数map1和第四个参数map2,X坐标和Y坐标的映射;
第五个参数interpolation,定义图像的插值方式;
第六个参数borderMode,定义边界填充方式;
方法二:使用undistort函数实现
undistort函数原型:
//! corrects lens distortion for the given camera matrix and distortion coefficients
CV_EXPORTS_W void undistort( InputArray src, OutputArray dst,
InputArray cameraMatrix,
InputArray distCoeffs,
InputArray newCameraMatrix=noArray() );
第一个参数src,输入参数,代表畸变的原始图像;
第二个参数dst,矫正后的输出图像,跟输入图像具有相同的类型和大小;
第三个参数cameraMatrix为之前求得的相机的内参矩阵;
第四个参数distCoeffs为之前求得的相机畸变矩阵;
第五个参数newCameraMatrix,默认跟cameraMatrix保持一致;
方法一相比方法二执行效率更高一些,推荐使用。
以下是使用某一张标定图使用方法一和方法二进行矫正的效果图对比。
原始标定图像:
方法一,使用initUndistortRectifyMap和remap实现矫正效果:
方法二,使用undistort函数实现矫正效果:
两个方法从矫正效果上看,结果是一致的。
以下是完整的工程代码:
#include &opencv2/core/core.hpp&
#include &opencv2/imgproc/imgproc.hpp&
#include &opencv2/calib3d/calib3d.hpp&
#include &opencv2/highgui/highgui.hpp&
#include &iostream&
#include &fstream&
void main()
ifstream fin(&calibdata.txt&); /* 标定所用图像文件的路径 */
ofstream fout(&caliberation_result.txt&);
/* 保存标定结果的文件 */
//读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
cout&&&开始提取角点………………&;
int image_count=0;
/* 图像数量 */
Size image_
/* 图像的尺寸 */
Size board_size = Size(4,6);
/* 标定板上每行、列的角点数 */
vector&Point2f& image_points_
/* 缓存每幅图像上检测到的角点 */
vector&vector&Point2f&& image_points_ /* 保存检测到的所有角点 */
int count= -1 ;//用于存储角点个数。
while (getline(fin,filename))
image_count++;
// 用于观察检验输出
cout&&&image_count = &&&image_count&&
/* 输出检验*/
cout&&&--&count = &&&
Mat imageInput=imread(filename);
if (image_count == 1)
//读入第一张图片时获取图像宽高信息
image_size.width = imageInput.
image_size.height =imageInput.
cout&&&image_size.width = &&&image_size.width&&
cout&&&image_size.height = &&&image_size.height&&
/* 提取角点 */
if (0 == findChessboardCorners(imageInput,board_size,image_points_buf))
cout&&&can not find chessboard corners!\n&; //找不到角点
cvtColor(imageInput,view_gray,CV_RGB2GRAY);
/* 亚像素精确化 */
find4QuadCornerSubpix(view_gray,image_points_buf,Size(5,5)); //对粗提取的角点进行精确化
//cornerSubPix(view_gray,image_points_buf,Size(5,5),Size(-1,-1),TermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,0.1));
image_points_seq.push_back(image_points_buf);
//保存亚像素角点
/* 在图像上显示角点位置 */
drawChessboardCorners(view_gray,board_size,image_points_buf,false); //用于在图片中标记角点
imshow(&Camera Calibration&,view_gray);//显示图片
waitKey(500);//暂停0.5S
int total = image_points_seq.size();
cout&&&total = &&&total&&
int CornerNum=board_size.width*board_size.
//每张图片上总的角点数
for (int ii=0 ; ii&ii++)
if (0 == ii%CornerNum)// 24 是每幅图片的角点个数。此判断语句是为了输出 图片号,便于控制台观看
int i = -1;
i = ii/CornerN
int j=i+1;
cout&&&--& 第 &&&j &&&图片的数据 --& : &&&
if (0 == ii%3) // 此判断语句,格式化输出,便于控制台查看
cout.width(10);
//输出所有的角点
cout&&& --&&&&image_points_seq[ii][0].x;
cout&&& --&&&&image_points_seq[ii][0].y;
cout&&&角点提取完成!\n&;
//以下是摄像机标定
cout&&&开始标定………………&;
/*棋盘三维信息*/
Size square_size = Size(10,10);
/* 实际测量得到的标定板上每个棋盘格的大小 */
vector&vector&Point3f&& object_ /* 保存标定板上角点的三维坐标 */
/*内外参数*/
Mat cameraMatrix=Mat(3,3,CV_32FC1,Scalar::all(0)); /* 摄像机内参数矩阵 */
vector&int& point_
// 每幅图像中角点的数量
Mat distCoeffs=Mat(1,5,CV_32FC1,Scalar::all(0)); /* 摄像机的5个畸变系数:k1,k2,p1,p2,k3 */
vector&Mat& tvecsM
/* 每幅图像的旋转向量 */
vector&Mat& rvecsM /* 每幅图像的平移向量 */
/* 初始化标定板上角点的三维坐标 */
int i,j,t;
for (t=0;t&image_t++)
vector&Point3f& tempPointS
for (i=0;i&board_size.i++)
for (j=0;j&board_size.j++)
Point3f realP
/* 假设标定板放在世界坐标系中z=0的平面上 */
realPoint.x = i*square_size.
realPoint.y = j*square_size.
realPoint.z = 0;
tempPointSet.push_back(realPoint);
object_points.push_back(tempPointSet);
/* 初始化每幅图像中的角点数量,假定每幅图像中都可以看到完整的标定板 */
for (i=0;i&image_i++)
point_counts.push_back(board_size.width*board_size.height);
/* 开始标定 */
calibrateCamera(object_points,image_points_seq,image_size,cameraMatrix,distCoeffs,rvecsMat,tvecsMat,0);
cout&&&标定完成!\n&;
//对标定结果进行评价
cout&&&开始评价标定结果………………\n&;
double total_err = 0.0; /* 所有图像的平均误差的总和 */
double err = 0.0; /* 每幅图像的平均误差 */
vector&Point2f& image_points2; /* 保存重新计算得到的投影点 */
cout&&&\t每幅图像的标定误差:\n&;
fout&&&每幅图像的标定误差:\n&;
for (i=0;i&image_i++)
vector&Point3f& tempPointSet=object_points[i];
/* 通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点 */
projectPoints(tempPointSet,rvecsMat[i],tvecsMat[i],cameraMatrix,distCoeffs,image_points2);
/* 计算新的投影点和旧的投影点之间的误差*/
vector&Point2f& tempImagePoint = image_points_seq[i];
Mat tempImagePointMat = Mat(1,tempImagePoint.size(),CV_32FC2);
Mat image_points2Mat = Mat(1,image_points2.size(), CV_32FC2);
for (int j = 0 ; j & tempImagePoint.size(); j++)
image_points2Mat.at&Vec2f&(0,j) = Vec2f(image_points2[j].x, image_points2[j].y);
tempImagePointMat.at&Vec2f&(0,j) = Vec2f(tempImagePoint[j].x, tempImagePoint[j].y);
err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
total_err += err/=
point_counts[i];
std::cout&&&第&&&i+1&&&幅图像的平均误差:&&&err&&&像素&&&
fout&&&第&&&i+1&&&幅图像的平均误差:&&&err&&&像素&&&
std::cout&&&总体平均误差:&&&total_err/image_count&&&像素&&&
fout&&&总体平均误差:&&&total_err/image_count&&&像素&&&endl&&
std::cout&&&评价完成!&&&
//保存定标结果
std::cout&&&开始保存定标结果………………&&&
Mat rotation_matrix = Mat(3,3,CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */
fout&&&相机内参数矩阵:&&&
fout&&cameraMatrix&&endl&&
fout&&&畸变系数:\n&;
fout&&distCoeffs&&endl&&endl&&
for (int i=0; i&image_ i++)
fout&&&第&&&i+1&&&幅图像的旋转向量:&&&
fout&&tvecsMat[i]&&
/* 将旋转向量转换为相对应的旋转矩阵 */
Rodrigues(tvecsMat[i],rotation_matrix);
fout&&&第&&&i+1&&&幅图像的旋转矩阵:&&&
fout&&rotation_matrix&&
fout&&&第&&&i+1&&&幅图像的平移向量:&&&
fout&&rvecsMat[i]&&endl&&
std::cout&&&完成保存&&&
/************************************************************************
显示定标结果
*************************************************************************/
Mat mapx = Mat(image_size,CV_32FC1);
Mat mapy = Mat(image_size,CV_32FC1);
Mat R = Mat::eye(3,3,CV_32F);
std::cout&&&保存矫正图像&&&
string imageFileN
std::stringstream StrS
for (int i = 0 ; i != image_ i++)
std::cout&&&Frame #&&&i+1&&&...&&&
initUndistortRectifyMap(cameraMatrix,distCoeffs,R,cameraMatrix,image_size,CV_32FC1,mapx,mapy);
StrStm.clear();
imageFileName.clear();
string filePath=&chess&;
StrStm&&i+1;
StrStm&&imageFileN
filePath+=imageFileN
filePath+=&.bmp&;
Mat imageSource = imread(filePath);
Mat newimage = imageSource.clone();
//另一种不需要转换矩阵的方式
//undistort(imageSource,newimage,cameraMatrix,distCoeffs);
remap(imageSource,newimage,mapx, mapy, INTER_LINEAR);
StrStm.clear();
filePath.clear();
StrStm&&i+1;
StrStm&&imageFileN
imageFileName += &_d.jpg&;
imwrite(imageFileName,newimage);
std::cout&&&保存结束&&&
标定图例1:
标定图例2:
标定结果1:
标定结果2:
矫正效果1:
矫正效果2:
以上程序已经是完整程序,需要棋盘标定图或者整个项目包的可以到这里下载:。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:33567次
积分:1298
积分:1298
排名:千里之外
原创:94篇
评论:67条
(18)(11)(25)(25)(15)}

我要回帖

更多关于 金正友 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信