opencv摄像机标定代码
- 格式:doc
- 大小:44.00 KB
- 文档页数:5
#include">
双目视觉 opencv 代码双目视觉是指利用两个摄像头来获取场景的深度信息。
在OpenCV中,可以使用双目视觉进行立体视觉的处理。
下面我将从多个角度介绍如何使用OpenCV来实现双目视觉的代码。
1. 初始化摄像头:首先,你需要初始化两个摄像头,可以使用OpenCV的VideoCapture类来实现。
你可以通过以下代码来初始化两个摄像头:cv::VideoCapture cap1(0); // 打开第一个摄像头。
cv::VideoCapture cap2(1); // 打开第二个摄像头。
2. 获取图像:接下来,你需要从两个摄像头中获取图像。
你可以使用以下代码来获取图像:cv::Mat frame1, frame2;cap1 >> frame1; // 从第一个摄像头获取图像。
cap2 >> frame2; // 从第二个摄像头获取图像。
3. 立体校正:在进行立体视觉处理之前,通常需要进行立体校正,以确保两个摄像头的图像对齐。
你可以使用OpenCV中的stereoRectify和initUndistortRectifyMap函数来实现立体校正。
4. 视差计算:一旦完成立体校正,你可以使用OpenCV中的StereoBM或StereoSGBM类来计算图像的视差。
这些类实现了不同的立体匹配算法,可以帮助你计算出图像中不同像素的视差值。
5. 三维重构:最后,你可以使用视差图和立体校正参数来进行三维重构,从而获取场景的深度信息。
你可以使用reprojectImageTo3D函数来实现三维重构。
以上是使用OpenCV实现双目视觉的基本步骤和代码示例。
当然,双目视觉涉及到的内容非常广泛,包括摄像头标定、深度图像的可视化等等,还有很多细节需要考虑。
希望以上内容能够帮助你入门双目视觉的代码实现。
一种基于OpenCV的摄像机标定算法的研究与实现作者:孙昆穆森邱桂苹赵倩来源:《电子世界》2012年第14期【摘要】摄像机标定是计算机视觉中的一个重要问题。
本文介绍了标定的基本原理,详尽阐述了使用二维模板的标定算法,重点分析了如何借助开源软件OpenCV实现该算法。
实验结果显示,使用OpenCV中的相关函数,可以方便地进行数学计算,简单有效地完成摄像机标定。
【关键词】摄像机标定;内部参数;单应性矩阵;OpenCV1.引言计算机视觉的基本任务之一是从摄像机获取的图像信息出发计算三维空间中物体的几何信息,并由此重建和识别物体。
而空间物体表面某点的三维几何位置与其在图像中对应点之间的相互关系是由摄像机成像的几何模型决定的,这些几何模型参数就是摄像机参数。
摄像机标定是确定摄像机内外参数的一个过程,其中内参数的标定是指确定摄像机固有的、与位置参数无关的内部几何与光学参数,包括图像中心坐标(也称主点坐标)、图像纵横比、相机的有效焦距和透镜的畸变失真系数等;外参数的标定是确定摄像机坐标系相对某一世界坐标系的三维位置和方向关系。
目前,摄像机标定技术主要有两种实现方法:(1)基于标定物的方法:需要尺寸已知的标定参照物,通过建立标定物上三维坐标已知点与其图像点之间的对应,利用一定的算法获得摄像机的内外参数。
标定物可以是三维的,也可以是二维共面的。
三维标定物条件下,只需一幅图像就可以求出摄像机的全部内外参数。
但三维标定物的加工和维护比较困难。
二维共面标定物加工维护简单,但一幅图像不足以标出所有的摄像机参数,因此需要简化摄像机模型,或者从不同角度获取多幅图像来同时标出所有的参数。
当应用场合要求的精度很高而且摄像机的参数不经常变化时,这种标定法应为首选。
(2)自标定法:不需要标定物,仅依靠多幅图像对应点之间的关系直接进行标定。
利用了摄像机内部参数自身的约束,而与场景和摄像机运动无关。
该方法非常灵活,但不是很成熟,由于未知参数太多,很难得到稳定的结果。
相机标定过程(opencv)+matlab参数导⼊opencv+matlab标定和矫正%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%⾟苦原创所得,转载请注明出处%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%start -- 摄像机标定 ---------------------------------------------->摄像机标定的数学过程如下标定事先选⽤棋盘格要注意⼀些问题,张正友论⽂中建议棋盘格数⼤于7*7。
opencv标定时候对正⽅形的棋盘格标定板是不能识别的,需要长⽅形的标定板。
张正友论⽂中建议每次拍摄标定板占50%以上,但这是对畸变并不是很⼤的普通相机⽽⾔的,对于球⾯相机是不适⽤的,相反球⾯相机标定使⽤的标定板占⽐应该较⼩⽐较好(对于格⼦并不是⾮常密的棋盘格⽽⾔),原因是因为棋盘格每个⾓点之间的距离越⼤,这段距离之间的可能发⽣畸变的点越多,如果占⽐过⼤就⽆法将形变体现在棋盘格中。
棋盘格的选⽤应该根据实际需要选⽤,对于要求精密识别的情况,则需要⾼精度的棋盘格,相应的价格也会较⾼;对于精度要求并不是很⾼的(如抓取)情况并不需要精度很⾼的标定板,也能够节省开⽀。
这⾥程序的实现是在opencv中,所以就⽤opencv的程序来说明具体的过程.注意各个版本的opencv之间的程序移植性并不好,以下程序是在opencv2.4.3下编制运⾏的,每⼀步的要⽤到的输⼊输出都做了红⾊标记.⽴体相机标定分为两个步骤,⼀个是单⽬标定(本⽂档第2步),另⼀个是双⽬标定单⽬标定获得相机的x,y轴的焦距;x,y轴的坐标原点位置;世界坐标系和平⾯坐标之间的旋转和平移矩阵,5个畸变系数双⽬标定获得两个相机成像平⾯之间的旋转和平移矩阵注意1.程序运⾏前需要插上摄像头,否则程序有可能不能正常运⾏2.单⽬标定(1).获取棋盘格图像for (int i=1; i<=19; i++)//输⼊左标定板图像{std::stringstream str;//声明输⼊输出流str << "./left" << i << ".jpg";//以名字⽅式把图像输⼊到流std::cout << str.str() << std::endl;//.str("")清除内容 .clear()清空标记位leftFileList.push_back(str.str());//.push_back从容器后向前插⼊数据leftBoardImage = cv::imread(str.str(),0);//⽤来显⽰即时输⼊的图像cv::namedWindow("left chessboard image");cv::imshow("left chessboard image",leftBoardImage);cv::waitKey(10);}(2).定义棋盘格的⾓点数⽬cv::Size boardSize(14,10)(3).程序定位提取⾓点这⾥建⽴的是理想成像平⾯(三维,第三维为0,单位为格⼦数)和图像坐标系(⼆维,单位是像素)之间的关系(a)⾸先声明两个坐标容器std::vector<cv::Point2f> imageCorners;//⼆位坐标点std::vector<cv::Point3f> objectCorners;//三维坐标点(b)初始化棋盘⾓点,令其位置位于(x,y,z)=(i,j,0),⼀个棋盘格为⼀个坐标值for (int i=0; i<boardSize.height; i++){for (int j=0; j<boardSize.width; j++){objectCorners.push_back(cv::Point3f(i, j, 0.0f));}}(c)直接使⽤opencv内函数找到⼆维⾓点坐标,并建⽴标定标定格⼦和实际坐标间的关系(像素级别)这个函数使⽤时,当标定板是长⽅形时可以找到⾓点,但是标定板是正⽅形时,就找不到,原因还未知.cv::findChessboardCorners(image, boardSize, imageCorners);(d)获得像素精度往往是不够的,还需要获得亚像素的精度cv::cornerSubPix(image,imageCorners, //输⼊/输出cv::Size(5,5),//搜索框的⼀半,表⽰在多⼤窗⼝定位⾓点cv::Size(-1,-1), //死区cv::TermCriteria(cv::TermCriteria::MAX_ITER + cv::TermCriteria::EPS,30, // max number of iterations//迭代最⼤次数0.01)); // min accuracy//最⼩精度注:TermCriteria模板类,取代了之前的CvTermCriteria,这个类是作为迭代算法的终⽌条件的,这个类在参考⼿册⾥介绍的很简单,我查了些资料,这⾥介绍⼀下。
学习笔记:使⽤opencv做双⽬测距(相机标定+⽴体匹配+测距).最近在做双⽬测距,觉得有必要记录点东西,所以我的第⼀篇博客就这么诞⽣啦~双⽬测距属于⽴体视觉这⼀块,我觉得应该有很多⼈踩过这个坑了,但⽹上的资料依旧是云⾥雾⾥的,要么是理论讲⼀⼤堆,最后发现还不知道怎么做,要么就是直接代码⼀贴,让你懵逼。
所以今天我想做的,是尽量给⼤家⼀个明确的阐述,并且能够上⼿做出来。
⼀、标定⾸先我们要对摄像头做标定,具体的公式推导在learning opencv中有详细的解释,这⾥顺带提⼀句,这本书虽然确实⽼,但有些理论、算法类的东西⾥⾯还是讲的很不错的,必要的时候可以去看看。
Q1:为什么要做摄像头标定?A: 标定的⽬的是为了消除畸变以及得到内外参数矩阵,内参数矩阵可以理解为焦距相关,它是⼀个从平⾯到像素的转换,焦距不变它就不变,所以确定以后就可以重复使⽤,⽽外参数矩阵反映的是摄像机坐标系与世界坐标系的转换,⾄于畸变参数,⼀般也包含在内参数矩阵中。
从作⽤上来看,内参数矩阵是为了得到镜头的信息,并消除畸变,使得到的图像更为准确,外参数矩阵是为了得到相机相对于世界坐标的联系,是为了最终的测距。
ps1:关于畸变,⼤家可以看到⾃⼰摄像头的拍摄的画⾯,在看矩形物体的时候,边⾓处会有明显的畸变现象,⽽矫正的⽬的就是修复这个。
ps2:我们知道双⽬测距的时候两个相机需要平⾏放置,但事实上这个是很难做到的,所以就需要⽴体校正得到两个相机之间的旋转平移矩阵,也就是外参数矩阵。
Q2:如何做摄像头的标定?A:这⾥可以直接⽤opencv⾥⾯的sample,在opencv/sources/sample/cpp⾥⾯,有个calibration.cpp的⽂件,这是单⽬的标定,是可以直接编译使⽤的,这⾥要注意⼏点:1.棋盘棋盘也就是标定板是要预先打印好的,你打印的棋盘的样式决定了后⾯参数的填写,具体要求也不是很严谨,清晰能⽤就⾏。
之所⽤棋盘是因为他检测⾓点很⽅便,and..你没得选。
Matlab摄像机标定和立体标定分类:OpenCV立体视觉/三维重建|2012-11-2721:01|25人阅读1.摄像头我用的摄像头是淘宝上买的三维摄像头,两个USB Camera加一个可调节的支架。
实物照片如下1.1三维摄像头实物图双USB摄像头的OpenCV驱动可以参考以下链接/index.php/使用DirectShow采集图像将上面代码复制到自己的工程之后还需要对工程或者编译环境做一下设置VC6下的详尽设置可以见代码的注释(修改工程的属性)VS2008中的设置也可以参照代码注释中VC++2005的设置(修改编译环境)2.标定由于OpenCV中cvStereoCalibrate总是会得到很夸张的结果(见下文5.1问题描述),所以最后还是决定用Bouguet的Matlab标定工具箱立体标定,再将标定的结果读入OpenCV,来进行后续图像校准和匹配。
Matlab标定工具箱的参考链接如下:/bouguetj/calib_doc/上面有详细的使用步骤,用起来相当的方便。
以下是我个人用Matlab工具箱进行立体标定的步骤,供参考,如果需要更详细步骤的话还是参照上面的链接把Matlab工具箱的文件copy到对应目录下,把所要标定的棋盘图也放到.m文件所在的目录下,然后在Matlab命令行窗口中打入calib_gui,选择Standard之后便出现以下窗口2.1.calilb_gui面板我们先对右摄像头的标定,所以先把从右摄像头上采集到的棋盘图复制到工具箱目录下。
点击Image names,命令行窗口会提示你输入图片的basename以及图片的格式(比如你图片文件名是right1,right2,…,right10,basename就是right),然后Matlab会自动帮你读入这些图片,如下图所示,可以看到,读入了10幅右摄像头的棋盘图。
采集棋盘图的时候要注意,尽量让棋盘占据尽可能多的画面,这样可以得到更多有关摄像头畸变方面的信息2.2.图像basename读入2.3.读入的棋盘图然后再回到主控制界面,点击Extract grid corners,提取每幅图的角点2.4.calib_gui面板点击完后,命令行会出现如下提示,主要是让你输入棋盘角点搜索窗口的大小。
摄像机标定原理及源码一、摄像机标定原理1.1相机模型在进行摄像机标定之前,需要了解相机模型。
常用的相机模型是针孔相机模型,它假设光线通过小孔进入相机进行成像,形成的图像符合透视投影关系。
针孔相机模型可以通过相机内部参数和外部参数来描述。
1.2相机内部参数相机内部参数主要包括焦距、光心坐标等信息,可以通过相机的标定板来获取。
标定板上通常有已知尺寸的标定点,通过计算图像中的标定点坐标和实际世界中的标定点坐标之间的关系,可以求解出相机的内部参数。
1.3相机外部参数相机外部参数主要包括相机在世界坐标系中的位置和姿态信息。
可以通过引入已知的点和相机对这些点的投影来求解相机的外部参数。
也可以通过运动捕捉系统等设备获取相机的外部参数。
1.4标定算法常用的摄像机标定算法有张正友标定法、Tsai标定法等。
其中,张正友标定法是一种简单和广泛使用的标定方法。
该方法通过对标定板上的角点进行提取和匹配,利用通用的非线性优化算法(如Levenberg-Marquardt算法)最小化像素坐标与世界坐标的重投影误差,从而求解出相机的内部参数和外部参数。
二、摄像机标定源码下面是使用OpenCV实现的摄像机标定源码:```pythonimport numpy as npimport cv2#棋盘格尺寸(单位:毫米)square_size = 25#棋盘内角点个数pattern_size = (9, 6)#获取标定板角点的世界坐标objp = np.zeros((np.prod(pattern_size), 3), dtype=np.float32) objp[:, :2] = np.mgrid[0:pattern_size[0],0:pattern_size[1]].T.reshape(-1, 2) * square_sizedef calibrate_camera(images):#存储角点的世界坐标和图像坐标objpoints = []imgpoints = []for img in images:gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#查找角点ret, corners = cv2.findChessboardCorners(gray, pattern_size, None)if ret:objpoints.append(objp)#亚像素精确化criteria = (cv2.TERM_CRITERIA_EPS +cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)imgpoints.append(corners2)#标定相机ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)return ret, mtx, dist, rvecs, tvecs#读取图像images = []for i in range(1, 21):img = cv2.imread(f'image_{i}.jpg')images.append(img)#相机标定ret, mtx, dist, rvecs, tvecs = calibrate_camera(images)#保存相机参数np.savez('calibration.npz', ret=ret, mtx=mtx, dist=dist, rvecs=rvecs, tvecs=tvecs)```以上代码首先定义了棋盘格尺寸和格子个数,然后定义了函数`calibrate_camera`来进行相机标定。
opencv的calibratecamera的flag
cv2.calibrateCamera函数是OpenCV中用于摄像机标定的函数,该函数的flags参数是一个整数值,可以包含以下标志:
- cv2.CALIB_USE_INTRINSIC_GUESS:使用先前计算得到的内部参数矩阵进行标定,这可以提高标定的准确性,同时减少标定所需的图像数量。
- cv2.CALIB_FIX_PRINCIPAL_POINT:将主点固定在图像中心,这在某些情况下可以提高标定的准确性,但也会限制标定算法的自由度。
- cv2.CALIB_FIX_ASPECT_RATIO:将像素宽高比固定为已知值,这对于在不同摄像机上拍摄相同对象的多个图像时非常有用。
- cv2.CALIB_ZERO_TANGENT_DIST:假设切向畸变为0,这是因为在一些情况下切向畸变很小,可以忽略不计,但如果不忽略它,标定算法可能会陷入局部极小值。
- cv2.CALIB_FIX_K1...cv2.CALIB_FIX_K6:将径向畸变系数固定为0或已知值,这可以防止标定算法过度拟合畸变系数。
- cv2.CALIB_RATIONAL_MODEL:使用畸变模型cv2.CALIB_RATIONAL_POLY(默认为cv2.CALIB_POLY)进行标定,这可以提高标定的精度,但计算成本更高。
不同的标志可以结合使用,但需要根据具体的应用场景选择合适的标志组合。
张正友标定法⽰例(含源代码)
博主在博客园的第⼀篇博客,以著名的张⼤⽜标定法开始吧!
具体标定原理就不详细说了,资料数不胜数,重点看张正友的原著《A Flexible New Technique for Camera Calibration》,搞明⽩这篇⽂章就⾜够了。
好了,现在主要说⼀下标定过程,并附上博主⾃⼰调⽤Opencv接⼝编写的代码。
1.拍摄棋盘格图⽚,8幅左右合适,⽂献⾥说n=8时,最⼩⼆乘法计算内参有稳定解。
所以我就拍了9幅。
2. 读取棋盘格图像,提取⾓点(注意:都是内⾓点)。
为了提⾼⾓点提取精度,进⼀步进⾏亚像素⾓点的提取,附上亚像素⾓点提取后的棋盘格图像。
3. 开始摄像机标定,opencv1.0 2.0版只有⼀种摄像机标定模型,就是普通的⼩孔成像模型,在cv::空间下。
⽽从opencv3.0开始,新增了⼀种鱼眼相机标定模型,在fisheye::空间下。
两种模型的主要区别在于像与物的投影关系不同,具体的⽂献资料依然是数不胜数,这⾥就不赘述。
根据opencv官⽅⽂档的建议,在畸变程度较⼤的⼴⾓镜头(⽐如:鱼眼镜头)上进⾏摄像机标定和畸变校正,最好是⽤fisheye模型,该模型在图像边缘畸变程度很⼤的地⽅⽐普通相机模型的效果要好。
4. 对标定结果进⾏评价
5.保存标定结果,写⼊txt⽂件,主要是内参(归⼀化焦距,fx,fy; 光⼼坐标cx,cy;以及畸变系数k1,k2k3...)
好了,主要过程介绍完了,附上我放在码云上的源代码连接:。
基于OpenCV的摄像机标定研究摘要:根据摄像机标定原理,实现了vc 2010环境下基于opencv 的摄像机标定系统。
该系统以棋盘格标定板图像作为输入,计算出了摄像机的各内外参数及畸变系数。
通过图像矫正实验证明了系统的有效性。
关键词:摄像机标定;棋盘格;opencv;图像矫正中图分类号:tp391.41 文献标识码:a文章编号:1007-9599 (2013) 05-0000-021引言视觉测量、三维重建等是计算机视觉应用中较为重要的研究领域。
在这些研究中,都需要确定视觉图像中的点与现实世界中对应点的几何位置关系。
我们常用的图像,由摄像机拍摄得到,因此,确定这种关系,就要依靠成像系统即摄像机的几何模型。
几何模型的参数就是摄像机的参数。
但这些参数不能够直接获取,而是要利用摄像机拍摄的图像,通过实验来获取。
获取这些参数的过程我们称之为摄像机标定。
摄像机标定是计算机视觉应用中的关键技术。
摄像机标定精度直接影响视觉测量精度,也是做好立体图像匹配与三维重建工作的基础[1]。
摄像机标定方法有3类:基于标定物的方法,自标定方法和基于主动视觉的标定方法[2,3]。
其中,使用平面标定物的标定方法[4],因其标定物制作简单、标定方法灵活而广泛使用。
本文详细介绍了摄像机标定原理,及在vc++ 2010环境下,利用opencv 2.4.4实现摄像机标定的方法和步骤,并通过实验验证了其有效性。
2标定原理摄像机标定首先需要利用合适的数学工具来描述和表达空间中的点与图像中对应点之间的关系。
这个工具就是几何模型,它涉及到摄像机的光学参数如图像中心、镜头焦距和镜头畸变等,还涉及到摄像机坐标系与世界坐标系的相对位置和方位等。
常用的针孔模型是一种理想的成像模型,没有考虑摄像机透镜的厚度及畸变对成像的影响,不能很好地反映实际情况。
opencv中的标定算法,其摄像机模型以针孔模型为基础,同时考虑了透镜的径向畸变和切向畸变,引入了径向畸变和切向畸变两个参数。
opencv calibratecameracharuco具体实现1. 引言1.1 概述本文介绍了Opencv中的calibrateCameraCharuco函数的具体实现。
相机标定是计算机视觉领域中重要的技术之一,它通过估计相机内外参数来提高图像处理和分析的精度。
而Charuco模式作为一种新型的标定模式,在相机标定中展现了较好的性能和鲁棒性。
1.2 文章结构文章按照以下结构展开对Opencv calibrateCameraCharuco函数进行详细介绍与分析。
首先,我们将介绍Opencv简介,以便读者对该库有一个基本的了解。
然后,我们会阐述相机标定的概念与意义,以及Charuco模式在相机标定中所起到的作用。
接下来,我们将详细说明Opencv calibrateCameraCharuco 函数的具体实现步骤和方法。
在实验结果与分析部分,我们将描述数据集、拍摄条件,并对标定结果进行评估指标解释。
最后,在结论与展望部分,我们会总结研究成果,并探讨该方法存在的创新点和局限性,同时提出后续研究方向建议与展望。
1.3 目的本文旨在系统地介绍和解析Opencv calibrateCameraCharuco函数的具体实现方法,为研究者和从业者在相机标定领域提供一种高效准确的方法。
通过对Charuco模式的使用和数据处理等步骤的描述与分析,读者可以深入理解该函数的原理与应用,并能够在实践中灵活运用该函数来进行相机标定。
此外,本文还将探讨该方法的潜在优化方案,以期提高算法的性能和鲁棒性。
2. Opencv calibrateCameraCharuco的背景知识:2.1 Opencv简介:OpenCV,全称Open Source Computer Vision Library,是一个开源的计算机视觉库,它提供了一系列用于图像处理和计算机视觉任务的函数和工具。
Opencv库广泛应用于机器人技术、智能交通系统、图像搜索引擎等领域。
一、calibratecamera 源码解析在计算机视觉和图像处理领域,相机标定是一个非常重要的过程,而OpenCV 提供了一个非常方便的函数 calibrateCamera 来实现相机的标定。
本文将对 calibrateCamera 函数的源码进行解析,帮助读者更好地理解相机标定的原理和实现。
二、calibrateCamera 函数的调用方式calibrateCamera 函数的调用方式如下所示:```pythonretval, cameraMatrix, distCoeffs, rvecs, tvecs =cv2.calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, flags=0, criteria)```其中,各参数的含义如下:- retval:标定结果的精度。
- cameraMatrix:相机内参矩阵。
- distCoeffs:径向和切向畸变系数。
- rvecs:旋转向量。
- tvecs:平移向量。
- objectPoints:世界坐标系中的三维点。
- imagePoints:图像坐标系中对应的二维点。
- imageSize:图像的尺寸。
- flags:额外的标定选项。
- criteria:标定迭代的终止条件。
三、calibrateCamera 函数的源码分析1. 在我们调用 calibrateCamera 函数时,函数会检查输入参数的合法性,包括 objectPoints 和 imagePoints 的数量是否一致,以及cameraMatrix 和 distCoeffs 的尺寸是否符合要求。
2. 函数会根据传入的标定选项 flags 执行相应的标定操作。
这些标定选项包括使用棋盘格或圆盘图案等以及是否对图像坐标进行优化等。
3. 接下来,函数会根据 objectPoints 和 imagePoints 计算出相机的内参矩阵 cameraMatrix 和畸变系数 distCoeffs。
opencv的相机标定方法相机标定是计算机视觉中的一个重要步骤,它的目标是通过对相机进行一系列的测量来确定相机的内部参数和外部参数,从而提高图像处理和计算机视觉任务的精确度和稳定性。
OpenCV是一个广泛使用的计算机视觉库,提供了多种相机标定方法。
1.单目相机标定方法:单目相机标定是指使用一个相机拍摄多张不同的棋盘格图像,通过提取图像中的棋盘格角点来确定相机的内部参数和外部参数。
OpenCV中提供了函数`cv::calibrateCamera(`来进行单目相机标定。
该函数需要输入一组棋盘格图像,每幅图像中的棋盘格角点坐标,以及每个角点在现实世界中的坐标。
函数根据这些数据计算相机的内部参数矩阵、畸变系数和每幅图像的旋转矩阵和平移向量。
2.双目相机标定方法:双目相机标定是指使用一对相机拍摄同一场景的图像,并通过识别这些图像中的共享特征点来计算相机的内部参数和外部参数。
OpenCV中提供了函数`cv::stereoCalibrate(`来进行双目相机标定。
该函数需要输入两个相机拍摄的图像,每幅图像中的特征点坐标,以及每个特征点在现实世界中的坐标。
函数根据这些数据计算两个相机的内部参数矩阵、畸变系数和旋转矩阵、平移向量之间的转换关系。
3.深度相机标定方法:深度相机标定是指使用深度相机(如Kinect)拍摄不同的场景,并通过识别图像中的特征点来确定深度相机的内部参数和外部参数。
OpenCV 中提供了函数`cv::rgbd::calibrate(`来进行深度相机标定。
该函数需要输入一系列深度图像和对应的RGB图像,以及特征点的坐标。
函数根据这些数据计算深度相机的内部参数矩阵和旋转矩阵、平移向量之间的转换关系。
4.灰度相机标定方法:灰度相机标定是指使用灰度相机(只能获取灰度图像)进行标定。
与单目相机标定类似,灰度相机标定也是通过拍摄多张棋盘格图像,提取角点坐标进行计算。
OpenCV中提供了函数`cv::calibrateCamera(`来进行灰度相机标定,其使用方式与单目相机标定相似。
// cvCalib.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include <stdio.h>#include <cv.h>#include <highgui.h>#include <cxcore.h>void InitCorners3D(CvMat *Corners3D, CvSize ChessBoardSize, int Nimages, float SquareSize);int image_width = 768;int image_height = 576;//待标定图片的大小const int ChessBoardSize_w = 7;const int ChessBoardSize_h = 7;//图片中可标定的角数const CvSize ChessBoardSize = cvSize(ChessBoardSize_w,ChessBoardSize_h);const int NPoints = ChessBoardSize_w*ChessBoardSize_h;//角点个数const int NImages=6;//待标定的图片数int corner_count[NImages] = {0};float SquareWidth = 10; //棋盘格子的边长,可任意设定,不影响内参数CvMat *intrinsics;CvMat *distortion_coeff;CvMat *rotation_vectors;CvMat *translation_vectors;CvMat *object_points;CvMat *point_counts;CvMat *image_points;void main(){IplImage *current_frame_rgb;IplImage *current_frame_gray;IplImage *chessBoard_Img;CvPoint2D32f corners[NPoints*NImages];chessBoard_Img =cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 3);current_frame_gray = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 1);current_frame_rgb = cvCreateImage(cvSize(image_width, image_height), IPL_DEPTH_8U, 3);int captured_frames=0;for(captured_frames=0;captured_frames<NImages;captured_frames++){char filename[]="cal20Img00.bmp"; //说明:我把待标定的图片的名子依次命名为:01.jpg, 02.jpg, 03.jpg, 04.jpg,……if(captured_frames<9)filename[9]=(char)(captured_frames+49);else if(captured_frames>=9&&captured_frames<=99){int j,jj;jj=(captured_frames+1)/10;j=(captured_frames+1)%10;filename[8]=jj+48;filename[9]=j+48;}elseprintf("error, too many images.......\n"); //load images endchessBoard_Img=cvLoadImage( filename, CV_LOAD_IMAGE_COLOR );cvCvtColor(chessBoard_Img, current_frame_gray, CV_BGR2GRAY);cvCopy(chessBoard_Img,current_frame_rgb);int find_corners_result;find_corners_result = cvFindChessboardCorners(current_frame_gray,ChessBoardSize,&corners[captured_frames*NPoints],&corner_count[captured_frames],//int corner_count[NImages] = {0};CV_CALIB_CB_ADAPTIVE_THRESH );cvFindCornerSubPix( current_frame_gray,&corners[captured_frames*NPoints],NPoints, cvSize(2,2),cvSize(-1,-1),cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03) );cvDrawChessboardCorners(current_frame_rgb, ChessBoardSize, //绘制检测到的棋盘角点&corners[captured_frames*NPoints],NPoints,find_corners_result);cvNamedWindow("Window 0", 1);cvNamedWindow("result", 1);cvShowImage("Window 0",chessBoard_Img);cvShowImage("result",current_frame_rgb);cvWaitKey(0);}intrinsics = cvCreateMat(3,3,CV_32FC1);distortion_coeff = cvCreateMat(1,4,CV_32FC1);rotation_vectors = cvCreateMat(NImages,3,CV_32FC1);translation_vectors = cvCreateMat(NImages,3,CV_32FC1);point_counts = cvCreateMat(NImages,1,CV_32SC1);object_points = cvCreateMat(NImages*NPoints,3,CV_32FC1);image_points = cvCreateMat(NImages*NPoints,2,CV_32FC1);//把2维点转化成三维点(object_points输出量),InitCorners3D(object_points, ChessBoardSize, NImages, SquareWidth);cvSetData( image_points, corners, sizeof(CvPoint2D32f));cvSetData( point_counts, &corner_count, sizeof(int));// float test_object_points[20000];// float test_image_point[10000];// float test_point_counts[4000];// for (int z=0;z<NPoints*NImages;z++)// {// test_object_points[z*3+0]=cvmGet(object_points,z,0); // test_object_points[z*3+1]=cvmGet(object_points,z,1); // test_object_points[z*3+2]=cvmGet(object_points,z,2); //// test_image_point[z*2+0]=cvmGet(image_points,z,0); // test_image_point[z*2+1]=cvmGet(image_points,z,1); //// test_point_counts[z]=cvmGet(point_counts,z,0);//// }//计算内参cvCalibrateCamera2( object_points,image_points,point_counts,cvSize(image_width,image_height),intrinsics,distortion_coeff,rotation_vectors,translation_vectors,0);float intr[3][3] = {0.0};float dist[4] = {0.0};float tranv[3] = {0.0};float rotv[3] = {0.0};for ( int i = 0; i < 3; i++){for ( int j = 0; j < 3; j++){intr[i][j] = ((float*)(intrinsics->data.ptr + intrinsics->step*i))[j];}dist[i] = ((float*)(distortion_coeff->data.ptr))[i];tranv[i] = ((float*)(translation_vectors->data.ptr))[i];rotv[i] = ((float*)(rotation_vectors->data.ptr))[i];}dist[3] = ((float*)(distortion_coeff->data.ptr))[3];//以上部分不明白printf("-----------------------------------------\n ");printf("INTRINSIC MA TRIX: \n");printf("[ %6.4f %6.4f %6.4f ] \n", intr[0][0], intr[0][1], intr[0][2]);printf("[ %6.4f %6.4f %6.4f ] \n", intr[1][0], intr[1][1], intr[1][2]);printf("[ %6.4f %6.4f %6.4f ] \n", intr[2][0], intr[2][1], intr[2][2]);printf("----------------------------------------- \n");printf("DISTORTION VECTOR: \n");printf("[ %6.4f %6.4f %6.4f %6.4f ] \n", dist[0], dist[1], dist[2], dist[3]);printf("----------------------------------------- \n");printf("ROTA TION VECTOR: \n");printf("[ %6.4f %6.4f %6.4f ] \n", rotv[0], rotv[1], rotv[2]);printf("TRANSLATION VECTOR: \n");printf("[ %6.4f %6.4f %6.4f ] \n", tranv[0], tranv[1], tranv[2]);printf("----------------------------------------- \n");cvReleaseMat(&intrinsics);cvReleaseMat(&distortion_coeff);cvReleaseMat(&rotation_vectors);cvReleaseMat(&translation_vectors);cvReleaseMat(&point_counts);cvReleaseMat(&object_points);cvReleaseMat(&image_points);cvDestroyAllWindows();}void InitCorners3D(CvMat *Corners3D, CvSize ChessBoardSize, int NImages, float SquareSize){int CurrentImage = 0;int CurrentRow = 0;int CurrentColumn = 0;int NPoints = ChessBoardSize.height*ChessBoardSize.width;float * temppoints = new float[NImages*NPoints*3];// for now, assuming we're row-scanningfor (CurrentImage = 0 ; CurrentImage < NImages ; CurrentImage++){for (CurrentRow = 0; CurrentRow < ChessBoardSize.height; CurrentRow++){for (CurrentColumn = 0; CurrentColumn < ChessBoardSize.width; CurrentColumn++){temppoints[(CurrentImage*NPoints*3)+(CurrentRow*ChessBoardSize.width + CurrentColumn)*3]=(float)CurrentRow*SquareSize;temppoints[(CurrentImage*NPoints*3)+(CurrentRow*ChessBoardSize.width + CurrentColumn)*3+1]=(float)CurrentColumn*SquareSize;temppoints[(CurrentImage*NPoints*3)+(CurrentRow*ChessBoardSize.width +CurrentColumn)*3+2]=0.f;}}}(*Corners3D) = cvMat(NImages*NPoints,3,CV_32FC1, temppoints);}。