作者 群号 C语言交流中心 240137450 微信
15013593099
照相机定标
[编辑]
ProjectPoints2
投影三维点到图像平面
void cvProjectPoints2( const CvMat* object_points, const CvMat* rotation_vector, const CvMat* translation_vector, const CvMat* intrinsic_matrix, const CvMat* distortion_coeffs, CvMat* image_points, CvMat* dpdrot=NULL, CvMat* dpdt=NULL, CvMat* dpdf=NULL, CvMat* dpdc=NULL, CvMat* dpddist=NULL );
- object_points
- 物体点的坐标,为3xN或者Nx3的矩阵,这儿N是视图中的所有所有点的数目。
- rotation_vector
- 旋转向量,1x3或者3x1。
- translation_vector
- 平移向量,1x3或者3x1。
- intrinsic_matrix
- 摄像机内参数矩阵A:
- distortion_coeffs
- 形变参数向量,4x1或者1x4,为[k1,k2,p1,p2]。如果是NULL,所有形变系数都设为0。
- image_points
- 输出数组,存储图像点坐标。大小为2xN或者Nx2,这儿N是视图中的所有点的数目。
- dpdrot
- 可选参数,关于旋转向量部分的图像上点的导数,Nx3矩阵。
- dpdt
- 可选参数,关于平移向量部分的图像上点的导数,Nx3矩阵。
- dpdf
- 可选参数,关于fx和fy的图像上点的导数,Nx2矩阵。
- dpdc
- 可选参数,关于cx和cy的图像上点的导数,Nx2矩阵。
- dpddist
- 可选参数,关于形变系数的图像上点的导数,Nx4矩阵。
函数cvProjectPoints2通过给定的内参数和外参数计算三维点投影到二维图像平面上的坐标。另外,这个函数可以计算关于投影参数的图像点偏导数的雅可比矩阵。雅可比矩阵可以用在cvCalibrateCamera2和cvFindExtrinsicCameraParams2函数的全局优化中。这个函数也可以用来计算内参数和外参数的反投影误差。注意,将内参数和(或)外参数设置为特定值,这个函数可以用来计算外变换(或内变换)。
[编辑]
FindHomography
计算两个平面之间的透视变换
void cvFindHomography( const CvMat* src_points, const CvMat* dst_points, CvMat* homography );
- src_points
- 原始平面的点坐标,大小为2xN,Nx2,3xN或者 Nx3矩阵(后两个表示齐次坐标),这儿N表示点的数目。
- dst_points
- 目标平面的点坐标大小为2xN,Nx2,3xN或者 Nx3矩阵(后两个表示齐次坐标)。
- homography
- 输出的3x3的homography矩阵。
函数cvFindHomography计算源平面和目标平面之间的透视变换.
使得反投影错误最小:
这个函数可以用来计算初始的内参数和外参数矩阵。由于Homography矩阵的尺度可变,所以它被规一化使得h33 =1
[编辑]
CalibrateCamera2
利用定标来计算摄像机的内参数和外参数
void cvCalibrateCamera2( const CvMat* object_points, const CvMat* image_points, const CvMat* point_counts, CvSize image_size, CvMat* intrinsic_matrix, CvMat* distortion_coeffs, CvMat* rotation_vectors=NULL, CvMat* translation_vectors=NULL, int flags=0 );
- object_points
- 定标点的世界坐标,为3xN或者Nx3的矩阵,这里N是所有视图中点的总数。
- image_points
- 定标点的图像坐标,为2xN或者Nx2的矩阵,这里N是所有视图中点的总数。
- point_counts
- 向量,指定不同视图里点的数目,1xM或者Mx1向量,M是视图数目。
- image_size
- 图像大小,只用在初始化内参数时。
- intrinsic_matrix
- 输出内参矩阵(A) ,如果指定CV_CALIB_USE_INTRINSIC_GUESS和(或)CV_CALIB_FIX_ASPECT_RATION,fx、fy、
cx和cy部分或者全部必须被初始化。 - distortion_coeffs
- 输出大小为4x1或者1x4的向量,里面为形变参数[k1, k2, p1, p2]。
- rotation_vectors
- 输出大小为3xM或者Mx3的矩阵,里面为旋转向量(旋转矩阵的紧凑表示方式,具体参考函数cvRodrigues2)
- translation_vectors
- 输出大小为3xM或Mx3的矩阵,里面为平移向量。
- flags
- 不同的标志,可以是0,或者下面值的组合:
- CV_CALIB_USE_INTRINSIC_GUESS -内参数矩阵包含fx,fy,cx和cy的初始值。否则,(cx,cy)被初始化到图像中心(这儿用到图像大小),焦距用最小平方差方式计算得到。注意,如果内部参数已知,没有必要使用这个函数,使用cvFindExtrinsicCameraParams2则可。
- CV_CALIB_FIX_PRINCIPAL_POINT -主点在全局优化过程中不变,一直在中心位置或者在其他指定的位置(当CV_CALIB_USE_INTRINSIC_GUESS设置的时候)。
- CV_CALIB_FIX_ASPECT_RATIO -优化过程中认为fx和fy中只有一个独立变量,保持比例fx/fy不变,fx/fy的值跟内参数矩阵初始化时的值一样。在这种情况下,(fx,fy)的实际初始值或者从输入内存矩阵中读取(当CV_CALIB_USE_INTRINSIC_GUESS被指定时),或者采用估计值(后者情况中fx和fy可能被设置为任意值,只有比值被使用)。
- CV_CALIB_ZERO_TANGENT_DIST –切向形变参数(p1, p2)被设置为0,其值在优化过程中保持为0。
函数cvCalibrateCamera2从每个视图中估计相机的内参数和外参数。3维物体上的点和它们对应的在每个视图的2维投影必须被指定。这些可以通过使用一个已知几何形状且具有容易检测的特征点的物体来实现。这样的一个物体被称作定标设备或者定标模式,OpenCV有内建的把棋盘当作定标设备方法(参考cvFindChessboardCorners)。目前,传入初始化的内参数(当CV_CALIB_USE_INTRINSIC_GUESS不被设置时)只支持平面定标设备(物体点的Z坐标必须为全0或者全1)。不过3维定标设备依然可以用在提供初始内参数矩阵情况。在内参数和外参数矩阵的初始值都计算出之后,它们会被优化用来减小反投影误差(图像上的实际坐标跟cvProjectPoints2计算出的图像坐标的差的平方和)。
[编辑]
FindExtrinsicCameraParams2
计算指定视图的摄像机外参数
void cvFindExtrinsicCameraParams2( const CvMat* object_points, const CvMat* image_points, const CvMat* intrinsic_matrix, const CvMat* distortion_coeffs, CvMat* rotation_vector, CvMat* translation_vector );
- object_points
- 定标点的坐标,为3xN或者Nx3的矩阵,这里N是视图中的个数。
- image_points
- 定标点在图像内的坐标,为2xN或者Nx2的矩阵,这里N是视图中的个数。
- intrinsic_matrix
- 内参矩阵(A) 。
- distortion_coeffs
- 大小为4x1或者1x4的向量,里面为形变参数[k1,k2,p1,p2]。如果是NULL,所有的形变系数都为0。
- rotation_vector
- 输出大小为3x1或者1x3的矩阵,里面为旋转向量(旋转矩阵的紧凑表示方式,具体参考函数cvRodrigues2)。
- translation_vector
- 大小为3x1或1x3的矩阵,里面为平移向量。
函数cvFindExtrinsicCameraParams2使用已知的内参数和某个视图的外参数来估计相机的外参数。3维物体上的点坐标和相应的2维投影必须被指定。这个函数也可以用来最小化反投影误差。
[编辑]
Rodrigues2
进行旋转矩阵和旋转向量间的转换
int cvRodrigues2( const CvMat* src, CvMat* dst, CvMat* jacobian=0 );
- src
- 输入的旋转向量(3x1或者1x3)或者旋转矩阵(3x3)。
- dst
- 输出的旋转矩阵(3x3)或者旋转向量(3x1或者1x3)
- jacobian
- 可选的输出雅可比矩阵(3x9或者9x3),关于输入部分的输出数组的偏导数。
函数转换旋转向量到旋转矩阵,或者相反。旋转向量是旋转矩阵的紧凑表示形式。旋转向量的方向是旋转轴,向量的长度是围绕旋转轴的旋转角。旋转矩阵R,与其对应的旋转向量r,通过下面公式转换:
反变换也可以很容易的通过如下公式实现:
旋转向量是只有3个自由度的旋转矩阵一个方便的表示,这种表示方式被用在函数cvFindExtrinsicCameraParams2和cvCalibrateCamera2内部的全局最优化中。
[编辑]
Undistort2
校正图像因相机镜头引起的变形
void cvUndistort2( const CvArr* src, CvArr* dst, const CvMat* intrinsic_matrix, const CvMat* distortion_coeffs );
- src
- 原始图像(已经变形的图像)。只能变换32fC1的图像。
- dst
- 结果图像(已经校正的图像)。
- intrinsic_matrix
- 相机内参数矩阵,格式为 。
- distortion_coeffs
- 四个变形系数组成的向量,大小为4x1或者1x4,格式为[k1,k2,p1,p2]。
函数cvUndistort2对图像进行变换来抵消径向和切向镜头变形。相机参数和变形参数可以通过函数cvCalibrateCamera2取得。使用本节开始时提到的公式,对每个输出图像像素计算其在输入图像中的位置,然后输出图像的像素值通过双线性插值来计算。如果图像得分辨率跟定标时用得图像分辨率不一样,fx、fy、cx和cy需要相应调整,因为形变并没有变化。
[编辑]
InitUndistortMap
计算形变和非形变图像的对应(map)
void cvInitUndistortMap( const CvMat* intrinsic_matrix, const CvMat* distortion_coeffs, CvArr* mapx, CvArr* mapy );
- intrinsic_matrix
- 摄像机内参数矩阵(A) [fx 0 cx; 0 fy cy; 0 0 1].
- distortion_coeffs
- 形变系数向量[k1, k2, p1, p2],大小为4x1或者1x4。
- mapx
- x坐标的对应矩阵。
- mapy
- y坐标的对应矩阵。
函数cvInitUndistortMap预先计算非形变对应-正确图像的每个像素在形变图像里的坐标。这个对应可以传递给cvRemap函数(跟输入和输出图像一起)。
[编辑]
FindChessboardCorners
寻找棋盘图的内角点位置
int cvFindChessboardCorners( const void* image, CvSize pattern_size, CvPoint2D32f* corners, int* corner_count=NULL, int flags=CV_CALIB_CB_ADAPTIVE_THRESH );
- image
- 输入的棋盘图,必须是8位的灰度或者彩色图像。
- pattern_size
- 棋盘图中每行和每列角点的个数。
- corners
- 检测到的角点
- corner_count
- 输出,角点的个数。如果不是NULL,函数将检测到的角点的个数存储于此变量。
- flags
- 各种操作标志,可以是0或者下面值的组合:
- CV_CALIB_CB_ADAPTIVE_THRESH -使用自适应阈值(通过平均图像亮度计算得到)将图像转换为黑白图,而不是一个固定的阈值。
- CV_CALIB_CB_NORMALIZE_IMAGE -在利用固定阈值或者自适应的阈值进行二值化之前,先使用cvNormalizeHist来均衡化图像亮度。
- CV_CALIB_CB_FILTER_QUADS -使用其他的准则(如轮廓面积,周长,方形形状)来去除在轮廓检测阶段检测到的错误方块。
函数cvFindChessboardCorners试图确定输入图像是否是棋盘模式,并确定角点的位置。如果所有角点都被检测到且它们都被以一定顺序排布(一行一行地,每行从左到右),函数返回非零值,否则在函数不能发现所有角点或者记录它们地情况下,函数返回0。例如一个正常地棋盘图右8x8个方块和7x7个内角点,内角点是黑色方块相互联通地位置。这个函数检测到地坐标只是一个大约地值,如果要精确地确定它们的位置,可以使用函数cvFindCornerSubPix。
[编辑]
DrawChessBoardCorners
绘制检测到的棋盘角点
void cvDrawChessboardCorners( CvArr* image, CvSize pattern_size, CvPoint2D32f* corners, int count, int pattern_was_found );
- image
- 结果图像,必须是8位彩色图像。
- pattern_size
- 每行和每列地内角点数目。
- corners
- 检测到地角点数组。
- count
- 角点数目。
- pattern_was_found
- 指示完整地棋盘被发现(≠0)还是没有发现(=0)。可以传输cvFindChessboardCorners函数的返回值。
当棋盘没有完全检测出时,函数cvDrawChessboardCorners以红色圆圈绘制检测到的棋盘角点;如果整个棋盘都检测到,则用直线连接所有的角点。
[编辑]
姿态估计
[编辑]
CreatePOSITObject
初始化包含对象信息的结构
CvPOSITObject* cvCreatePOSITObject( CvPoint3D32f* points, int point_count );
- points
- 指向三维对象模型的指针
- point_count
- 对象的点数
函数 cvCreatePOSITObject 为对象结构分配内存并计算对象的逆矩阵。
预处理的对象数据存储在结构CvPOSITObject中,只能在OpenCV内部被调用,即用户不能直接读写数据结构。用户只可以创建这个结构并将指针传递给函数。
对象是在某坐标系内的一系列点的集合,函数 cvPOSIT计算从照相机坐标系中心到目标点points[0] 之间的向量。
一旦完成对给定对象的所有操作,必须使用函数cvReleasePOSITObject释放内存。
[编辑]
POSIT
执行POSIT算法
void cvPOSIT( CvPOSITObject* posit_object, CvPoint2D32f* image_points, double focal_length, CvTermCriteria criteria, CvMatr32f rotation_matrix, CvVect32f translation_vector );
- posit_object
- 指向对象结构的指针
- image_points
- 指针,指向目标像素点在二维平面图上的投影。
- focal_length
- 使用的摄像机的焦距
- criteria
- POSIT迭代算法程序终止的条件
- rotation_matrix
- 旋转矩阵
- translation_vector
- 平移矩阵.
函数 cvPOSIT执行POSIT算法。图像坐标在摄像机坐标系统中给出。焦距可以通过摄像机标定得到。算法每一次迭代都会重新计算在估计位置的透视投影。
两次投影之间的范式差值是对应点中的最大距离。如果差值过小,参数criteria.epsilon就会终止程序。
[编辑]
ReleasePOSITObject
释放3D对象结构
void cvReleasePOSITObject( CvPOSITObject** posit_object );
- posit_object
- 指向CvPOSIT 结构指针的指针。
函数 cvReleasePOSITObject 释放函数 cvCreatePOSITObject分配的内存。
[编辑]
CalcImageHomography
计算长方形或椭圆形平面对象(例如胳膊)的Homography矩阵
void cvCalcImageHomography( float* line, CvPoint3D32f* center, float* intrinsic, float* homography );
- line
- 对象的主要轴方向,为向量(dx,dy,dz).
- center
- 对象坐标中心 ((cx,cy,cz)).
- intrinsic
- 摄像机内参数 (3x3 matrix).
- homography
- 输出的Homography矩阵(3x3).
函数 cvCalcImageHomography 为从图像平面到图像平面的初始图像变化(defined by 3D oblongobject line)计算Homography矩阵。
[编辑]
对极几何(双视几何)
[编辑]
FindFundamentalMat
由两幅图像中对应点计算出基本矩阵
int cvFindFundamentalMat( const CvMat* points1, const CvMat* points2, CvMat* fundamental_matrix, int method=CV_FM_RANSAC, double param1=1., double param2=0.99, CvMat* status=NULL);
- points1
- 第一幅图像点的数组,大小为2xN/Nx2 或 3xN/Nx3 (N点的个数),多通道的1xN或Nx1也可以。点坐标应该是浮点数(双精度或单精度)。:
- points2
- 第二副图像的点的数组,格式、大小与第一幅图像相同。
- fundamental_matrix
- 输出的基本矩阵。大小是 3x3 或者 9x3 ,(7-点法最多可返回三个矩阵).
- method
- 计算基本矩阵的方法
- CV_FM_7POINT – 7-点算法,点数目= 7
- CV_FM_8POINT – 8-点算法,点数目 >=8
- CV_FM_RANSAC – RANSAC 算法,点数目>= 8
- CV_FM_LMEDS - LMedS 算法,点数目 >=8
- param1
- 这个参数只用于方法RANSAC 或 LMedS。它是点到对极线的最大距离,超过这个值的点将被舍弃,不用于后面的计算。通常这个值的设定是0.5 or 1.0 。
- param2
- 这个参数只用于方法RANSAC 或 LMedS 。 它表示矩阵正确的可信度。例如可以被设为0.99 。
- status
- 具有N个元素的输出数组,在计算过程中没有被舍弃的点,元素被被置为1;否则置为0。这个数组只可以在方法RANSAC and LMedS情况下使用;在其它方法的情况下,status一律被置为1。这个参数是可选参数。
对极几何可以用下面的等式描述:
其中 F 是基本矩阵,p1 和 p2 分别是两幅图上的对应点。
函数 FindFundamentalMat利用上面列出的四种方法之一计算基本矩阵,并返回基本矩阵的值:没有找到矩阵,返回0,找到一个矩阵返回1,多个矩阵返回3。计算出的基本矩阵可以传递给函数cvComputeCorrespondEpilines来计算指定点的对极线。
例子1:使用 RANSAC 算法估算基本矩阵。 int numPoints = 100; CvMat* points1; CvMat* points2; CvMat* status; CvMat* fundMatr; points1 = cvCreateMat(2,numPoints,CV_32F); points2 = cvCreateMat(2,numPoints,CV_32F); status = cvCreateMat(1,numPoints,CV_32F); fundMatr = cvCreateMat(3,3,CV_32F); int num = cvFindFundamentalMat(points1,points2,fundMatr,CV_FM_RANSAC,1.0,0.99,status); if( num == 1 ) printf("Fundamental matrix was found\n"); else printf("Fundamental matrix was not found\n"); 例子2:7点算法(3个矩阵)的情况。 CvMat* points1; CvMat* points2; CvMat* fundMatr; points1 = cvCreateMat(2,7,CV_32F); points2 = cvCreateMat(2,7,CV_32F); fundMatr = cvCreateMat(9,3,CV_32F); int num = cvFindFundamentalMat(points1,points2,fundMatr,CV_FM_7POINT,0,0,0); printf("Found %d matrixes\n",num);
[编辑]
ComputeCorrespondEpilines
为一幅图像中的点计算其在另一幅图像中对应的对极线。
void cvComputeCorrespondEpilines( const CvMat* points, int which_image, const CvMat* fundamental_matrix, CvMat* correspondent_lines);
- points
- 输入点,是2xN 或者 3xN 数组 (N为点的个数)
- which_image
- 包含点的图像指数(1 or 2)
- fundamental_matrix
- 基本矩阵
- correspondent_lines
- 计算对极点, 3xN数组
函数 ComputeCorrespondEpilines根据外级线几何的基本方程计算每个输入点的对应外级线。如果点位于第一幅图像(which_image=1),对应的对极线可以如下计算 :
其中F是基本矩阵,p1 是第一幅图像中的点, l2 -是与第二幅对应的对极线。如果点位于第二副图像中 which_image=2),计算如下:
其中p2 是第二幅图像中的点,l1 是对应于第一幅图像的对极线,每条对极线都可以用三个系数表示a, b, c:
归一化后的对极线系数存储在correspondent_lines 中。
[编辑]
ConvertPointsHomogenious
Convert points to/from homogenious coordinates
void cvConvertPointsHomogenious( const CvMat* src, CvMat* dst );
- src
- Theinput point array, 2xN, Nx2, 3xN, Nx3, 4xN or Nx4 (where N is thenumber of points). Multi-channel 1xN or Nx1 array is alsoacceptable.
- dst
- Theoutput point array, must contain the same number of points as theinput; The dimensionality must be the same, 1 less or 1 more thanthe input, and also within 2..4.
The function cvConvertPointsHomogenious converts 2D or 3D pointsfrom/to homogenious coordinates, or simply copies or transposes thearray. In case if the input array dimensionality is larger than theoutput, each point coordinates are divided by the lastcoordinate:
- (x,y[,z],w) -> (x‘,y‘[,z‘])
- 其中
- x‘ =x/w
- y‘ =y/w
- z‘ =z/w (if output is 3D)
If the output array dimensionality is larger, an extra 1 isappended to each point.
(x,y[,z]) -> (x,y[,z],1)
Otherwise, the input array is simply copied (with optionaltranposition) to the output. Note that, because the functionaccepts a large variety of array layouts, it may report an errorwhen input/output array dimensionality is ambiguous. It is alwayssafe to use
the function with number of points N>=5, or to usemulti-channel Nx1 or 1xN arrays.
分享:
基础矩阵
单应矩阵
ransac匹配
为什么要标定
标定的作用其一就是为了求取畸变系数(因为经过镜头等成像后,或多或少都有畸变),其二是为了得到空间坐标系和图像坐标系的对应关系。标定的过程就是一个最小化的求取参数的过程,拍的图越多(相当于输入)结果越准确,至少10张以上吧,而且尽可能覆盖视野各个角落,要偏转一定角度,这样得出的参数是只用于整个场景的
。
作者:金秉文
链接:http://www.zhihu.com/question/29448299/answer/74502055
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
相机标定的目的是确定相机的一些参数的值。通常,这些参数可以建立定标板确定的三维坐标系和相机图像坐标系的映射关系,换句话说,你可以用这些参数把一个三维空间中的点映射到图像空间,或者反过来。
相机需要标定的参数通常分为内参和外参两部分。外参确定了相机在某个三维空间中的位置和朝向,至于内参,可以说是相机内部的参数(这好像是废话...笑),我觉得需要引入一点光学的东西来更好地解释一下。现有的相机都至少包含一个光学镜头和一个光电传感器(CCD或CMOS)。
通过镜头,一个三维空间中的物体经常会被映射成一个倒立缩小的像(当然显微镜是放大的,不过常用的相机都是缩小的),被传感器感知到。
- 理想情况下,镜头的光轴(就是通过镜头中心垂直于传感器平面的直线)应该是穿过图像的正中间的,但是,实际由于安装精度的问题,总是存在误差,这种误差需要用内参来描述;
- 理想情况下,相机对x方向和y方向的尺寸的缩小比例是一样的,但实际上,镜头如果不是完美的圆,传感器上的像素如果不是完美的紧密排列的正方形,都可能会导致这两个方向的缩小比例不一致。内参中包含两个参数可以描述这两个方向的缩放比例,不仅可以将用像素数量来衡量的长度转换成三维空间中的用其它单位(比如米)来衡量的长度,也可以表示在x和y方向的尺度变换的不一致性;
- 理想情况下,镜头会将一个三维空间中的直线也映射成直线(即射影变换),但实际上,镜头无法这么完美,通过镜头映射之后,直线会变弯,所以需要相机的畸变参数来描述这种变形效果。
然后,说到为什么需要20张图片,这只是一个经验值,实际上太多也不好,太少也不好。单纯从统计上来看,可能越多会越好,但是,实际上图片太多可能会让参数优化的结果变差,因为棋盘格角点坐标的确定是存在误差的,而且这种误差很难说是符合高斯分布的,同时,标定过程所用的非线性迭代优化算法不能保证总是得到最优解,而更多的图片,可能会增加算法陷入局部最优的可能性。
拍照时的标定板位置和朝向的多样性,会让内参的估计更为准确。准确的内参可以较好地把整个图像的畸变都进行矫正,但如果给定的标定板的位置过于单一,比如都是在图像的左上角,那么优化得到的内参也可能只会比较好地纠正图像左上角的畸变。推荐找个畸变较大的镜头做做实验,会更形象。
作者:立党
链接:http://www.zhihu.com/question/29448299/answer/74327790
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
在去除畸变的情况下,相机标定就是求intrinsic matrix——K,因为3D点可以用(X,Y,Z,1)表示,2D点可以用(X,Y,1)来表示,因此3*3的矩阵K就包含了全部相机模型的内部参数(intrinsic matrix),K[R|t]就是三维点到二维点的线性变化关系(R是3-by-3 Rotation,t是translation,如果以其中一个相机C0为Reference Camera,那么R=eyes(3),t=[0,0,0]‘,其他的R和t都是关于C0的R和t)。
在去除畸变的理想情况下,K的参数可以一一对应到针孔相机的焦距f,offset (x0,y0)以及skew s四个参数上,具体关系为K=[fx,s,x0;0,fy,y0;0,0,1]。理想情况的针孔相机,fx=fy,但是在大部分实测情况下,fx和fy之间仍然会有误差。
理想状态下,Zhang‘s method的二维标定板的摆放不影响标定结果。但考虑到三维点实际投射到相机sensor上的误差符合Gaussian distribution,因此尽量把所有网格包含在图像内,不要角度过于偏,过于远乃至偏到了toolbox无法精确提取calibration board的边界即可。
畸变模型可以是高阶线性甚至非线性的,通常相机厂商已经内置了去畸变的方法,输出的图像很精准了,当然如果有再次去畸变的要求可以阅读相关论文,反正我最高也只实现过三次线性畸变移除。
20张当然不是定数,但理论上张数越多,normalize之后解中间那个矩阵误差越小,上课时老师讲过误差分析,具体的我一时想不起来,Berkeley的课件上应该有。
当然也有三维的标定方法(拿一组三维的,互成90度的黑白格放在一起,并提取其中若干点),一维的标定(也是张正友提出的方法,在一根木棒上标定若干点,然后把一端放在桌子上,另一端做圆锥形运动,拍下若干张。这也是我上这门课的final project)等等等等。总之都是用几何关系尽可能地找到K。
k1和k2是径向形变系数,p1和p1是切向形变系数。OpenCV中没有考虑高阶系数。形变系数跟拍摄的场景无关,因此它们是内参数,而且与拍摄图像的分辨率无关。
后面的函数使用上面提到的模型来做如下事情:
- 给定内参数和外参数,投影三维点到图像平面。
- 给定内参数、几个三维点坐标和其对应的图像坐标,来计算外参数。
- 根据已知的定标模式,从几个角度(每个角度都有几个对应好的3D-2D点对)的照片来计算相机的外参数和内参数。
三个坐标系
如上图表示的三个坐标系分别为世界坐标系,摄像机坐标系,图像坐标系
1:世界坐标系(Xw Yw Zw)
用户定义的空间三维坐标系,用来描述三维空间中的物体和相机之间的坐标位置,满足右手法则
2:摄像机坐标系(Xc Yc Zc)
以相机的光心作为原点,Zc轴与光轴重合,并垂直于成像平面,且取摄影方向为正方向,Xc、Yc轴与图像物理坐标系的x,y轴平行,且OcO为摄像机的焦距f
3:图像坐标系
是以图像的左上方为原点,的图像坐标系(uv)(此坐标以像素为单位),这里我们建立了图像物理坐标系(x y)为xoy坐标系(此坐标系以毫米为单位)。