投影与三维视觉
TODO
第50页
OCR文字识别结果:
为达此目的我们将继续沿用第11章的一些原理摄像机内参数矩阵M、畸变参
数、旋转矩阵R、平移向量7以及单应性矩阵H.
首先讨论使用标定后的摄像机到三维世界的投影,并回顾仿射和投影变换(第一次
在第6章遇见),然后给出一个获得地平面鸟瞰图的程序实例®。接下来,我们还将
对POSIT算法进行讨论,该算法可以让我们从一幅图像中査找获得已知三维物体
的三维姿态(位置和旋转角度)。
然后我们转到多幅图像的三维几何问题。一般情况下,没有可靠的方法可以做到不
依赖多幅图像就可以进行标定或提取3D信息。利用多幅图像重建三维场景的最常
见情形就是立体视觉。在立体视觉中,同时在不同位置上拍摄两幅图像(或者更多)
中的特征,然后对图像中的相应特征进行匹配,分析其中的差异,从而获得深度信
息。另一个情形是从运动中得到结构。这种情况下,我们可能只用一个摄像机,但
是要在不同时间从不同的地方拍摄多幅图像。对前者而言,我们主要对视差效应
(三角剖分)感兴趣,并作为计算距离的一种方法而后者,则是通过计算基础矩阵
(将两个不同场景联系到一起)来获得场景理解的数据源。下面我们开始介绍投影的
相关内容。
投影
一旦对摄像机完成了标定(见第11章),就有能将现实物理世界中的点无歧义地投
国这是在机器人技术以及其他很多视觉应用中常见的问题。
投影与三维视觉441
L
第12章
第51页
OCR文字识别结果:
,影到图像上。这意味着给定对于摄像机三维物理坐标框架下的位置,我们可以计算
该三维点在成像仪中的坐标,即像素坐标。在OpencV中,这个转换过程通过函
数cvprojectpoints20来实现的。
void cvprojectpoints2(
const CvMat * obj ect-points,
const CvMat* rotation-vector,
const CvMat* translation-vect. or,
const CvMat* intrinsic-matrix,
const CvMat* distortio'n-coeffs,
const CvMat*
const CvMat*
CvMat *
CvMat ·
CvMat *
CvMat *
CvMat *
CvMat ·
doubt e
image_po I nt s,
dpdrot NULL,
dpdt NULL,
dpdf NULL,
dpdc NULL,
dpddi s t NULL,
aspect Ratio
仅仅从参数个数来看,这个函数可能有一些吓人,但实际上,它是一个使用简单的
函数。函数cvprojectpoints20被设计用来适应这样的场景(非常普通),即欲投
影的点位于某些刚体上。这种情况下,就自然地不是用摄像机坐标系统表示这些点
的位置,而是用以物体本体为中心的坐标系来表示这些点的位置。然后用旋转和平
移定义物体坐标系和摄像机坐标系之间的关系。事实上,函数
cvprojectpoints2o在函数cvcalibratecamera2o的内部被调用,这也是函数
cvcalibrate-camera2o组织自身内部操作的方式。所有可选参数都是被函数
cvcalibrate-camera2o使用,但熟练的用户可以根据自己的需求来方便地使用
这些参数。
第一个参数object_points是需要投影的点序列,它是一个包含点位置的N×3
矩阵。可以给这些点赋以物体自身的坐标系,然后提供一个3×l的旋转矩阵
rota仁ion_vector®和translation_vector来建立两个坐标系的联系。如果在特
定的环境下,直接使用摄像机坐标系更方便,可以只设定该坐标系下的
object_poln·s,并把rotatio。_vect·r和translat上on_veccor内的元素置为(严。
®旋转向量通常以弧度表示。
园记住,这个旋转向量是按轴旋转来表示,所以如果设置为全O,则意味着它的长度为
O,故无旋转。
442第12章
第52页
OCR文字识别结果:
pr
参数intrinsic_matrix和distortion_coeffs与来自第·11章中讨论的函数
cvcalibratecamera20里面的摄像机内参数和畸变系数是一样的。参数
image_points是一个JV × 2的矩阵,将被写人计算结果。
最后,长长的可选参数dpdrot,dpd七,dpdf,dpdc和dpddis七都是偏导数的雅
可比矩阵,这些矩阵将图像点和每个不同的输入参数联系起来。具体来说,
己pdro匕是与旋转向量部分相关的图像点的偏导数,为N×3矩阵I dpd七是关于与
平移向量部分相关的图像点的偏导数,为N×3矩阵\dp己f是关于f。和」,的图像点
的偏导数,为N×2矩阵,dpdc是关于c.和c,的图像点的偏导数,为N×2矩阵,
dp己dist是关于畸变系数的图像点的偏导数,为N×4矩阵。大多数情况下,这些
参数被默认设置为NuL乙,不参与计算。最后一个参数aspect Ratio也是可选的,
在函数cvcalibratecamera20或者函数cvs七ereocalibrateo中,当方向比固
定时,它被用来导数运算。如果aspec七Ratio不为O,导数dpdf被调整。
[406-407]
仿射变换和透视变换
在OpencV中,经常出现和讨论的两个变换就是仿射变换和透视变换(在其他的自
己编写的应用软件中也同样如此)。我们第一次是在第6章遇到了这些变换。如
OpencV所实现的那样,这些程序作用于点序列或整幅图像。它们把图像上的点从
一个位置映射到另外一个位置,通常还伴随着亚像素的插值。回忆一下,仿射变换
可以将矩形映射为任意平行四边形而更一般的情形是,透视变换将矩形映射为任
意四边形。
透视变换(perspective transformation)与透视投影(perspective projection)关系密切。
透视投影是使用中心投影法,沿着一系列最终汇聚到一个被称为投影中心(center of
projection)的点的投影线,将三维物理世界中的点投影变换到二维图像平面中。投
影变换是一种特定的单应性变换cD,是将同一个三维物体分别投影到两个不同投影
平面下的两幅图像联系起来(因此,针对的是与三维物体相交的平面,具有不同投
影中心的非退化配置)。
与这些投影变换相关的函数在第6章中已经做了详细的论述,为方便起见,我1,门仅
仅在这里做个简单的汇总,见表12.1.
出回想第11章,这种特殊的单应性变换也称为平面单应性变换。
投影与三维视觉443
第53页
OCR文字识别结果:
了
表12-1仿射变换和透视变换函数
cvTransformo点序列的仿射变换,
cvWarpA田ne0整个图像的仿射变换
cvGetAffineTransformo
cv2DRotation Matrixo
cvGetQuadrangl es ubp ixo
cvperspectiveTransformo
cvwarpperspectiveo
cvGetperspectiveTransformo得到透视变换矩阵参数
[407]
鸟瞰图变换实例
机器人导航的一项常见工作就是将机器人场景的摄像机视图转换到从上到下的。俯
视。视图。在图12-I中,场景的机器人视图转换成了鸟瞰图,使得视图就可以被
随后的由扫描激光测距仪创建的世界场景覆盖。结合我们已学的知识,接下来我们
将详细地来说明如何利用标定的摄像机计算这样的一个鸟瞰图。【408】
为了获得鸟瞰图®,我们需要从标定程序中得到摄像机内参数和畸变参数矩阵。仅
仅为了程序的多选择性,我们选择从硬盘读取文件。在地面上放置一个棋盘,从机
器人车上获得它的地平面图像,然后将图像重新映射为鸟瞰图。具体算法流程
如下。
1,读取摄像机的内参数和畸变参数模型。
2.査找地平面上的已知物体(如本例中的棋盘),获得最少4个亚像素精度上
的点。
3将找到的点输入到函数cvGetperspectiveTransformj中(参见第6章),计算地
平面视图的驻应矩阵H.
使用函数cy1Ndi-pperspecti·e0(还是参见第6章),设置标志CV_INTER一
LINEAR CV_1NARP_INVERSE_MAP + CV_WARP_FILL_OUTLIERS, 获得地平面
的前向平行视图(鸟瞰图)。
区)潋视图技术也可以应用于将任意平面(如墙或天花板)透视变换到前向平行视图。
444第12章
得到访射变换矩阵参数
得到仿射变换矩阵参数
低开销的图像仿射变换
点序列的透视变换
整个图像的透视变换
第54页
OCR文字识别结果:
歹
图1 2-1鸟瞰图。安装在机器人轿车里的摄像机对道路场景进行扫描,激光测
距仪识别定位出车前面的。道路。区域,并用框线标记(上图)视觉算法对平
坦的。似道路。区域进行分割(中图)分割后的道路区域转换成鸟瞰图,并和
鸟瞰图上的激光图进行图像融合(下图)
国「
例12-1给出了鸟瞰图的全部代码。
例12-1鸟域图
//cal1
// birds-eye b aard_w board_h instrinics distor ti Dn image_file
// ADJUST VIEW HEIGHT using keys u'up, d'down. ESC to qu]-t
int main(1nt arge, char* argvt] )
if ( arge !. 6 ) return 1
/ / INPUT-PARAMETERS
投影与三维视觉445
L
第55页
OCR文字识别结果:
int board-w-atoi ( argv[1] )
int board-h · atoi{argv [2] ) I
int board-n-board-w * bobrd-h
Cvsize', board-sz-cvsize( board-w, board-h )
CvMat* intrinsic = (CvMat* ) cvLoad ( argv[3] )
CvMat * distortion = ( CvMat* ) cvLoad ( argv[a] )
l'
Iplimage"image = Oi ·
Iplimage"gray-image = O
if ( ( image = cvLoadlmage ( argv[5] ) ) == O )
prinQ · f(" Error Couldn't load %s\n", argv[5])
return-1
gray-lrpage = cvcreatelmage( cvGetsize ( image ), 8, 1 )
cvcvtcolor{image, gray-image, CV_BGR2GRAY )
/ / UNDI STORT OUR IMAGE
Iplimage * mapx cvcreatelmage ( cvGetsize(image ), LPL_DEPTH_32F, 1 )
Iplimage"mapy cvcreatelmage ( cvGetsize(image ), IPL_DEPTH_32F, 1 )
/ /his initializes rectification matrices
cvlnitundistort Map (
intrinsic,
di stortion,
mapx,
mapy
Iplimage *t cvc1onelmage ( image )
/ / Rectify our image
cvRemap( t, image, mapx, mapy )
/ / GET THE CHESSBOARD ON THE PLANS
cvNamedwindow("Chessboard")
Cvpoint2D32f* corners = new Cvpoint2D32f [ board-n ]
int corner count-o
inr found-cvFindchessboardcorners(
1T门二八口
1 mag e,
board-s z,
:. 446 g 12 章
第56页
OCR文字识别结果:
'"'=ill«llji W h mw
corners,
& corner_count,
CV_CALIB_CB_ADAPTIVE_THRESH CV_CALIB_CB_FILTER_QUADG
if ( ! found ) {
printf ("Couldn't aquire chessboard on %s,
"only found %d of %d corners \ n",
argv[5], corner_count, board_n
return-1
/ /Get Subpixel accuracy on those corners
cvFindcornersubpix (
gr ay_image,
corners,
corner_count,
cvTermcriteria( CV_TERMCRIT_EPS I CV_TERMCRIT_ITER, 30, 0. 1
/ / GET THE IMAGE AND OBJECT POINTS
/ / We will choose chessboarcl object points as ( r, c )
Cvpoint2D32f objpts[a], imgpts[a]
objpts[O]. x O objpts[O]. y 0
obj Pts[1]. x board_w-1 obj Pts[1]. y-0
obj Pts[2]. x O obj Pts [2]. y-board_b-1
objpts[3]-x board_w-1 objpts[3]. y-board_h-1
imgpts[O] corners[O]
imgpts[1] corners[board_w-1]
imgpts [2] corners [(board_h-1 ) * board_w]
imgpts [3] corners [[board_h-1 ) · board_w + board_w-1 1
//DRAW THE POINTS in order B, G, R, YELLOW
cvcircle( image, cvpoint From32f ( imgpts[O] ), 9, CV_RGB(O, 0, 255 ), 3 )
cvci rc1 e( image, cvpoint From32 f(imgpt s[1] ), 9, CV_RGB(0, 2 5 5, 0 ), 3 )
cvci rele ( image, cvpoint From32 f ( lmgpt s [2 ] ), 9, CV_RGB ( 2 5 5, 0, 0 ), 3 )
cvcircle( image, cvpoint From32 f ( imgpts [3 ] ), 9, CV_RGB ( 2 5 5, 2 5 5, 0 ), 3 )
投影与三维视觉447
第57页
OCR文字识别结果:
/ /DRAW THE FOUND CHESSBOARD
cvDrawchessboardcorners (
image,
board_s z,
corner_count,
found
cvshowlmage("Chessboard", image )
/ / FIND THE HOMOGRAPHY
CvMat *H-cvcreate Matl 3, 3, CV-32F )
cvGetperspective Trans formi obj Pts, imgpt s, H )
//LET THE USER ADJUST THE Z HEIGHT OF THE VIEW
float Z 25
int key O
Iplimage *birds_image cvc1onelmage ( image )
cvNamedwindow("Birds_Eye")
//L00P TO ALLOW USER TO PLAY WITH HEIGHT
// escape key stops
while(key旧回国27)
// Set the height
CV-MAT-ELEM(*H, float, 2, 2 ) = Z
/ / COMPUTE THE FRONTAL PARALLEL OR BIRD'S-EYE VIEW
/ / USING HOMOGRAPHY TO REMAP THE VIEW
cvwarpperspect ive(
image,
birds-image,
H,
CV INTER LINEAR CV-WARP-INVERSE-MAP CV-WARP FILL-OUTLIERS
448第12章
第58页
OCR文字识别结果:
cvshowlmage ("Birds-Eye", birds-image )
key cvwait Keyo
if ( key == u') Z += 0. 5
if ( key =. d') Z 0. 5
cvsave(" H. xm1", H) //we can reuse H for the same camera mounting
return o
一旦知道单应矩阵和高度参数集后,就能去除图像中的棋盘和车,制作出道路的鸟
瞰图视频,如何制作鸟瞰图视频留给读者作为练习。图12-2是鸟瞰图代码的输入
图像(左图)和输出图像(右图)。
■二
图12-2鸟瞰图例子
POSIT 3D姿态估计
在进入立体视觉之前,我们首先了解一下一个能够估计已知物体三维位置的算法,
即 POSI 丁 算法. POStT(英文"Pose fr om Orthography and Scaling with [teration"的
缩写)是1992年首次提出的用于计算3D物体(其精确的维数是已知的)的姿态的一
种算法(位置7和方向R由6个参数描述[De Menthon92])。为了计算这个姿态,必
须找到物体表面的至少4个非共面点在相应二维图像上的位置。算法的第一部分,
第59页
OCR文字识别结果:
一一试了正
由正交投影和尺寸变换提取姿态(P0S),并假设物体上的点具有相同的有效滦度国
而且原始模型的大小变化只与其距摄像机的远近比例相关。在这种情况下,基于尺
度变换的物体三维姿态的解是闭合形式的。所有物体点都具有相同有效深度的假设
意味着物体距离摄像机足够远,使得我们可以忽略了各个点在物体内部的深度差
异,这个假设称为。弱透视近似。。
给定已知摄像机的内参数,我们就能求取已知物体的透视缩放比例,从而计算它的
近似姿态。这样计算的精度不高,但是如果真实的三维物体位于通过POS计算出
的近似位置,我们就可以将4个观测点投影到预期的位置上,然后我们将这些新的
点作为POS的输入参数,重新运行一遍POS算法。如此的反复迭代,四五次后算
法便可会收敛到真实的物体姿态,这也是该算法为何被称为。迭代POS算法。的
原因。记住,上述过程是基于这样的假设,即物体的内部深度远远小于物体与摄像
机的距离。如果假设不成立,则算法可能要么不收敛,要么收敛到一个。糟糕的姿
态。。OpencV所实现的这个算法可以允许我们跟踪四个以上的非共商物体点,从
而提高姿态估计的精度。
POSIT算法在Open,。V中有三个相关的函数一个是对每一个单一的物体的姿态
分配数据结构,一个释放该数据结构,一个是POSIT算法的执行函数。
CvpOSiTObject* cvcreatepOSiTObject(
Cvpoin · t3D32f* points,
int point_count
void cvReleaseposiTObject(
CvpOSiTobject** posit_object
函数cvcreatep0SIT0bject0的输入为points(三维点集合)和point_count(表
示点个数的整数),并返回分配好了内存的指向posIT对象结构的指针。而函数
cv只eleaseposITobject o是一个指向上述结构的指针,并且释放该数据结构(在
处理过程中,设置该指针为NuLL)。
void cvPOSIT(
CvPOSiTObject* posit-obj ect,
Cvpoint2D32f* image-points,
该结构查找一个通过与图像平面平行的穿过物体的参考平面,该平面与图像平面有单
一距离值Z.物休上的三维点首先投影到该参考平面上,然后再利用透视映射投影到
图像平面上。这个结果就是比例正交投影,它可以特别容易地将物体大小与深度关联
起来。
450第12章
第60页
OCR文字识别结果:
focal_length,
CvTermcriteria criteria,
float* rotation_matrix,
float* translation_vector
) [411-412]
现在,回到posIT函数本身,函数cvpoSITO的参数列表其他大部分函数不同,
这是因为它使用的是早期版本OpencV中所用的。旧的。参数风格©。这里,
posit_object是指向欲跟踪的posIT对象结构的指针,ima·e_points为图像平
面上对应点的位置列表(注意,这些是运,行亚像素精度的32位浮点数数值)。函数
cvposIT o的当前实现是假设方形像素,因此只使用一个值表示参数
focal_length,而不是原来使用的x和y方向上的两个值。因为函数cvposITO
是个迭代算法,它需要一个迭代终止准则该准则提示何时结果已经足够好,迭代
可以结束。最后两个参数rotation_matrix和translation_vector与早期函数
的同名参数意义相同,它们是指向浮点型的指针,因此可以通过调用函数
cvcalibratecamera2 0来获得矩阵的数据部分信息。这种情况下,给定矩阵M,
便可以使用M-》data.f1作为函数cvpoSITO中的参数。
使用posIT时,请记住,增加物体表面上的共面点,并不能使算法执行得更好。
若一个点位于其他三个点定义的平面上,那么这样的点对算法不会有任何贡献。实
际上,多余的共面点往往会导致算法性能降低。而多余的非共面点,则对算法有好
处。图12-3给出了POSIT算法在玩具飞机上的应用[Tanguay00],飞机上有四条标
记线,用来定义4个非共面点。这些点被传入到函数cvposITo中,输出的
ro仁ation_matrix和translation_vector就用来控制飞行模拟器。
图1 2-3POSIT算法的应用。用玩具飞机的四个非共面点控制飞行模拟器
[414]
®可能已注意到很多函数都是以。2。结尾的。这往往是因为当前版本库中的函数参数与
前一版本相比通常发生了改变,因而利用的是较新的参数类型。
第61页
OCR文字识别结果:
立体成像
现在我们正式开始进入立体成像(-tereo imagin吕)®。所有人对眼睛的立体成像能力
都很熟悉,但是在计算机系统内我们可以多大程度地模仿这种立体成像能力呢?计
算机可以在两个成像仪上寻找对应点来完成立体成像。通过这样的对应点和摄像机
之1司已知的基线间隔,我们就可以计算这些点的三维位置。虽然对应点的搜寻需要
很高的计算成本,但是我们可以根据已有系统的几何结构来尽可能地减小捜索空
间。在实际应用中,两台摄像机的立体成像过程包括以下四个步骤。
1.消除畸变使用数学方法消除径向和切线方向上的镜头畸变,第11章已对此
进行了详细描述。这一步输出的是无畸变图像。
2.摄像机校正调整摄像机间的角度和距离,输出行对准o的校正图像。
3图像匹配査找左右摄像机视场中的相同特征@。这一步输出的是视差图,差
值是指左右图像上的相同特征在x坐标上的差值xl-x,。
4.重投影当知道了摄像机的相对几何位置后,就可以将视差图通过三角测量的
方法转成距离。本步骤输出等深度图。
我们先从最后一步说起,然后分析前三步。
三角测量
假设我们已有一套无畸变、对准、已测量好的完美标准立体实验台,如图12-4所
示,两台摄像机的像平面精确位于同一平面上,光轴严格平行(光轴是从投影中心
口朝像主点c方向引出的一条射线,也称为主光线©),距离一定,焦距相同f= f.。
®这里我们仅仅给出高层的理解、更详细论述请参考下面的文献Trucco and Verri
[Trucco98], Hartley 与 Zisserman [Hartley06], Forsyth 与 Ponce [Forsyth03], H 及
Shapiro与Stockman [Shapiro021。这些书中的立体校正部分将给出本章所引用文献的
背景知识。
园我们说的。行对准。是指两图像在同一个平面上,并且图像的每一行是严格对齐的(具
有相同的方向和夕坐标)。
固我们每次提到左右摄W机时、乞表示可能是竖直方向的上下摄W机,不同的只是x方
向上的视差变成了1方向的。
固两条平行主光线是指这两条线在元方远处相交。
452第12章
第62页
OCR文字识别结果:
r
并且假设主点才。和c吵"已经校准,在左右图像上具有相同的像素坐标。注意,不要
将主点和图像中心混为一谈,主点是主光线与像平面的交点,该交点在镜头的光轴
上。我们在第II章提到过,像平面很少与镜头完美地重叠,因此图像中心也几乎
不会和像主点重合。
图12-4利用无畸变对准的标准立体实验台和已知的特征对应点,深度Z可
以通过相似三角形计算出来成像仪的主光线从投影中心01和02出发,并经
过两个像平面的像主点c/和c,
进一步假设两幅图像是行对准的,并且一台摄像机的像素行与另一台完全对准©,
我们称为摄像机前向平行排列。再假设物理世界中的点P在左右图像上的成像点
为pl和p,,相应的横坐标分别为xl和x,。
在这个简单化的例子中,xI和x.分别表示点在左右成像仪上的水平位置,这使得深
度与视差成反比关系,视差简单的定义为d=x/-x,。如图12-4所示,利用相似三
角形可以很容易推导出Z值。由图可知®
国这里提出了好几个假设,但是我们现在只考虑基本假设。请记住,校正的过程(接下来
要说的)就是当这些假设在现实中不成主时用数学方法解决问题。类似地,按下来也做
了临时的假设来分析匹配问题。
园这个公式说明主光线在无穷远处相交。然而,如同本章后文所示,我们推导出与主点
c。和平山相关的立体校正。在推导过程中,如果主光线在无穷远处相交,主点则具有
相同的坐标,计算深度的公式成主但是如果主光线在有限距离内相交的话,则主点
不会相等,而求深度公式修改为Z=丹/(d一(c:。'_c:'"),
投影与三维视觉453
第63页
OCR文字识别结果:
因为深度与视差成反比,二者是明显的非线性关系。当视差接近0时,微小的视差
变化会导致和很大的深度变化1当视差较大时,微小的视差变化几乎不会引起深度
多大的改变。结果就是,立体视觉系统仅仅对于物体与摄像机相距较近时具有较高
的深度精度,如图12-5所示。
tl %t
阳■圈圈■
图12-5深度与视差成负相关,故精度较高的深度估计被限制于针对附近的物体
在第11章对标定的讨论中,·我们已经遇到多个坐标系统。图12-6显示立体视觉在
OpencV中使用到的二维和三维坐标系统。,注意,它是一个右手坐标系你用右手
食指指向X方向,弯曲中指指向Y方向,拇指指向的就是主光线的方向。左右成
像仪的像素原点都在图像的左上角,像素坐标分别记为(×1,力)和(x,,y.)。投影中心
为口1和0.,主光线与图像平面相交于主点(c.,c,)(非图像中心)。经过数学校正,摄
像机就是行对准的(共面且水平对准),且相距为T,相同的焦距为f.
这样安排可以相对容易地求取距离。现在,我们必须花一些精力去弄明白,怎么样
才能让现实世界中摄像机设备映射到理想安排的几何状态。在真实世界中、摄像机
几乎不可能会像图12-4那样的严格的前向平行对准。不过,我们可以通过教学方
法计算投影图和畸变图,从而将左右图像校正成为前向平行对准。在设计立体实验
台的时候,最好近似地将摄像机放置成前向对准,并尽量让摄像机水平刘准。这种
实际的对准可以使得数学变换更易处理。如果摄像机没有尽可能对准,那么数学转
换的结果会导致很大的图像畸变,而且也会减小至消除结果图像的立体重叠区域"。
要想要一个好的结果,也需要同步的摄像机。如果摄像机不能同时捕获图像,
针对想在很近范围内获得高精度的应用则例外在这种情况下,让摄像机相互微微倾
料,以保证摄像机的主光线能在一个有限的距离内相交。经过数学整理,摄像机向内
倾斜的影响就是引入了一个从视差减去的x偏移量。这可能会导致负的视差、但我们
可以在感兴趣深度范围内获得更好的深度精度。
454第12章
视差
第64页
OCR文字识别结果:
F
则一旦场景(包括摄像机本身)内有任意物体在移动,就会出问题。如果没有同步摄
像机,就只能使用固定摄像机观察静态的立体场景了。
. l-
图12-60pencV中的末畸变校正摄像机的立体坐标系。像素坐标系以图像的
左上角为原点,两个平面行对准摄像机坐标系以左摄像机的投影中心为原点
图12-7描述了两个摄像机间的真实情况和想要实现的数学对准。为了完成数学对
准,我们需要知道观测一个场景的两台摄像机间更多的的几何关系。一旦知道它们
的几何定义和一些可以描述的术语与符号,我们就可以回到对准的问题上。
[417-418)
P
:R变换I
图12-7我们的目的是想要将摄像机在数学上对准(而不是物理对准)到同一个
观察平面上,从而使得摄像机之间的像素行是严格的互相对准
投影与二维视觉455
第65页
OCR文字识别结果:
rnq
对极几何
立体成像的基本几何学就是对极几何。从本质上来说,对极几何就是将两个针孔模
型(每个摄像机就是一个针孔®)和一些新的被称为极点(epipole)的感兴趣点(见图12-8)
结合起来。在解释这些极点有何用处之前,我们先花点时间来明确定义它们,再了
解一些相关的术语。完成这些之后,我们将会对整个对极几何有一个简明的理解,
然后会发现可以尽可能地缩小两台立体摄像机上匹配点出现的可能范围。这个额外
的发现将对实际的立体实现具有重要的作用。
极点
图12-8极面是观测点p与两个投影中心01和0,确定的面极点是投影中心
的连线与两个投影面的交点
每台摄像机各自都有一个独立的投影中心,分别为(O,和口,)以及相应的投影平面
风和日,。物理世界中的点P在每个投影面上的投影点,记为pi和p,。新感兴趣的
点叫极点,像平面化(或几.)上的一个极点e!(或e.)被定义成另一台摄像机口。(相应
地,O,)的投影中心的成像点。由实际点P和两个极点e/和e,(或者投影中心O,和
O,)确定的平面叫极面。线piel和prer(投影点与对应极点之间的连线)称为极线®。
[419]
国由于我们处理的实际上是真实镜头而不是针孔摄像机,因此左右两幅图像的畸变处理
非常重要,详见第11章。
圆你可能想到为什么极点以前没有出现过。这是因为当平面是完美平行时,极点为无
穷远。
第66页
OCR文字识别结果:
为了理解前面提到过的极点的用处,当我们看到物理世界中的一个点投影到右(或
左)图像平面时,一这个点实际上会落在沿着由已指向p,(或者由01指向pt)的这条射
线的任何位置上,这是因为我们仅仅靠一个摄像机是无法知道与观测点的距离。准
确地说,假设点P是从右图像上看到,因为这摄像机仅仅看到p,(P在心的投
影),实际的点P可以是在p,和岛所在直线的任何位置。很明显这条直接包含点
P,但也同样包含其他的很多点。感兴趣读者的会问,这条线如果被投影到左图像
马上会是怎么样$实际上,这就是pt和e/确定的那条极线。翻译过来就是,在一
个成像仪上看到的所有可能位置的点都是穿过另一台成像仪的极点和对应点的直线
图像。
现在,我们总结一下立体摄像机对极几何的一些事实。
摄像机视图内的每个3D点都包含在极面内,极面与每幅图像相交的直线是
极线。
给定一幅图像上的一个特征,它在另一幅图像上的匹配视图一定在对应的极线
上。这就是。对极约束。。
对极约束意味着,一旦我们知道立体试验台的对极几何之后,对两幅图像间匹
配特征的二维捜索就转变成了沿着极线的一维捜索。这不仅仅节省了大量的计
算,还允许我们排除许多导致虚假匹配的点。
·次序是保留的。如果两个点A和B在两幅成像仪上都可见,按顺序水平出现
在其中成像仪上,那么在另一个成像仪上也是水平出现®。【420-421】
本征矩阵和基础矩阵
你可能想下一步就应该介绍计算这些极线的OpencV函数了。但在介绍这些函数
之前,我们实际上还需要两个因素。这两个因素就是本征矩阵E和基础矩阵F®。
矩阵E包含在物理空间中两个摄像机相关的旋转和平移信息(见图12-9),矩阵F除
国由于碰撞和视图叠加区域,自然士现两个摄W机都看不见的点。但是次序却是保留
的。假设左边成W仪上的三个点A、B、C从左到右排列,而B由于遮挡在右边成像仪
上不可见,这时候我们仍然可以在右图像上看到从左到右的点A和C.
圆接下来的一小部分与数学相关。如果不喜欢数学,可以直接略过不读至少当某时某
刻全部理解这些材料后会增强你的信心。就简单的应用而言,可以仅仅使用OpencV
提供的框架而无需下面几页所提供的细节。
投影与三维视觉457
第67页
OCR文字识别结果:
了包含E的信息外还包含了两个摄像机的内参数®。由于F包含了这些内参数,因
此它可以在像素坐标系将两台摄像机关联起来。
图12-9立体成像的几何本质是通过本征矩阵E得到的,它包含了关于平移T
和旋转R的所有信息,T和R描述了一台摄像机相对另一台摄像机在全局坐标
系中的相对位置
我们再补充说明一下E和F的区别。本征矩阵E是单几何意义上的,与成像仪无
关,它将左摄像机观测到的点P的物理坐标与右摄像机观稠1」到的相同点的位置关
联起来(例如将角和p.关联)。基础矩阵F则是将一台摄像机的像平面上的点在图
像坐标(像素)上的坐标和另一台摄像机的像平面上的点关联起来(在这里,我们标
记为们和q。。【421~422】
本征矩阵数学
我们接下来将引人一些数学内容,这样可以更好地理解这些OpencV函数,以解
决立体几何的一些难题。
给定点P,我们将要推导点P在两个成像仪的观测位置角和p.之间的关系。该关
系将最终转变成本征矩阵的定义。从考虑p/和p.的关系开始,pt和p.是在两个摄
像机坐标系中观察到的点的物理坐标。利用对极几何,可以将它们联系起来,如已
聪明的读者会认识到,矩阵E和前一节描述的単应矩阵対几乎完全相同。尽管它们都
是由相同的信息构建的,但是二者还是有些差异,不能混为一谈。厅定义的本质是我
们所考虑的为摄像机的观察平面,从而把该平面上的点与摄像机平面上的匹配点关联
起来。而矩阵E没有这个假设,它仅仅是将一幅图像上的点和另外一幅图像的点联系
起来。
458第12章
旋转R
第68页
OCR文字识别结果:
经所阐述的那样©。
我们选择一列坐标,左或右都行,开始引人计算。任何一组都没有问题,但是我们
:将选择左摄像机0/为中心的坐标。在这些坐标里面,观测点的位置是P,,而另一
台摄像机的原点为T.点P在右摄像机的观测坐标(右摄像机坐标系)是p.,p.一
R(Pt-门。关键的一步是引人极面,如我们所知,它联系所有的相关事务。当然,
我们能够用多种方式去描述一个平面,但对当前目的而言,最有用的就是用通过法
向量n和平面上的所有点x表示
(x-a) n-O
回顾向量Pt和T在极面上,因此,如只有一个向量与Pt和T都垂直(比如Ptx
门◆,那就可以用以表示求取平面公式中的n。这样,通过点T的所有可能点P/以
及包含这两个向量的方程表示为圆
(-ry (T × n = O
记住,我们的目的是通过Pt和P.的联系来获得们和q。之间的关系。通过等式P.一
R(Pt-门将点P.绘制到图像上,这样便可方便地将等式重写为(Pt-门=R-'P.,并代
人到R7-R-1,可得
(R T y (T×n = O
总是可以将叉积写成矩阵相乘的形式,故定义矩阵S为
这样就推导出第一个结果,将上式代人到叉积公式中,得到
(F, y Rsp_O
乘积RS就是我们定义的本征矩阵,可以写成下面的简洁形式
®请不要把在投影的像平面上的点pt、p.与和在两台摄像机坐标系下的点P的位置J7/、
p,混为一谈。
自用两个向量的叉积得到的第三个向量与这两个向量都垂直。叉积的方向可以通过。方
手规则。定义:食指指向方向a,中指弯曲指向方向b,那么a和b的叉枳axb与a
和b垂直,它的方向就是拇指指向的方向。
固这里我们用通过将正交向量转置后矩阵乘法代替了点积(点菜)。
投影与三维视觉459
第69页
OCR文字识别结果:
Tq
(P, L T Ep,-O
当然了,我们真正想要的是获得成像仪上的观测点之间的关系,这仅仅是其中的一
步。我们可以通过投影方程pi一力P,/Zt和p.-f.P,/Z,将上式简化,并利用ZtZ,
石f。分解得到我们的最终结果
P EP,-0
首先,看起来,如果已知其他项,我们就完全可以确定p项,但是E是一个秩亏
矩阵©(一个秩等于2的3×3矩阵),因此方程实际上有无穷解。本征矩阵中有五个
参数——三个旋转参数、两个平移参数(没有设置缩放)以及两个其他约束。本征矩
阵中的两个其他约束是(1)行列式值等于0,因为是秩亏矩阵(一个3×3、秩为2
的矩阵);(2)两个非零奇异值相等,因为S是反对称矩阵,而R是旋转矩阵。这总
共产生七个约束。再次注意,E不包括摄像机的内参数,因此它联系的是点的物理
坐标或者摄像机坐标而不是像素坐标。【422~423】
基础矩阵数学
矩阵E包含两台摄像机相关的所有几何信息,但不包括摄像机本身的任何信息。
在实际应用中,我们通常只对像素坐标感兴趣。为了探究一幅图像上的像素和它在
另一幅图像上的对应极线的联系,必须引人两台摄像机的内参数信息。为此,用
p(像素坐标)来代替q,二者通过摄像机内参数矩阵相关联。已知q-Mp(M是摄像
机内参数矩阵)或等价的,p-彻-'q,因此关于E的等式就变成
q(M,')EM'q,-0
虽然看起来有点混乱,我们可以通过定义基础矩阵F来整理一下
F = LM )EM,'
因此有
q Fq,-0
表面上,除了基础F操作的是图像像素坐标而E操作的是物理坐标之外,基础矩
对于类似E的nxn方阵,秩亏意味着它的非0特征值个数小于n。所以秩亏矩阵说明
线,F生方程组没有惟一解。如果秩(非0特征值的个数)为n-1,方程的所有解会在同一
条直线上如果秩为n-2,就可以确定一个面以此类推。
460第12章
第70页
OCR文字识别结果:
阵F与本征矩阵E没什么差别m。与E一样,基础矩阵F的秩也为2。基础矩阵F
有7个参数,其中两个参数表示对极,三个参数表示两个像平面的单应矩阵(通常
的4个参数中没有比例因素)。
OpencV的处理方法
类似地,可以像前一节计算图像单应矩阵的方法,通过已知的匹配点来计算矩阵
F.这种情况下,至不需要单独为摄像机进行标定,因为我们可以直接求解F,
它其实隐含了两台摄像机的基础矩阵。处理整个过程的这个算法是cvFindFunda一
menta1Mat 0.
1nt cvFindFundamenta1Mat(
const CvMat* points1,
const CvMat* points2,
CvMat* fundamental_matrix,
int me thod-CV-FM-RANSAC
doubt e param1 · 1. 0,
doubt e param2. 0. 9 9,
CvMat* status = NULL
函数cvFindFundamenta1Mato的前两个参数是N× 2或者N× 3@的浮点型(单精度
或双精度)矩阵,它包含的是收集的N个匹配点(也可以是N× 1的2或3个通道的
多通道矩阵)。输出结果是fundamental_matrix,是与输入点相同精度的3 × 3矩
阵(个另l:情况下是9 × 3的矩阵,下面将阐述)。【424~4251
函数的下一个参数是利用对应点计算基础矩阵的方法选项,你可以从四个之中选择
一个。对每个数值,对点points1和points2所需要的(或允许的)点数有限制,
如表12-2所示。
国请注意,该公式是将本征矩阵和基础矩阵联系在一起。如策有了校正图像和用焦距归
一化所有点、这时内参数矩阵M就变成了单位矩阵,并且F= E.
园你可能想李。道、厅×3或者3通道矩阵有何用途。这个算法只适用于标定物体测量到的
3D坐标卜,.,引。三维点最后将被变换成(x/z,y/z),或者你也可以用齐次坐标(x,y,1)的
形式输入3D坐标,这样的处理方式是一样的。如果输入(x,儿O)、算法将会忽略0.
一般情况下,由于我们只能探测到标定物体上的2D点,所以实际上很少会出现3D点
的情况。
投影与三维视觉461
第71页
OCR文字识别结果:
表1 2-2cvFindFundamentalMa图中方法参数的约束条件
CV_FM_7P01NT N=7 7点算法
CV_FM_8P01NT N -88点算法
CV_FM_RANSAC N 8 RANSAC 算法
CV-FM_LMEDS N 28 LMedS 算法
7点算法只使用7个点,其原理是,矩阵F的秩必须为2,这样才可以完全地约束
矩阵。,这个约束的好处就是,矩阵F的秩总是为2,因此它没有不等于0的很小特
征值。不足之处在于,约束不是绝对的唯一,所以函数有可能返回三种不同的矩阵
(这就是为什么前面说到了要将fun己amen上al_matrix创建为9 × 3的矩阵,这是考
虑了要顾及所有的三种结果)。8点算法通过线性方程来求解F.如果输入的点数目
超过8,则求所有点的最小二乘解。7点算法和8点算法都存在的一个问题是它fr」
对异常点非常敏感(即使8点算法的输人点数目超过8也是如此)。RANSAC与
LMedS算法一般被划分为鲁棒算法,这是因为他们有一定的识别和剔除异常点的
能力◆。对这两种方法而言,都要求最少输入8个点,且多多益善。
下面的两个参数仅为方法RANSAC和Lmeds所使用。第一个参数param1是点到
极线(像素)的最大距离,超出该值贝Y认为该点是异常点。第二个参数param2是期
望可信度(0~1之间),实际上是告诉算法的迭代次数。
最后一个参数status为可选,如果使用则应该它是一个N×l的cv_8uc1类型的
矩阵,其中N与points1和points2的长度相同。如果矩阵非空,RANSAC和
LMedS就会用它来存储哪些是异常点和哪些不是异常点的信息。具体说来,如果
为异常点则其元素置为O,否则置为1。对其他两种方法而言,如果数组存在,则
所有值都置为1。【425~426】
cvFin己Fun己amenta1Mat 0的返回值是一个整数,表示査找出来的矩阵个数。它对
7点算法而言可以是0.1和3,而对其他所有方法只能是0或者1。如果为O,说
明没有矩阵被计算。OpencV手册上的f列子代码见例】2-2.
RANSAC和LMedS算法的内部工作原理超出了本书的范围,但是RANSAC算法的基
本原理是使用点的随机子集来多次地求解问题,然后选出最接近平均或中间的结策。
LMedS算法采用点的子集去估计一个解、,?,奚后李巴剩余的那些与解。相容。的点中加入
到子集中,并剔除其他的所谓的。异常点。。更多有关RANSAC的内容,请参考
Fischler和Boltes的原始论文、有关最小中值平方,请参考Rousseeuw
[Rousseeuw84],使用LMedS的线性拟合、请参考Inui,Kaneko和Igarashi [lnui03]。
462第12章
一栏
第72页
OCR文字识别结果:
例12-2使用RANSAC算法计算基本矩阵
r
int point-count · 100
CvMat* points1
CvMat* points2
CvMat* status
CvMat"fundamental_ma trix
POnts1 cvcreace Mat(1, point_count, CV_32FC2 )
points2 cvcreate Mat(1, point_count, CV_32FC2 )
status cvcreate Mat(1, point_count, CV_8UC1 )
/"Fill the points here"/
fori int I 0 I < point_count i++
points1-»data. F1[i2] <x1, i> //These are points such as
found
points1-»data. F1[i2+1] <y1, i> // on the chessboard
calibration
points2-»data. F1[i2] <x2, i> // pattern.
points2-»data. 61[i*2+1] «y2, i»
fundamental_matrix = cvcreate Mat ( 3, 3, CV_32FC1 )
int fm_count cvFindFundamenta1Mat( points1, points2,
fundament a 1_ma t r ix,
CV_FM_RANSAC, 1. 0, 0. 99, status )
一点警告(与返回0时的可能性有关)如果这些点形成了退化形态,会导致算法失
败。当提供的点少于所需的信息时,如一个点出现的次数多于一次,或者当多个点
共线或与其他点共面时,这些退化形态就会产生。因此,检査
cvFin己Fun己amenta1Ma上0的返回值显得十分重要。
极线的计算
一旦有了基础矩阵,我们就能够计算极线。OpencV中的cvco田putecorrespond一
Ep土lineso函数根据一幅图像中的点列,计算其在另一幅图像中对应的极线。注
意,给定一幅图像上的任意点,在另外一幅图像总是有对应的极线。每条计算的极
线以三点(a,b,c·I的形式编码,这样极线就定义如下
投影与三维视觉463
第73页
OCR文字识别结果:
ax + by + c-O [426]
为了计算这些极线,函数需要前面用cvFin己Fun己amenta1Mat0算出的基础矩阵。
void cvcomputecorrespondEpi line s (
const CvMat* points,
int whi ch-image,
const CvMat* £undamenta1_matrix,
CvMat* correspondent-lines
这里第一个参数p。in仁s,通常的是一个N×2或者JV×3阵列的点(也可以是Nx
的2或2通道的多通道矩阵)。参数which_image必须是1或者2,它标明哪幅图
像的点被定义(相对于cvFindFundamenta1Mat O中的points1和points2)。当
然,参数fun己amenta1_matrix是函数cvFindFundamenta1Mat 0返回的3 × 3的
矩阵。最后的参数correspon己ent_lines是一个N× 3的浮点数矩阵,表示将写
人的结果极线。容易看出,极线方程ax+by-c-O与参数a、b、c的所有归一化
无关。它们都默认地被归一化了,故口2+b,-1.
立体标定
我们已经在摄像机和三维点的背后建立许多可以利用的理论机制。本节将介绍立体
标定,下一节则介绍立体校正。立体标定是计算空间上两台摄像机几何关系的过
程。相反地,立体校正则是对个体图像进行纠正的过程,这样保证这些图像可以从
像平面行对准的两幅图像获得(回顾图12-4和图12-7)。通过这样的校正,两台摄
像机的光轴(或者主光线)就是平行的,即所谓在无穷远处相交。当然,我们也可以
将两台摄像机的图像标定成许多其他的结果,但是这里(在OpencV中)我们将注意
力集中在一些更常见更简单的实例来使主光线在无穷远处相交。
立体标定依赖于査找两台摄像机之间的旋转矩阵R和平移向量T,如图12-9所
示。R和T都是通过函数c·····eocalibra·eo来计算的,这个函数与我们在第
】1章中看到的cvca11bra亡ecamera2o相似,所不同是现在我们有了两台摄像机
和一些新的函数用以计算(利明以前的计算)摄像机的失真矩阵、本征矩阵或者基础
矩阵。立体标定和单摄像机标定的另一主要不同之处在于,在函数
cvcalibratecamera2 o中,我f门以摄像机和棋盘视图之间的一些列旋转和平移结
束,而在函数cvscereocalibra·eo中我们则是寻求单个旋转矩阵和平移向量来
联系左右摄像机。
464第12章
第74页
OCR文字识别结果:
'-一飞邕
前面我们已经说明如何计算本征矩阵和基础矩阵。但是如何计算左右摄像机的R
和T呢?给定物体坐标系中的任意3D点P,我们可以分别用两台摄像机的单摄像
机标定来将,P输入到左右摄像机的摄像机坐标系P,-R,P+马和p.-R.p+
T,。相应地,从图12-9中也同样能明显看出点P(在两台摄像机上)的两个视图可以
用P,-RT(P,-门关联©,其中R和T分别两个摄像机之间的旋转矩阵和平移向量。
利用这三个等式分别求解旋转和平移,就可以推出下面的简单关系@
R一R,(只)丁
T = -R T [427-428]
给定棋盘角点的多个联合视图,函数cvs仁ereocalibrateo利用
cvcalibratecamera2 0来单独求解每个摄像机棋盘视图的旋转和平移参数(请参
见第11章)。然后将这些旋转和平移结果代入到公式中,就可以求出两台摄像机之
间的旋转和平移参数。由于图像噪声和舍人误差,每一对棋盘都会使得R和T的
结果出现细小不同。这时,cvstereocalibra·eo就选用R和T参数的中值来作
为真实结果的初始近似值,然后再运行稳健的Levenberg-Marquardt迭代算法查
找出棋盘角点在两个摄像机视图上的(本地的)最小投影误差,并返回R和T的结
果。为了使得到的立体标定显示更清晰,旋转矩阵被作用到与左摄像机共面的右摄
像机上,这样就保证两个图像平面共面并且行不对准(在下面小节中我们将看到如
何完成行对准的)
函数cvste reocalib ra·eo有许多参数,但是它们都相当直观易懂,而且大部分
都与第11章中的cvcalibra仁ecamera20函数相同。
bool cvstereocalibrate(
const CvMat * obj ectpoints,
const CvMat · imagepoints 1,
const CvMat* imagepoints2,
const CvMat* npoints,
CvMat · cameraMatrix1,
CvMat* distcoeffs1,
国注意这些项的意义Pl和Pr分别是左方摄像机相应的坐标系下3D点P的位置R!和
T了(或者Rr和Tr)表示左摄像机(对畜摄像机)上由摄像机到3D点的旋转和平移矩阵;R
和T则是将才摄像机坐标系转换到左摄W机的旋转和平移。
园左方摄像机可以通过两个公式中的下标进行翻转,也可以翻转下标并只在转换公式中
将R转置来完成。
投影与三维视觉465
第75页
OCR文字识别结果:
CvMat *
CvMa t *
Cvs I z e
CvMat *
CvMat *
CvMat *
CvMa t *
camera Mat rix2,
distcoeffs2,
imagesi ze,
R,
T.
E,
F,
CvTermcri teria termcri t,
int flags =CV-CALIB-FIX-INTRINS IC
) [428-429]
第一个参数objectpoints是一个N× 3的矩阵,它包含三维物体在M幅图像中的
每一幅图像上的K个点的物理坐标,因此N=Kx M.当使用棋盘作为三维物体
时,这些点就落在物体的坐标系上,棋盘的左上角作为原点(棋盘平面上点的Z坐
标通常置为0),但任意已知的3D点都可能被用到cvcalibratecamera2o中。
现在我们有两台摄像机,分别标记为。1。和。2。。。因此有imagepoints1和
imagepoin七s2,它们是N× 2的矩阵,分别存储由objectpoints提供的所有物体
参考点在左右坐标系上的位置。如果使用一个棋盘来完成两个摄像机的标定,那么
imagepoints1和imagepoints2就正好分别是调用cvFindchessboar己cornerso
求取左右视图的返回值。
参数npoin七s是每幅图像上的点数目,为Mx t的矩阵。
参数camera Matri×1和camera Matri×2是3 × 3的摄·像机矩阵,而参数
distcoeffs1和己istcoef fs5分别是摄像机1和摄像机2的5 × 1畸变矩阵。记
住,这些矩阵中前两个径向参数首先出现,然后是两个切向参数,最后是第三个径
向参数(参见第11章对畸变系数的讨论),因为第三个镜像畸变参数是OpencV发
展中新加入的成员,因此放在最后它主要是用于广角(鱼眼)镜头。这些摄像机内
参数的使用由参数flags控制,如果flags设置成CV_CALIB_FIX_INT只INSIC,
这些参数便仅用于标定过程中$如果flags为CV_CA乙IB一USE_IN丁只INSIC一
GuEss,参数便被用作优化摄像机的内参数和畸变参数的初始值,而且在
cvstereocalibrateo返回时被改进值所更换。结合flags的其他设置,使之具
有和函数cvcalibracecamera2 o完全相同的可能值,这样这些参数在
简单而言,就是用。1。来表示左摄像机,2。来表示右摄像机。你也可以交换它们
以本书讨论的相反方式来描述结果旋转和平移结果。最重要的是保持摄像机的物理对
准,从而保证它们的扫描线能近似对应,以获得更好的标定结果。
466第12章
第76页
OCR文字识别结果:
cvstereocalibra仁eo中就从0开始计算得到。换句话说,可以利角!
cvstereocalibra·eo函数一次性计算内参数、外参数和立体参数。。
参数{.ges..是以像素为单位的图像大小。它汉用于细化或者计算内参数且
11.gs不等于C,_CA乙1日_FIX_INTRN4S··时,
R和7项是输出参数,在函数返回时被填人待求的(联系左右摄像机的)旋转矩阵和
平移向量。参数E和F为可选,如果不为空,cvstereocalibrateo就会计算和
填充这些3×3的本征矩阵和基础矩阵。之前我们已经见过参数termcrit多次
了,它设置内部最优化准则,或者指示计算参数的变化在结构termcrit中的阈值
内时,迭代一定次数后将程序终止或者暂停。这个函数的一个典型调用是
cvTermcriteria ( CV-TERMCRIT_ITER + CV_TERMC 只 IT_EPS, 100, le-5 )
最后,我们已经稍微讨论了参数flags。如果已经将两台摄像机标定,并确认了结
果,你便可以使用Cv_CALIB_FIX_INTRINSIC。强行重置。先前的单摄像机标定结
果。如果认为两台摄像机的初始标定不够好,可以设置参数flags为
CV_CALIB_uSE_INTRINSIC_GUESS来,用它来细化内参数和畸变参数。如果摄像
机没有分别进行标定,你可以设置第11章cvcalibratecamera20函数的参数
flags为相同的设置。
一旦有了旋转或者平移值(R,7)或者基础矩阵F,我们就可以利用这些结果来校正
两幅立体图像,使得极线沿着图像行对准,并且穿过两幅图像的相面线也是相同
的。尽管R和T并不决定唯一的立体校正,但是在下一小节中,我们就会看到怎
样利用这些项(以及其他约束条件)。
立体校正
当两个像平面是完全的行对准时(见图12-4),计算立体视差是最简单的。不幸的
是,如前面所讨论的,由·于两台摄像机几乎不可能有准确的共面和行对准的成像平
面,完美的对准结构在真实的立体系统中几乎不存在。图12-7显示了立体校正的
目的我们要对两台摄像机的图像平面重投影,使得它们精确落在同一个平面上,
而且图像的行完全地对准到前向平行的结构上。如何选择特定的平面使摄像机保持
数学对准依赖于所使用的算法。在下文中,我们讨论使用OpencV提及的两个
注意尝试一次性求解多个参数有时会导致结果发散值到无意义的值。求解方程组是
一项技术活,必须校验结果。可以看到在标定中一些这样的考虑和校正源码实例,其
中便利用对极约束来检查标定结果。
投影与三维视觉467
第77页
OCR文字识别结果:
了\l
腾况。
我们要保证两个摄像机的图像行在校正之后是对准的,使得立体匹配(在不同摄像
机视场中发现相同点)更可靠,计算更可行。注意,只在图像的一行上面搜索另一
图像的匹配点能够提高可靠性和算法效率。让每个图像平面都落在一个公共成像面
上并水平对准的结果是极点都位于无穷远。即一幅图像上的投影中心成像与另一个
像平面平行。但是由于可选择的前向平行平面个数是有限的,我们需要加入更多的
约束,包括视图重叠最大化和畸变最小化,接下来我们讨论如何选择算法。
[430]
对准两个图像平面后的结果有八项,左右摄像机各四项。对每个摄像机,我们都会
有一个畸变向量己istcoeffs、一个旋转矩阵R...,(应用于摄像机)、校正和为未校
正的摄像机矩阵(环。。,和间。从这些项里使用函数cvlnitun己istort一
Rec七ify Map o(接下来就简要论述)创建一个映射,该函数从原始图像插值出一幅
新的校正图像国。
有很多算法可以计算我们的校正项,OpencV实现了其中的两种一是Hartley算
法,它只使用基础矩阵来生成非标定立体视觉!二是Bouwet算法圆,它使用两台
标定摄像机的旋转和平移参数。Hartley算法可以通过单个摄像机记录的运动推导
出立体结构,虽然单个摄像机会(当立体校正后比Bouwet标定算法产生更多的畸
变图像。在可以使用标定模式的情形下,如机器人臂或者安全摄像机装备上,
Bouguet算法更简单自然。
非标定立体校正Ha「tley算法
Hartley算法旨在找到最小化两幅立体图像的计算视差时将对极点映射到无穷远处
的单应矩阵。这可通过匹配两幅图像之间的对应点简单完成。因此,就可以绕过计
算两个摄像机的摄像机内参数,因为这样的内参数信息式隐含在匹配点对之中。所
以我们只需计算基础矩阵,它可以通过前面描述的cvFindFundamen匕a1Mat o函数
所获得的两个场景视图上的7个以上匹配点来获得。
Ha出ey算法的优点是,在线立体标定可以简单地通过场景中的观察点来完成。缺
点是场景的图像比阒未知。例如,如果使用棋盘来生成点对,就无法知道棋盘从一
国在OpencV中,只有当对极在图朱矩形框外面时才能对图像进行立体校正。因此,当
立体构型的基线很宽或者摄像机对视过多时,这个校正算法就可能没有用处了。
Bouguet算法是由Tsai【Tsa8'7]第一次提出的方法的简化实现。Jean-Yves Bouguet从来
没有在其著名的同八TLAB摄像机标定工具箱之外公布这个算法。
第78页
OCR文字识别结果:
F
端到另一端是100米还是100厘米。这样我们就不明确摄像机的内参数矩阵,因为
摄像机可能有不同的焦距、倾斜像素、不同的投影中心和/或不同的主点。因此,
我们只能根据投影变换来重构3D物体。也就是说,一个目标的不同比例尺或者投
影看起来都是相同的(比如说,尽管3D物体不同,但它们具有相同的2D坐标)。
这些问题如图12-10所示。【431】
图12-10立体重建的非惟一性如果不知道物体的大小,那么根据和(左)摄
像机距离的远近,不同大小的物体看起来有可能是相同的如果不知道摄像机
内参数,不同的投影看起来也是相同的——比如它们有不同的焦距和主点
1.
假设我们有基础矩阵F(该矩阵需要至少7个点来计算),Hartley算法流程如下
(更多细节,请参见Hartley的原作[Ha八ley98】)。通过下面的关系式用基础矩阵
来计算两个极点及其关系Fe,=o和他rF上面两式分别对应左右两极点。
2.我们先求第一个单应矩阵邕,它将右极点映射到无穷远(1,0,0广处的二维齐
次点。由于一个单应矩阵有7个常数(没有比例尺),其中的三个用来做无穷远
的映射,剩下的四个自由度来选择H,。因为H,的大部分选择都会导致非常扭
曲的图像,所以这四个自由度最容易导致混乱。为了找到一个好的H.,我们
选择图像上的一点,使得这一点上有最小的畸变,即只允许刚性旋转和平移而
不是剪切。对这样的点的一个合理选择就是图像原点,我们进一步假设极点落
在x轴上(下面的一个旋转矩阵将会完成这个)(e.r_(f,o,1)给定这些坐标,如
下矩阵会将这样的一个极点映射到无穷远。
0 0
G一0 1 0
一1/k 0
3.对右图像上所选择的一个感兴趣点(这里选择原点),我们计算点到图像原点的
投影与三维视觉469
第79页
OCR文字识别结果:
平移矩阵T和将极点指向(er·(f,0,1)的旋转矩阵R,则需要的单应矩阵就是
H,-GRT. [432]
4.接下来捜索匹配的单应矩阵H,,它将左极点发送到无穷远,并保证两幅图像
的行对准。通过步骤2中的三个约束可以容易地将左极点转到无穷远。为了能
够行对准,仅仅的事实是行对准使两幅图像的所有匹配点间距离和最小。也就
是说,我们査找局,使得左右匹配点的总的视差最小。工,d(HH,,邕p)这两个
单应矩阵就定义了立体校正。
虽然说这个算法的细节有点拐弯抹角,但是cvs仁ereo Rectifyuncalibratedo完
成了所有的复杂工作。这个函数的叫法有点不妥当,因为它不是校正非标定立体图
像,而是计算可以用于校正的单应矩阵。算法调用如下
int cvstereoRectifyuncalibrated(
const CvMat* points1,
const CvMat* points2,
const CvMat* F,
cvsize imagesi'ze,
LvMat* H1,
CvMat* Hr,
double threshold
函数cvstereo只ectifyuncalibrated中,算法输入为左右图像间的2×K匹配点
数组poin仁s1和pain仁s2。上面计算出来的基础矩阵F作为参数传入。我们对
lmagesize已经熟悉了,它只是描述了在标定中使用到图像的宽和高。函数变量
H1和H,返回校正的单应性矩阵。最后,如果点和对应的极线之间的距离超过了设
定的阈值,算法会删除对应点®。
如果摄像机大致有相同的参数,并且是设置为近似水平对准的向前平行构型,那么
Hartley算法的最终校正输出就非常像我们接下来描述的标定情形。如果知道了场
景中物体的大小和3D几何,我们就能够获得和标定情形相同的结果
标定立体校正:Bouguet算法
给定立体图像间的旋转矩阵和平移(R,门,立体校正的Bouguet算法就是简单地使
Hartley算法对已经由単摄像机标定法校正的图像最有效,寸高度畸变的图像则完全无
效,有点讽刺意味的是,我们的。免标定。方法只是对无畸变图像(图像的参数来自以
前的标定)有用。另一个非标定3D方法请参见Pollefeys[Po11efeys99a]。
470第12章
第80页
OCR文字识别结果:
两图像中的每一幅重投影次数最小化(从而也使重投影畸变最小化),同时使得观测
面积最大化。
为了使图像重投影畸变最小化,将右摄像机图像平面旋转到左摄像机图像平面的旋
转矩阵R被分离成图像之间的两部分,我们称之为左右摄像机的两个合成旋转矩
阵rl和r,。每个摄像机都旋转一半,这样其主光线就平行地指向其原主光线指向的
向量和方向。如所标记的,这样的旋转可以让摄像机共面但是行不对准。为了计算
将左摄像机极点变换到无穷远并使极线水平对准的矩阵R...,,我们创建一个由极点
el方向开始的旋转矩阵。让主点(c.c,)作为左图像的原点,极点的方向就是两台摄
像机投影中心之间的平移向量方向
下一个向量e2必须与el正交,没有其他限制。对e2而言,很好的一个选择就是选
择与主光线正交的方向(通常沿着图像平面)。这可以通过计算el和主光线方向的叉
积来得到,然后将它归一化到单位向量
【一乙里了O] T
e2 = Jc +
第三个向量只与el和e2正交,它可以通过叉积得到
e3 = el X e2
这个矩阵将左图像绕着投影中心旋转,使得极线变成水平,并且极点在无穷远处。
两台摄像机的行对准通过设定来实现
我们同样可以计算校正后的左右摄像机矩阵M...,,1和环。。,,r,但是与投影困·阵门和
P.一起返回
丁
e【'"
Wil
第81页
OCR文字识别结果:
J._t a cx_/ 1 0 0 0l
0 010010
(其中,a/和a,是像素畸变比例,它们在现代摄像机中几乎总是等于0)。投影矩阵
将齐次坐标中的3D点转换到如下齐次坐标系下的2D点
其中,屏幕坐标为(x/w,y/w)。如果给定屏幕坐标和摄像机内参数矩阵,二维点同
样可以重投影到三维中,重投影矩阵如下
这里,除c',外的所有参数都来自于左图像,c',是主点在右图像上的x坐标。如果
主光线在无穷远处相交,那么cx-c'.,并且右下角的项为0。给定一个二维齐次点
和其关联的视差d,我们可以将此点投影到三维中
Q -
三维坐标就是(X/W,Y/W,刀W)。
应用刚刚描述的Bouguet校正方法即可生成图12-4中的理想立体构型。为旋转图
像选择新图像中心和边界从而使叠加视图的面积最大化。大体上来说,这正好生成
一一个相同的摄像机中心和两个图像区域共有的最大高度和宽度作为新的立体视图
平面。
472第12章
第82页
OCR文字识别结果:
: 三
T void cvStereoRectif]'(
:. : const CvMat* cameraMatrix1,
\ const CvF(at · camera matrixz,
const CvMat · distcoef fs1,
const Cvtla 匕 · dis 匕 Coef fs2,
cvsize imagesize,
const CvMat · R,
const Cvldat · T,
CvMat · Rl,
CvMat"Rr,
CvMat"Pl,
CvMat · Pr,
CvMat · Q = O,
int flags= CV_CALIB_ZER. O_DI SPARITY
) [435-436]
对函数cvs仁ereo Rectifyo®来说,输入的是我们所熟悉的由
cvstereocalibrateo返回的原始摄像机矩阵和畸变向量。接下来的参数
imagesize是用来执行标定的棋盘图像的大小。同样传人由
cvstereocalibrateo返回的左右摄像机间旋转矩阵R和平移向量T.
返回参数是3 × 3矩阵R/和R,,是从前述公式推导而来的左右摄像机平面间的行对
准的校正旋转矩阵。同样地,我们也获得了3 ×4的左右投影方程P/和P,。一个可
选返回参数为Q,是前面叙述过的4 × 4的重投影矩阵。
Flags参数的默认设置为无穷远处的视差,如图12-4中的通常情形。不设置
flags参数,意味着我们想要摄像机相互重合(比如轻微的。交叉注视。),从而使
得有限距离内的视差为0(这可能在特定距离附近的更高深度分辨率的情形下需要)
如果参数flags不为CV_CALIB_ZERO_DISPARITY,那我们要对如何完成校正系统
更加小心。回顾以前,我们是相对于左右摄像机的主点(c.,c,)来校正系统的,因此
图12-4的测量值也是和这些点的位置相关。基本上说,我们必须修正这些距离,
使得丘"=."_c'"'和歹一x'_,当视差设置成无穷大时,我们有c。_c。(比如,当
CV_CALIB_ZERO一DISPARITY传递到cvstereo Recti fy O中),并且我(门可以传递
平面像素坐标(或者视差)到公式中以计算深度。但是如果cvstereo只ectifyo被
®再次说明,cvstereo Recti fy()的名称不妥当是因为此函数是计算可以用来校正的
参数项,而不是真实的对立体图像进行校正。
投影与二维视觉473
匕
第83页
OCR文字识别结果:
调用时没有传人cv_CALIB_ZERO_DISPARITY,一般有才。壮寸。。因此,,即使公式
Z=fH(x,-x,)仍然保持不变,但要切记,xt和x,不是针对图像中心,而是针对各自
的主点心。and可'",它们与xt和xr不同。所以,如果计算视差d=x/-x,,那么在
计算Z之前就应该将其修正为Z川(d-(c-eight))。
校正映射
一旦有了立体标定项,我们就可以单独调用cvlnitun己istort Rec上ify Mapo来事
先计算左右视图的校正査找映射表。对任何图像到图像的映射函数,由于目标位置
是浮点型的缘故,正向映射(即根据原始图像上的点计算其到目标画像上的点),不
会命中目标图像对应的像素位置,因为目标图像看起来像瑞士硬干酪。因此我们采
用逆向映射对目标图像上的每个整型的像素位置,首先査找出其对应源图像上的
浮点位置,然后利用周围源像素的整型值插值出新的值来。这种査找一般使用双线
性插值方法,在第6章中的,cvRemap O函数中遇到。【436~437】
这个校正的过程如图12-11所示。图中公式流程就是真实的从(c)到(a)的后向校正
过程,称为逆向映射。对校正图像(c)中的每个整型像素,我们査找它在非畸变图
像(b)上的坐标,并用这些坐标回溯在原始图像(a)上的真实(浮点)坐标。浮点坐标
上的像素值通过在原始图像上的邻近整型像素位置插值得到,这个值被赋给目的图
像(c)上的校正后整型像素位置。在校正图像都被赋值之后,我们经常将它剪切以
增大左右图像间的叠加面积。
右摄像机
佃)原始图像、、,,.
M,. I Distort ((R.MM''p)
《b)非畸变.
(R, M_)-Y p'
(C),'"-'necl
(d) .. m
图1 2-11立体校正。对左右摄像机而言,(a)原始图像、(b)非畸变化、(c)校
正和(d)最后裁切成两幅图像间的重叠区域。校正实际上是由(c)到(a)的反向过程
第84页
OCR文字识别结果:
I,,调用了两次,左右图像各调用一次。
图12-II中数学描述的函数实现是cvInitundistoTtRectifyMap0。这个函数被°「
void cvlnitundistort Recti£y Map(
const CvMat* M,
const CvMat* distcoeffs,
const CvMat* Rrect,
const CvMat* Mrect,
CvArr* rnapx,
C vArr"mapy
cvlnitundistor t Recti £yMap O使用的输入参数是3 × 3的摄像机矩阵M、校正后
的3×3摄像机矩阵Mrect、3×3的旋转矩阵Rrect和5×l的摄像机畸变参数
distcoe££s.
如果使用cvstereo Rectifyo去标定立体摄像机,我们可以从
cvstereo Recti£yo直接读出cvlnitundistort Recti£yMapo的输入参
数,使用左参数校正左图像,右参数校正右图像。对Rrect可用
cvstereo Recti£yo的局和R,,对M,使用camer己Matri×1或者
camera Ma七ri×2。对Mrect,我们可以用cvstereo Rectify O中的3 × 4 P,或
片的前面三列,但为方便起见,函数允许我们直接输入马和P,,并从中读出
Mrect.
另一方面,如果使用cvstereo Rectifyuncalibrated 0校正立体摄像机,那我们
必须预处理一下单应性矩阵。尽管在理论和实际中可以不使用摄像机内参数来校正
立体视觉,但OpencV中没有这样的直接处理函数。假设没有从先前的标定中获
得Mrect那正确的流程应该是令Mrect等于M.然后对
cvlnitundistort Rectify Map O中的Mrect来说,我们需要分别计算左右校正的
风。一,-M/H,M,(或无法得到R~_,-M,-·H,M,初二一,)以及R.。_.-心,一。H.M.(或无法得到
R.。,_.-M'H.成心,_.)。最后,我们还需要每台摄像机的畸变系数来赋给5× 1的
distcoeff s 参数,
函数cvlnitun己istort Rectify Map O返回的输出值是查找映射表mapx和mapy.
对目标图像上的每个像素来说,映射表说明应该从什么位置插f直源像素并且映射
表可以直接被cvRemapo嵌人使用,我们第一次在第6章中见到过该函数。如我
们提到的,函数cvlnitun己istort Recti fy Map O被左右摄像机分别调用,这样可
以获得它们的各自不同的重映射参数mapx和mapy。当每次我们有新的左右立体图
像需要校正时可以使用左右映射表时,函数cvRemapo也可能被调用。图12-12是
投影与三维视觉475
第85页
OCR文字识别结果:
图像立体对的立体非畸变化和校正的结果。注意,特征点在非畸变校正图像上是如
何变成水平对准的。【437~438】
立体匹配
立体匹配——匹配两个不同的摄像机视图的3D点——只有在两摄像机的重叠视图
内的可视区域上才能被计算。再重复一下,这就是为什么如果将摄像机尽量靠近前
向平行(至少在你成为立体视觉的专家之前)以获得更好结果的一个原因。一旦知道
了摄像机的物理坐标或者场景中物体的大小,就可以通过两个不同摄像机视图中的
匹配点之间的三角测量视差值d-xt-x.(当主光线在有限距离内相交时d=x!一
x,(c-c'")来求取深度值。没有这样的物理信息,我们就只能计算深度的比例关
系。如果我们没有摄像机内参数,如当使用Hartley算法时,我们只能在投影变换
意义上计算点的位置(见图12-10)。
r : L j.
图1 2-12立体校正原始的左右像对(上)和校正后的左右像对(下)t注意,桶
形畸变(棋盘图形顶部)被纠正了,并且校正图像中的扫描行也已经被对准了
OpencV实现了一个快速有效的块匹配立体算法cvFindstereocorrespondence一
BMo,它与Kurt Konolige提出的算法相似。它使用了一个叫。绝对误差累计。的
476第12章
第86页
OCR文字识别结果:
歹卜
小窗口(SAD)来査找左右两幅立体校正图像之间的匹配点田。这个算法只査找两幅
图像之间的强匹配点(强纹理)。因此,在一个强纹理场景中(例如出现在森林户
外),每个像素都有可计算的深度。而在弱纹理场景里(比如室内的走廊),则只需
要计算少数点的深度。对于处理非畸变的校正立体图像,块匹配立体匹配算法有以
下三个步骤。【438~439】
1.预过滤,使图像亮度归一化并加强图像纹理。
2,沿着水平极线用SAD窗口进行匹配搜索。
3再过滤,去除坏的匹配点。
在预过滤中,输入图像被归一化处理,从而减少7亮度差异,也增强T图像纹理。
这个过程通过在整幅图像上移动窗口来实现的,窗口的大小可以是5 × 5.7 × 7(默
认值)、······21 ×21(最大)。窗口的中心像素几由min[max(二一八一天。。),乙。】来代
替,其中了是窗口的平均值,1。。是一个正数范围,默认值为30。这个方法通过设
置CV_NORMALIZED_RESPONSE标志被激活。另外一个标志是
CV_LAPLAC IAN_OF_GAUSSIAN,它在图像的平滑版本上运行峰值检波器。
匹配过程通过滑动SAD窗口来完成。对左图像上的每个特征而言,我们搜索右图
像中的对应行以找到最佳匹配。校正之后,每一行就是一条极线,因此右图像上的
匹配位置就一定会在左图像的相同行上(即具有同样的夕坐标)。如果特征有足够多
可检测的纹理,并且位于右摄像机视图内,就可以找出该匹配位置(如图12-16所
示)。如果左特征像素位于(xo,/o),那么对水平前向平行的摄像机排列情形而言,
它的匹配点(如果有的话)就一定与属在同一行,或者是在xo的左边,见图12-13.
对前向平行的摄像机来说,xo是0视差,并且左边的视差更大。对两个摄像机之间
有夹角的情况,匹配点则可能出现负的视差(xo以右)。控制匹配搜索的第一个参数
是minDispari七y,它说明了匹配捜索从哪里开始,默认值为0。这时工程序在
numberof Disparities设置的(默认为64)视差内开始捜索。视差是离散的,亚像
素精度通过参数subpixeloisparities(默认值16)来设定。我们可以通过限制极
线上匹配点的搜索长度来减少搜索的视差个数,从而缩减计算的时间。记住,视差
越大表示距离越近。
通过设置最小视差和捜素的视差个数就可以建立起一个双眼视界,这个3D体被立
体算法的捜索范围所覆盖。图12-14显示了由三种不同视差(20、17.16)限制开始
的5像素的视差搜索范围。如图所示,每组不同的视差限制和视差个数都产生丁不
同的深度可知的双眼视界。在这个范围之外就不能获得深度,在深度图上会出现一
国这个算法可以从Videre的FPGA主体硬件系统中得到(见[videre])。
投影与三维视觉477
第87页
OCR文字识别结果:
个深度未知的'空洞'。缩小摄像机问的极践距离T、减小焦距长度、JB加立体视
差的搜索范国或者增大像素宽度,都可以使双眼视差变得更大,
图12-13左图像特征的右图像匹配一定出现在相同的行上,并且在相同的坐
标点上(或者左边),这个点就是匹配搜索从min Disparity点(here,O)开向左移
动视差个数的位置。图的下半部分是基于窗口特征匹配的特性匹配函数
凼牖凼——
图12-14每条直线表示整型像素从20到12变换时的恒等视差平面5个像
案内的视差搜索范围包含了不同的两眼视界范围(图中的垂直箭头),并且不同
的最大视差产生不同的两眼视界
双眼视界的匹配有一个隐含的约束,叫1顷序约束,它简单地规定了特征从左视图到
478第12章
糊彩
第88页
OCR文字识别结果:
右视图转换时顺序保持一致。可能会有特征缺失,这是因为有遮挡和噪声的缘故,
使得左图像上的特征在右图像上没有发现,但是发现它们的顺序保持不变。同样
地,右图像上也可能有一些特征在左摄像机上不能识别(称为插入),但是插入不会
改变特征的顺序,即使这些特征可能会扩散。图12-16中的过程反映了水平扫描线
上匹配特征的顺序约束。【440-442】
图12-15一个固定视差形成了离摄像机距离不变的平面
左右
匹配不相(奖励)(奖励)
似的惩罚
图1 2-16立体匹配由分配左右图像匹配行之间的点匹配开始台灯的左右图
像(上图)、单一扫描线放大(中图)、分派匹配的可视化(下图)
投影与三维视觉479
第89页
OCR文字识别结果:
给定允许的最小视差增量,通过下面的公式,我们能确定可以获得的最小深度范围
精度。
醒=一td
罗罗
牢记这个公式是很有用的,因为你可以知道从立体实验台中预期获得的是哪种深度
精度。
在匹配之后,我们就开始后过滤处理。图12-13的下部显示了一个典型的匹配功能
响应,因为特征是从最小视差里扫描出来的最大视差。请注意,匹配值经常具有一
个特点,就是强烈的中央峰被副瓣所包围。一旦确定了两个视图的待选特征匹配,
就可用后过滤来预防虚匹配。OpencV通过一个叫uniquenessRatio的参数(默认
值为12)来使用匹配功能模式,这个参数可以在uniquenessRatio〉(match.
va1-min_match)/min_match的地方过滤掉匹配值。卜40~442】
OpencV使用了texture Thresho1己参数来保证有足够的纹理以克服随机噪声。这
是对SAD窗口响应的一个限制,它使得任何响应小于texture Thresho1己的匹配
不予考虑。最后,由于匹配窗口捕捉的是物体一侧的前景和另一侧的背景,基于块
的匹配在物体的边界附近会有一些问题。这会导致同时产生大小视差的局部区域,
我们称它为散斑。为了避免出现这种边界匹配,可以通过设置参数
specklewin己owsi·e来在散斑窗口(大小从5×5到21 ×21)上设置一个散斑探测
器,这个参数的默认值为9,窗口大小默认值为9 × 9。在散斑窗口内部,只有探测
到的最大最小视差在speckle Range范围(默认范围是4)内的匹配才能被接受。
立体视觉对监控系统、导航、机器人技术这类有实时性能要求的系统来说,变得尤
其重要。所以要把立体匹配过程设计成能够快速运行才行。因此,我们不能为每次
基于块的匹配参数和内部离散缓存保存在一个叫cvstereoBMsta·e的结构体内。
typedef struct CvstereoBMState
//pre filters ( normalize input images )
int pre Filter Type
1nt preFiltersizellfor 5×5 up to 21×21
1nt pre Filtercap
/ / correspondence using Sum of Absolute Difference ( S. D )
int SADWj-ndowSize // Could be 5×5, 7×7, 21.x21
int min Disparity
int numberof DisparitiesllNumber
//post filters ( knock out bad matches )
480第12章
of pixels to search
第90页
OCR文字识别结果:
F'nnR*
int textureThreshold /lminimum allowed
float uniquenessRatio // Filter out if
// [ match_val min_match <
// uniq Ratio+min_match
// over the corr window area
int specklewindowsize //Disparity variation window
int speckleRange //Acceptable range of variation in window
temporary buffers
CvMat* pre Filteredlmgo
CvMat* pre Filteredlmg1
CvMat* slidingsumBuf
Cv StereoBMState
typedef struct CvstereoBMState
//pre filters ( normalize input images )
int pre Filter Type
int preFiltersize /lfor 5×5 up to 21×21
int pre Filtercap
//correspondence using Sum of Absolute Difference ( SAD )
int SADWIndowSIze // Could be 5×5, 7×7, 21×21
int min Disparity
int numberofDisparities//Number of pixels to search
//post filters ( knock out bad matches )
int textureThreshold /lminimum allowed
float uniquenessRatio // Filter out if
// [ match_val min_match <
/ / uniq Ratio · min_match
/ / over the corr window area
int specklewindowsize //Disparity variation window
int speckleRangellAcceptable range of variation in window
/ / temporary buffers
CvMat* pre Filteredlmgo
CvMat* pre Filteredlmg1
CvMat* slidingsumBuf
Cvst ereoBMState [443-444]
这个固定的结构在函数cvcreatestereo8Msta·e O中分配并返回。这个函数使用
的参数preset可以设置为下面的任意一个。
CV STEREO BM BASIC将所有参数设置为默认值。
投影与三维视觉481
第91页
OCR文字识别结果:
CV_STEREO_BM_FISH_EYE,,将参数设置成可以处理广角镜头。
CV_STEREO_BM_NARROW将参数设置成可适用窄视场的立体摄像机。
这个函数也有一个可选参数numberof Disparities,如果为O,它就从preset中
获得默认值,下面是规格说明
CvstereoBMState* cvcreatestereoBMState(
int p re s e tF 1 ag-CV-STEREO_BM-BAS IC,
int numbero£Disparities = O
状体结构cvstereoBMstate{}通过调用函数来释放
void cvReleaseBMState(
CvstereoBMState **BMState
在调用cvFindstereocor respon己enceBM期间,可以通过为状态结构的各个字段
分配新属性值随时调整任何的立体匹配参数。
最后,cvFindstereocorrespon己enceBM O输入校正图像对,并输出视差映射,
其结构如下
void cvFindstereocorrespondenceBM(
const CvArr *1eftlmage,
const CvArr"rightlmage,
CvArr *disparity Result,
Cv StereoBMState *BMState
) [444-445]
立体标定、校正及相应的示例代码
让我们使用一个实例程序以及其中的代码来把所有的这些知识综合起来,实例程序
将从一个叫list.·xt的文件中读人棋盘图形。文件中包含交替的左右立体(棋盘)像对
序列,可以用来标定摄像机和校正图像。再次注意,我f门是假设已经将摄像机排列
好了,其图像扫描线是粗略的物理对齐,从而使得每台摄像机本质上都具有相同的
482第12章
第92页
OCR文字识别结果:
■
视场。这可以避免极点在图像内©的问题,还可以在重投影视差最小化的1司时使立
体重叠面积最大。
在代码中(例12-3),我们首先读人左右图像对,找出亚像素精度的棋盘角点,然后
在能够看到所有棋盘的图像上设定目标的图像点。这个过程是可以随时显示的。给
定这些在合格棋盘图像上的査找点序列后,代码调用函数cvstereocalibrateo
来标定图像。标定后我们就有了摄像机矩阵_M、两台摄像机的畸变向量_D、平移
向量_T、本征矩阵_E和基础矩阵_F.
下面是一个小插曲,通过检査图像上点与另一幅图像的极线的距离远近来评价标定
的精度。为了实现这个目的,我们'1使用cvun己is仁ortpoints0(参见第11章)来对
原始点做去畸变处理,使用cvcomputecorrespondEpilines O来计算极线,然后
计算这些点和线的点积(理想情形中,这些点积都为0)。累计的绝对距离形成了
误差。
代码继续往前,选择非标定(Ha八ley)方法cvs七ereo Rectifyuncalibratedo或者
标定(Bouguet)方法cvstereo Rectifyo来计算校正映射。如果选择了非标定纠
正,代码下一步就从头开始计算需要的基础矩阵或者只计使用立体标定得到的基础
矩阵。这时就调用cvRemap O来计算校正图像。在我们的例子中,绘制直线穿过
图像对,这有助于观察一个好的校正图像是如何排列的。实例的一个结果可参见
图12-12,从图中可以看到,原始图像的桶形畸变主要是从上到下纠正的,并且图
像按照水平扫描线对齐。
最后,如果校正了图像,便使用cvcreateBMstateo来初始化块状匹配状态(内部
分配和参数)。这时'候便可以使用cvFindstereocorrespondenceBM 0来计算视差
图。这里的代码例子允许你使用水平对齐(从左到右)或者垂直对齐(从上到下)的摄
像机¥但要注意,对于摄像机垂直对齐的情形而言,如果没有自己添加图像转置的
对于摄像机水平对齐的情形,函数cvFindstereocorrespondenceBM0可以计算
标定和非标定的校正立体像对的视差。(参见后面图12-17中的实例视差结果)
[445-446]
例12-3立体标定、校正、匹配
#include"cv. h"
#include"cxmisc. T · 1"
OpencV(至今还)没有处理机点在图像框内的立体图像校正。对这种情况以及实例的讨
论, tT 参 见 Pollefeys. Koch. Alld Gooi [Pollefeys99b].
投影与三维视觉483
匕
第93页
OCR文字识别结果:
#include"highgui. h"
#include"cvaux. h ·
#include <vector>
#include <string>
#include <algorithm>
#include <stdio. H>
#include <ctype. H>
using namespace std
// Given a list of chessboard images, the number of corners ( nx, ny )
/ / on the chessboards, and a flag called usecalibrated ( 0 foF
Hart 1 ey
/ / or 1 for Bouguet stereo methods ). Calibrate the cameras and
display the
/ / rectified results along with the computed disparity images.
static void
Stereocalib(const char* image List, int nx, int ny, int
useunca librated )
int displaycorners O
int showundistorted-1
boo1 isvertica1Stereo false //opencV can handle left-right
lior up-down camera arrangements
const int maxscale 1
const float squaresize 1. f //set this to your actual square size
FILE* f fopen(image List,'rt")
int I, j, lr, nframes, n = nx * ny, N · O
vector«strlng» image Names[2]
vector«Cvpoint3D32f> objectpoints
vector«Cvpoint2032f» points[2]
vector<int» npoints
vector«uchar» active[2]
vector«Cvpoint2D32f» temp ( n )
Cvsize imagesize ( 0, 01
// ARRAY AND VECTOR STORAGE
double M1[3] [3], M2 [3] [3], D1[5], D2 [51
CvMat M1 cvMat ( 3, 3, CV-64F, M1 )
CvMat M2 · cvMat(3, 3, CV-64F, M2 )
484第12章
第94页
OCR文字识别结果:
CvMat-D1. cvMat(1, 5, CV-64F, D1 )
CvMat-D2-cvMat(1, 5, Cv-64p, D2 )
CvMat-R. cvMat(3, 3, CV-64F, R ) ¢
CvMat-T. cvMat(3, 1, CV-64F, T ) ?
CvMat-E · cvMat ( 3, 3, CV-64F, E ) $
CvMat-F · cvMat(3, 3, CV-64F, F ) 3
if ( displaycorners
cvNamedwindow("corners"1 ) ?
/ / READ IN THE LIST OF CHESSBOARDS
if ( !f
fprintf ( stderr,'can not open file %s \ n", image List )
return
for ( I · O i++)
char buf [1024]
int count O, result=Oi
lr = I % 2i
vector<Cvpoint2D32f>& pts = points[1r] I
if ( !fgets ( buf, sizeof ( bu£ )-3, f ) )
break
size-t len = strlen ( buf )
while( len > O & & isspace(buf ilen-1] ) )
if ( buf [0] == '#')
continue
Iplimage * img-cvLoadlmage( bu£, O )
if ( !img
breaki
imagesize = cvGetsize ( img )
image Names [ lr]. pusH-back ( buf )
/ / FIND CHESSBOARDS AND CORNERS THEREIN
fori int s = 1 s <= maxscale s++
Iplimage"tmg img
if ( s > 1
timg cvcreatelmage(cvsize(img-»width's, img-
»height · s ),
img-»depth, img-»nchannels )
投影与三维视觉485
第95页
OCR文字识别结果:
:司
cvResize( img, timg, CV_INTER.. CUBIC )
result cvFindchessboardcorners( timg, cvsize(nx, ny ),
& temp [0], & count,
CV_CALIB_CB_ADAPT IVE_THRESH
CV-CALIB-CB-NORMALIZE-IMAGE )
if ( timg = img
cvReleaselmage( &timg )
i£( result \t s == maxscale
if ( result
break
if ( displaycorners
printf ("%s \ n", buf )
Iplimage"cimg cvCreatelmage( imagesize, 8, 3 }-
cvc\. TColor ( img, cimg, CV_GRAY2BGR. )
cvDrawchessboardcorners ( cimg, cvsize ( nx, ny ), & temp [0]
count, result )
cvshowlmage( corners", cimg )
cvReleaselmage( &cimg )
if ( cvwait Key ( 0 ) 27 //A11ow ESC to quit
exit(-1 )
else
putchar ('.')
N-pts. sizeo
pts. Resize{N + n, cvpoint2D32f ( 0, 0 ) )
active [ lr] · pusH-back ( ( uchar ) resulc )
/ /. ssert( result = O )
1f ( result
//calibration will suffer without subpixel interpolation
cvFindcornersubpix( img, &Lemp[O], count,
cvTermcriteria ( CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,
486第12章
第96页
OCR文字识别结果:
30, 0. 01 ) )
copy( temp-begino, temp. Endo, pts. Begino
+ N )
E. 1''"fl
printf ("\ n")
/ / HARVEST CHESSBOARD 3D OBJECT POINT LIST
nframes active[O]. sizeo //Number of good chessboads found
objectpoints. Resize ( nframes*n )
fori I 0 I < ny i++
fori j = 0 j < nx j++
objectpoints[i+nx + j]
cvpoint3D32f ( i*squaresize, j * squaresize, O )
fori I 1 I nframes i++
copy( objectpoints. Begino, abjectpoints. Begino + n,
objectpoints. Begino + i*n )
npoints. Resize ( nframes, n )
N nframes*n
CvMat_objectpoints = cvMat{1, N, CV_32rr C3, &objectpoints[O]
CvMat_imagepoints1-cvMat ( 1, N, CV_328C2, &points[O] [0] )
CvMat imagepoints2 cvMat(1, N, CV_32FC2, &points[1][O] )
CvMat_npoints = cvMa 匕 ( 1, npoints. sizeo, CV_32S, &npoints[O] )
cvsetldentity(&_M1 )
cvsetldentity(&_M2 )
cvzero(&_D1 )
cvzero(&_D2 )
/ / CALIBRATE THE STEREO CAMERAS
printf ("Running stereo calibration..")
fflush ( s匕dout )
cvstereocal ibrate( &-obj ectpoints, &-imagepoints 1,
&-imagepoints2, &-npoint s,
&一M1,压一D 1,压一M2,&一D2,
images I z e,&一R,&一了,&一E,&一F,
cvTermcri teria ( CV-TERMCRIT-ITER+
CV-TERMCRIT EPS, 100, le-5 ),
CV-CAL I B-F I X-ASPECT-RATIO +
CV-CAL I B-ZERO_TANGENT-DIST +
CV一C八乙I B一SAME一FOCA乙一LENGTH)
printf ("done \ n")
/ / CALIBRATION QUALITY CHECK
投影与三维视觉487
第97页
OCR文字识别结果:
/ / because the output fundamental matrix implicitly
/ / includes all the output information,
/ / we can check the quality of calibration using the
// epipolar geometry constraint m2^ t*F*m1 · O
vector<Cvpoint3D32f> lines[2]
points [ 0 ]. Resize ( N )
points 11 1. Resize (N)
imagepoints1-cvMat(1, N, CV-32FC2, &points[OJ[O] )
imagepoints2. cvMat(1, N, CV-32FC2, &points[1][O] )
lines [0]. Resize (N)
lines [1]. Resize (N )
CvMat-L1 · cvMat(1, N, CV-32FC3, &lines[O][O] )
CvMat-L2. cvMat(1, N, CV-32FC3, &lines[1] [0]]
//A1ways work in undistorted space
cvundistortpoints( &_imagepoints1, &_imagepoints1,
cvundistortpoints( &_imagepoints2, &_imagepoints2,
cvcomputecorrespondEpi 1 ines ( &_imagepoints1, 1, &_F,
cvcomputecorrespondEpilines( &_imagepoints2, 2, &_F,
double avg Err O
fori I 0 I < N i++
double err = fabs{points[O] [i]. x*lines[1] [i]. x +
points[O] [i]. y +lines[1] [i]. y + lines[1] [i]. z )
+ fa. Bs(points[1] [i]. x+lines[O] [i]. x +
avg Err += err
printf ("avg err = %g \ n", avg Err / ( nframes*n ) )
/ / COMPUTE AND DISPLAY RECTIFICATION
if ( showundistorted
CvMat* mx1 · cvcreate Matl imagesize. Height,
imagesi ze. width, CV. 3 2 F
CvMat* my1-cvcreate Matl imagesize. Height,
imagesize. width, CV_32F
CvMat* mx2 · cvcreate Matl imagesize. Height,
imagesi ze. width, CV_3 2 F )
CvMat* my2. cvcreate Matl imagesize. Height,
imagesize. width, CV. 3 2F
488第12章
第98页
OCR文字识别结果:
旷'""'国画曾邕邕如
CvMat* imglr · cvcreate Matl imagesize. Height,
imagesize. width, CV-8U )
CvMat* img2r-cvcreateMat( imagesize. Height,
imagesi ze. width, CL8U )
CvMat* disp-cvcreate Matl imagesize. Height,
imagesize. width, CV-16S )
CvMat* vdisp-cvcreateMat( imagesize. Height,
imagesi ze. width, CV-8U )
CvMat* pair
CvMat-R1. cvMat(3, 3, CV_64F, R1 )
CvMat-R2 · cvMat ( 3, 3, CV_64F, R2 )
// IF BY CALIBRATED ( BOUGUET'S METHOD )
if ( useuncalibrated 0
CvMat_P1 cvMat(3, 4, CV_64F, P1 )
CvMat_P2 cvMat ( 3, 4, CV_64F, P2 )
cvstereoRectify( &_M1, &_M2, &_D1, &_D2,
0 /"CV_CALIB_ZERO_DISPARITY · / )
isvertica1Stereo = fabs ( P2[1j[3] ) > fabs ( P2[Oj[3] )
//precompute maps for cvRemapo
'cvlnitundistort Rectify Map(&_M1, &_D1, &_R1, &_P1, mx1, my1 )
cvlnitundistort Rectify Map(&_M2, &_02, &_R2, &_P2, mx2, my2 )
/ / OR ELSE HARTLEY'S METHOD
else if ( useuncalibrated 111 useuncalibrated 2
/ / use intrinsic parameters of each camera, but
/ / compute the rectification transformation directly
/ / from the fundamental matrix
double H1[3. I [3]. H2 [3] [3], IM[3] [3]
CvMat H1. cvMat ( 3, 3, CV-64F, H1 )
CvMat H2 · cyMat(3, 3, CV-64F, H2 )
CvMat IM-cvMat(3, 3, CV_64F, IM )
/ / Just to Show you could have independently used F
if ( useuncalibrated.. 2
cvFindFundamenta1Mat( &-imagepoints1,
&-imagepoints2, &-F)
cvstereoRectifyuncalibrated( &-lmLgepoints1,
投影与三维视觉489
images I z e,
第99页
OCR文字识别结果:
&_imagepoints2, &_F,
imagesize,
cvlnvert ( &_M1, &_IM )
cvlnvert ( &_M2, &_IM )
cvMatMu1(&_H2, &_M2,-&_R2 )
cvMatMu1 ( &_IM, &_R2, &_R2 )
//precompute map £or cvRemapo
cvlnitundistort Recti fyMap ( &_M1, &_D1, &_R1, &_M1, mx1, my1 )
cvlnitundistort Rectify Map ( &_M2, &_D1, &_R2, &_M2, mx2, my2 )
else
assert ( 0 )
cvNamedwindow ('rectified", 1 )
// RECTIFY THE IMAGES AND FIND DISPARITY MAPS
if(
lisvertica1Stereo
pair cvcreate Matl imagesize. Height, imagesize. width"2,
CV_8UC3 )
else
pair cvcreate Matl images1ze. Height"2, imagesize. width,
cv_uc3 )
//setup for finding stereo correspondences
CvstereoBMState"BMState = cvcreatestereoBMStateo
assert(BMState !-O )
BMState->pre Filtersize=41
BMState->pre Filtercap = 31
BMState-»SADWindowSize-41
BMState->min Di spari ty--6 4
BMState->numberof Di spari ties =128
BMState->texture Threshold-10
BMState->uniquenes sRat io=15
£or( I 0, I < nframes i++
Iplimage"imgl= cvLoadlmage{image Names[O][i]. c_str 0. 0 )
Iplimage"img2 = cvLoadlmage(image Names[1] [i]. c_str 0, ( )
if ( img1 & & img2
CvMat part
cvRemap ( img1, imglr, mx1, my1 )
第100页
OCR文字识别结果:
==== · =»«tllll
/ / When the · stereo camera is oriented vertically,
/ / useuncalibrated==O does not transpose the
/ / image, so the epipolar lines in the rectified
/ / images are vertical. Stereo correspondence
/ / function does not support such a cas. e.
cvFindstereocorrespondenceBM( imglr, img2r,
BMState ) /
cvNormalize( disp, vdisp, 0, 2 56, CV-MINMAX
cvNamedwindow("disparity")
cvshowlmage( · disparity", vdisp )
if ( !isvertica1stereo
cvGetcols ( pair, & part, O, imagesi ze. width )
cvcvtcolor ( imgl r, & part, CV-GRAY2 BGR )
cvGetcols( pair, & part, imagesize. width,
imagesize. width*2 ) I
cvcvtcolor ( img2 r, & part, CV-GRAY2 BGR )
fori j = 0 j < imagesize. Height j += 16
cvLine( pair, cvpoint(O, j ),
cvpoint (imagesize. width*2, j ),
CV-RGB(0, 255, 0 ) )
else
cvGetRows ( pair, & part, O, images ize. Height )
cvcvtcolor ( imgl r, & part, CV_GRAY2 BGR )
cvGetRows( pair, & part, imagesize. Height,
imagesize. Height*2 )
cvcvtcolor ( img2 r, & part, CV-GRAY2 BGR )
fori j 0 j < imagesize. width j += 16
cvLine( pair, cvpoint(i, O ),
cvpoint ( j, imagesi ze. Height · 2 ),
CV-RGB(0, 255, 0 ) )
cvshowlmage("rectified", pair
if ( cvwait Keyo == 27
break
投影与三维视觉491
di sp,
第101页
OCR文字识别结果:
cvReleaselmage( &img1 ) I
cvReleaselmage( &img2 )
cvRel easestereoBMState ( & BMState )
cvReleaseMat( &mx1 )
cvRelease Matl &my1 )
cvRelease Matl &mx2 )
cvRelease Matl &my2 )
cvRelease Matl &imglr
cvRelease Matl &img2r )
cvRelease Matl &disp )
int
main ( void )
Stereocalib("list. Txt", 9, 6, 1 )
return o
[446-452]
从三维重投影获得深度映射
很多算法直接使用视差映射——比如检测目标是否在工作台之上(或者从工作台伸
出)。但是对三维形状匹配、三维模型学习和机器人抓取等应用,我们需要真正的
三维重建或者深度映射。幸运的是,我们至今建立的许多立体机制都能使这项任务
变得简单。回顾前文介绍的4×4的重投影矩阵Q.也请回顾,如果给定视差d和
2D点(x,夕),我们就能用下面的公式来计算3D深度
其中三维坐标就是(X/w,片W,Z/ W)。显然Q可以解析出摄像机视线是否收敛以及摄
像机基线和两幅图像的主点。因此,我们不需要明确解释收敛或者前向平行摄像
机,而只需要简单地通过矩阵相乘就提取深度信息。OpencV中有两个函数帮助我
们完成这项工作。第一个函数是你之前就熟悉的,操作的是一序列点及其关联视
差,函数名称是cvperspectve Transform
492第12章
第1页
OCR文字识别结果:
F
void cvperspective Transform(
cons t CvArr *point sXYD,
CvArr* result3DPoints,
const CvMat *Q
r=l
第二个函数(也是新函数)cvReprojec七Image To3D 0是操作整幅图像
voi d cvReproj ectlmageTo3D(
CvArr *disparitylmage,
CvArr +result3Dimage,
CvAr r * Q
这个程序输入的是单通道的dispari七ylmage,并利用4 × 4重投影矩阵Q,将每
个像素的(x,y)坐标和视差(比如矢量【x夕d】 T)转换到匹配的三维点(刀W.打W'"W)。
输出的是大小与输入相同的3通道浮点型(捉着16为整型)图像。
当然,这两个函数都允许你传入由cvstereo Rectify计算出的任意投影变换(比如
标准转换)或者它们的叠合、任意的3D旋转、变换等。
图12-17给出了利用cvReprojectlmage To3D 0处理一幅杯子和椅子图像的结果。
图 12-17 使用函数 cvFindstereocorrespondenceBMO和函数 cvReprojectl-
mageTo3Do(图像来源于W川ow Garage)计算的深度映射输出实例(对于一个
杯子或椅子来说)
来自运动的结构
来自运动的结构是移动机器人技术以及更广泛的视频图像分析,比如来自手持摄像
投影与三维视觉493
第2页
OCR文字识别结果:
机等领域中非常重要的主题。由运动中得到的结构是一个很广的领域,并且在这个
领域中,已经做了大量的研究工作。然而,通过简单的观测可以完成更多的内容
在一个静态的场景中,由移动摄像机拍摄的一幅图像和任何另一台摄像机拍摄的图
像没有什么不同。所以,所有的直觉以及数学和算法机制,都可以迅速地应用于这
种情形中。当然,描述词。静态。是比较苛刻的,但是在很多实际情形中,场景要
么是静止的,要么是近似静止的,即场景中只有很少的移动点,这可以利用鲁棒性
拟合方法,作为异常点处理。
考虑摄像机在建筑物内移动的情形,如果环境中有相对较多的可识别特征可以被光
流技术找到(比如cvcalcoptica1F1owpyrLK0),这时我们就应该可以计算足够多
的点之间——帧到帧——的匹配,来重建摄像机轨迹(此信息通过本征矩阵E来表
示,E可以通过基础矩阵F和摄像机内参数矩阵M来计算获得)、建筑物的全部
3D结构、建筑物中的上述所有特征的位置。cvstereoRectifyuncalibra·e工程
序只需要基础矩阵就可以根据缩放比例来计算场景上的基本结构。
二维和三维下的直线拟合
本章中最后一个兴趣主题是常规的直线拟合。直线拟合的出现来自很多原因,也导
致很多相关内容。我们在这里选择它来介绍,是因为在分析三维点的时候频繁与直
线拟合相关(尽管这里描述的函数也能拟合二维直线)。直线拟合一般使用统计的
鲁棒算法。OpencV中的直线拟合算法cvFit Li·eo适用于需要直线拟合的任何
时候
void cvFit Linet
const CvArr* points,
int dist-type,
double param,
double reps,
double aeps,
float · line
) [453-455]
点序列可以是厅×3或JV×2的浮点值矩阵(可以是2D和3D上的点),也可以是
cvpointxxx结构序列©。参数己ist_type表示对所有点列进行最小化的距离准
®这里××X表示诸如2032F或者3064f等可以被替换的字符。
494 第 12 章 I
第3页
OCR文字识别结果:
歹
"'".'''._T一₩
则。(如表12-3所示)
表12-3用来计算dist_type值的距离准则
CV_DIST_L2 P (-) = 2
参数line是存储结果的位置。如果点存在.N×2数组中,line就是一个指向4个
浮点数数组的指针(如上loatariay[4】)如果点存在N×3数组中,lIne就是一
个指向6个浮点数数组的指针(比如float array 【6】)。在第一种情形中,返回值
是(v.,如xo,Jo),其中卜x,v夕)是和拟合直线平行的归一化向量,(xo,yo)是直线上的
一点。类似地,后一种(3D)情形中的返回值是(vx,VJ·,vz·xo,yo:zo),其中(v.,如v.)
是和拟合直线平行的归一化向量,(xo,lo,zo)是直线上的一点。给定了直线的形
式,精度评价参数reps和aep5就是reps是xo,夕o[,zo]估计的请求精度,ae·s
是vx,v,[,v,]的角度精度。OpenCV文档对这两个精度值的推荐值都是0.01.
cvFit Lineo可以拟合2D和3D中的直线。因为通常只需要2D中的直线拟合,而
OpencV中的3D技术则变得更重要了(见第14章),我们最后将以一个直线程序来
结束,见例12-4a。代码中,我fr 1首先假设直线周围有一些2D噪声点,,然后增加
一些和直线无关的随机点(称之为异常点),最后将这些点拟合成直线并显示出来。
cvFit Line O很好地忽略了离群点,这在测量值被高噪声、传感器故障等破环的实
际应用中非常重要。【455-456】
国感谢Vadim Pisarevsky生成的这个实例。
投影与三维视觉495
第4页
OCR文字识别结果:
例12-42D直线拟合
# include"cv. h"
#include "h ighgu I. h"
#include <math. H>
int maini int arge, char** argv
Iplimage"img-cvcreatelmage( cvsize( 500, 500 ), 8, 3 )
CvRNG rng cvRNG(-1 )
cvNamedwindow( fitline", 1 )
£or ( )
char key
int I
int count cvRandlnt ( &rng) %100 + 1
1nt outliers-count / 5
£1oat a = cvRandRea1 ( &rng ) *200 ?
float b · cvRandRea1 (&rng ) *40i
float angle = cvRandRea1 ( &rng ) *CV-Pli
float cos-a-cos ( angle ) I
float sin-a. sin ( angle ) }
Cvpoint pt1, pt2i
Cvpoint* points = «Cvpoint* ) malloc( count ·
CvMat point Mat-cvMat( 1, count, CV-32SC2,
float line[4]
£1oat d, c ?
s izeof ( point s [0] ) )
points
b MiNta"0. 3, b )
/ / generate some points that are close to the lIne
fori I 0 I < count outliers i++ )
float x ( cvRand Real ( &rng ) *2-1 )"a
£1oat y ( cvRand Real ( &rng) *2-1 ) *b
poinEs [i]-x = cvRound(x*cos_a y'sin_a img-»wiMh12 )
points [ I ]. y-cvRound (x · sin_a y"cos_a img-»heght / 2 )
/ / generate"completely o£f · points
fori I < count i++ )
I t
poincs[i]. x-cvRandlnt ( &rng ) % img->width
496第12章
第5页
OCR文字识别结果:
points[i]. y-cvRandlnt ( &rng ) % img->height
.. Z''"I °g )
/ / draw the points
fori I. O I < count i++
cvcircle (
img,
points[i],
2,
( I < count outliers ) ? CV_RGB(255, 0, 0 ) CV_RGB(255, 255, 0 )
CV_FILLED, CV_AA,
/ / and the line long enough to cross the whole image
d-sqrt ( ( double ) line [ 0 ] * 1 ine [ 0 ] + ( double ) line [ 1 ] · linet 1 ] )
line[O] / = d
t ( float ) ( img-»width + img-»height )
pt1. x cvRound(line[2] ー line [0]*t)
pt1. y-cvRound(line[3] ー line[1]*t ) }
pt2. x-cvRound(line[2] + line [Ol*t]
pt2. y-cvRound(line[3] + line[1j*t ) ?
cvLine ( img, pt1, pt2, CV-RGB ( 0, 255, 0 ), 3, CV-AA, O )
cvshowlmage("fitline", img ) ?
key ( char ) cvwaitKey ( 0 )
if ( key 27 1 key-q II key-Q') / / Esc'
break
free( points )
cvDestroywindow ( fitline")
return o
[456-457]
投影与三维视觉497
第6页
OCR文字识别结果:
练习
1.
使用函数cvcalibratecamera20和至少15幅棋盘图像来对摄像机进行标
定,然后调用函数cvprojectpoints2 0,使用由摄像机标定得到的旋转和平
移向量,将一个正交箭头投影到每幅图像的棋盘(曲面法线)上。
2.
三维操纵杆。利用一个简单的已知目标,用至少四个不共面的可跟踪的测量点
作为POSIT的输入参数,并以此目标作为一个三维操纵杆在图像上移动小棒
图形。
3.在文中的鸟瞰图实例中,通过平面上空的摄像机水平的对周围成像,我们看到
在文中的鸟瞰图实例中,通过平面上空的摄像机水平的对周围成像,我们看到
了地平面的单应性有一条水平线,而超过了该水平线,单应性是无效的,怎么
使无穷平面上具有水平线?为什它不会永远出现?
提示在远离摄像机的平面上的等间隔点序到上绘制直线。摄像机平面到下一
点的角度与上一点的角度是如何变化的?
4.在观测地平面的视频摄像机内应用鸟瞰图。实时运行它,当目标围绕鸟瞰图图
像和常规图像移动时会发生什么?
5.安装两个摄像机或者一台移动摄像机来拍摄两幅图像,然后完成以下练习。
a,计算、存储并检测基础矩阵。
b,重复几次计算基础矩阵,看看计算的稳定性。
6,如果有一个标定好的立体摄像机,并且跟踪两个摄像机中的移动点,请问你如
何使用基础矩阵来获得跟踪误差?
7、计算和绘制两台摄像机装置的极线来建立立体视觉。
8,安装两台视频摄像机,应用立体校正,并根据以下条件对深度精度进行实验。
a,在场景中放入一块镜子时会发生什么?
b,改变场景中的纹理并汇报结果。
c.尝试不同的视差方法并汇报结果。
9安装立体摄像机,并在手臂上放一些纹理,f,红用所有的己ist_type方法对手
臂进行直线拟合。比较不同方法的精度性和h:靠性。
498第12章