0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

极限校正的实现原理方法有哪些

新机器视觉 来源:新机器视觉 2023-07-14 11:03 次阅读

导读

极限校正的实现原理方法以及代码详解。

为什么要做极线校正?

三维重建是通过双目立体匹配实现的如图1,通过匹配空间中点在两个图像中的投影点,再根据三角关系得到P的Z值。

410c378c-21d8-11ee-962d-dac502259ad0.png41274658-21d8-11ee-962d-dac502259ad0.png

我们双目相机拍摄的时候实际情况下如下图a,两个图像做匹配时如我们图中蓝色箭头指示的匹配点那样,需要在全图中进行查找。但是如果我们对相机进行校正,使得它们成像面平行且行对齐如下图b,匹配点在同一行。那么我们只需在同行上查找,大大节约时间。因此,极线校正目的是对两幅图像的二维匹配搜索变成一维,节省计算量,排除虚假匹配点。

414327d8-21d8-11ee-962d-dac502259ad0.png

做极线校正我们需要知道哪些基础的立体视觉相关的基础知识?

1. 齐次坐标,刚体变换

齐次坐标

用n+1维矢量表示n维矢量,主要用途是可以方便矩阵运算。(参考下式)

刚体变换

4166bd10-21d8-11ee-962d-dac502259ad0.png

假设欧式空间中一点, 在两个坐标系中的坐标分别为和, 那么图中变换公式:

即:

用齐次坐标表示:

刚性物体无论位置和方向发生变换还是在不同坐标系下观察同一个物体,它的形状和大小都保持不变;

3个旋转3个平移共6个自由度;

用途:

计算一个刚体经过旋转和平移后的新坐标 ;

计算同一刚体在不同坐标系下的坐标。

2.图像坐标系,相机坐标系,世界坐标系

图像坐标系

417d4288-21d8-11ee-962d-dac502259ad0.png

上图中,是表示以像素为单位的图像坐标系的坐标,是以为单位的图像坐标系的坐标,是相机光轴与图像的交点其对应的像素坐标, 每个像素在轴和轴对应的 物理尺寸。两者转换关系如下:

用矩阵的表示形式:

逆关系:

相机与世界坐标系

为相机光心,轴与图像的轴平行,轴为相机光轴与相机图像平面垂直交点就是图像坐标原点。与组成的直角坐标系为相机坐标系,为焦距。

418ed5fc-21d8-11ee-962d-dac502259ad0.png

世界坐标系与相机坐标系转换关系:

式中为的正交单位矩阵,为三维平移向量,为矩阵。

3.相机投影模型(针孔投影模型)

41ac4ace-21d8-11ee-962d-dac502259ad0.png

把图像平面放到针孔前方(数学上等价,计算更简单):

41c0918c-21d8-11ee-962d-dac502259ad0.png

当已知图像点p时,由针孔成像模型,任何位于射线OP上的空间点的图像点都是p点,因此空间点不是唯一确定的。

投影关系 (从世界坐标系到图像坐标系)

称为归一化焦距,只与相机内部参数有关, 被称为相机内参;由相机相对世界坐标系的方位决定, 被称为相机外参。确定相机内外参数被称为相机标定。

4.对极几何

425be07e-21d8-11ee-962d-dac502259ad0.png

极点: 极点: 右相机坐标原点在左像平面上的像; 极点:左相机坐标原点在右像平面上的像

极平面:由两个相机坐标原点、和物点组成的平面

极线: 极平面与两个像平面的交线

极线约束:给定图像上的一个特征, 它在另一幅图像上的匹配视图一定在对应的极线上, 即已知则它对应在右图的匹配点一定在极线上反之亦然。

4272a5b6-21d8-11ee-962d-dac502259ad0.png

极线约束给出了对应点重要的约束条件,它将对应点匹配从整幅图像中查找压缩到一条线上查找,大大减小了搜索范围,对对应点的匹配起指导作用。

极限校正怎么实现?

1.三角测量原理

假设我们两台摄像机像平面精准位于同一平面上,且行对齐,两个光轴严格平行。

4298764c-21d8-11ee-962d-dac502259ad0.png

利用三角形关系我们很容易推出Z值:

如果主点坐标相同则可简化为:

因为视差,且为我们的深度值, 故:

视差与深度图关系:

视差与深度成反比,视差接近0时,微小的视差变化会产生较大的深度变化

当视差较大时,微小的视差变化几乎不会引起深度多大的变化

因此,立体视觉系统仅物体距离相机较近时具有较高的深度精度

42b3424c-21d8-11ee-962d-dac502259ad0.png

2.极线校正原理

校正过程:将相机在数学上对准到同一观察平面上,使得相机上像素行是严格对齐的

42d41b02-21d8-11ee-962d-dac502259ad0.png

校正目的:对两幅图像的二维匹配搜索变成一维,节省计算量,排除虚假匹配点

3.校正算法步骤:(参考文献A compact algorithm for rectification of stereo pairs

为了将摄相机极点变换到无穷远使得极线水平对准, 我们创建一个旋转矩阵, 首先是轴的旋转, 我们将轴旋转到与基线相同的方向即旋转后新轴就是, 旋转向量:

确定旋转后的新轴, 只需满足与正交即可:选则与主光轴和相交的方向:

新的轴, 与垂直且满足右手定则:

最终得到的旋转矩阵:

则左右两个图像新的旋转矩阵:

4.校正后,baseline 计算:

42f3de24-21d8-11ee-962d-dac502259ad0.png

下式中是指左相机光心在右相机坐标系下的坐标(也等于与右相机光心的距离),t 求解公式的意义是左相机光心在右相机校正后的坐标系下的坐标(也等于与右相机校正后的坐标系下光心的距离) 。故baseline就是轴方向的距离。

极线校正代码怎么写?

//see:"Acompactalgorithmforrectificationofstereopairs",A.Fusiello,E.Trucco,andA.Verri,2000
//极线校正
REALCamera::StereoRectifyFusiello(constcv::Size&size1,constCamera&camera1,constcv::Size&size2,constCamera&camera2,Matrix3x3&R1,Matrix3x3&R2,Matrix3x3&K1,Matrix3x3&K2)
{
//computerelativepose
//计算相对位姿
RMatrixposeR;
CMatrixposeC;
ComputeRelativePose(camera1.R,camera1.C,camera2.R,camera2.C,poseR,poseC);

//newxaxis(baseline,fromC1toC2)
//新的x轴,基线方向
constPoint3v1(camera2.C-camera1.C);
//newyaxes(orthogonaltooldzandnewx)
//新的y轴,垂直旧的Z轴(光轴)和新的X轴
constPoint3v2(camera1.Direction().cross(v1));
//newzaxes(nochoice,orthogonaltobaselineandy)
//新的Z轴,垂直上面两个新轴
constPoint3v3(v1.cross(v2));

//newextrinsic(translationunchanged)
//新的外参,平移不变
RMatrixR;
R.SetFromRowVectors(normalized(v1),normalized(v2),normalized(v3));

//newintrinsic(arbitrary)
//新的内参
K1=camera1.K;K1(0,1)=0;
K2=camera2.K;K2(0,1)=0;
K1(1,1)=K2(1,1)=(camera1.K(1,1)+camera2.K(1,1))/2;

//newrotations
//新的选择从校正前的相机坐标系转到校正后的相机坐标系
R1=R*camera1.R.t();
R2=R*camera2.R.t();
//计算新的基线距离
constPoint3t(R2*(poseR*(-poseC)));
ASSERT(ISEQUAL(-t.x,norm(v1))&&ISZERO(t.y)&&ISZERO(t.z));
returnt.x;
}//StereoRectifyFusiello

极线校正后的视差图转校正前的深度图怎么转,代码怎么实现?

视差图是校正后的坐标系下得到的值,首先将其转换为校正后坐标系下的深度图

则:

把上式写成矩阵形式:

式中定义如下:

将校正后的坐标系下深度图转换到校正前的相机坐标系下

将校正后的坐标系下深度图转换到校正前的相机坐标系下

已知:校正前的相机坐标系下坐标转到校正后相机坐标系下坐标转换关系如下:

则已知校正后的求校正前的公式如下:

再将其投影到图像坐标系下:

即:

将上两步合并得到校正后坐标系下的视差图(与校正前的坐标系下的深度图的转换矩阵

已知:

则:

代码实现

转换矩阵求解

boolImage::StereoRectifyImages(constImage&image1,constImage&image2,constPoint3fArr&points1,constPoint3fArr&points2,Image8U3&rectifiedImage1,Image8U3&rectifiedImage2,Image8U&mask1,Image8U&mask2,Matrix3x3&H,Matrix4x4&Q)
{
ASSERT(image1.IsValid()&&image2.IsValid());
ASSERT(image1.GetSize()==image1.image.size()&&image2.GetSize()==image2.image.size());
ASSERT(points1.size()&&points2.size());

#if0
{//displayprojectionpairs
std::vectormatches1,matches2;
FOREACH(i,points1){
matches1.emplace_back(reinterpret_cast(points1[i]));
matches2.emplace_back(reinterpret_cast(points2[i]));
}
RECTIFY::DrawMatches(const_cast(image1.image),const_cast(image2.image),matches1,matches2);
}
#endif

//computerectification
//校正计算
Matrix3x3K1,K2,R1,R2;
#if0
constREALt(Camera::StereoRectify(image1.GetSize(),image1.camera,image2.GetSize(),image2.camera,R1,R2,K1,K2));
#elif1
constREALt(Camera::StereoRectifyFusiello(image1.GetSize(),image1.camera,image2.GetSize(),image2.camera,R1,R2,K1,K2));
#else
Posepose;
ComputeRelativePose(image1.camera.R,image1.camera.C,image2.camera.R,image2.camera.C,pose.R,pose.C);
cv::MatP1,P2;
cv::stereoRectify(image1.camera.K,cv::noArray(),image2.camera.K,cv::noArray(),image1.GetSize(),pose.R,Vec3(pose.GetTranslation()),R1,R2,P1,P2,Q,0/*cv::CALIB_ZERO_DISPARITY*/,-1);
K1=P1(cv::Rect(0,0,3,3));
K2=P2(cv::Rect(0,0,3,3));
constPoint3_t(R2*pose.GetTranslation());
ASSERT((ISZERO(_t.x)||ISZERO(_t.y))&&ISZERO(_t.z));
constREALt(ISZERO(_t.x)?_t.y:_t.x);
#if0
cv::Matmap1,map2;
cv::initUndistortRectifyMap(image1.camera.K,cv::noArray(),R1,K1,image1.GetSize(),CV_16SC2,map1,map2);
cv::remap(image1.image,rectifiedImage1,map1,map2,cv::INTER_CUBIC);
cv::initUndistortRectifyMap(image2.camera.K,cv::noArray(),R2,K2,image1.GetSize(),CV_16SC2,map1,map2);
cv::remap(image2.image,rectifiedImage2,map1,map2,cv::INTER_CUBIC);
return;
#endif
#endif
if(ISZERO(t))
returnfalse;

//adjustrectifiedcameramatricessuchthattheentireareacommontobothsourceimagesiscontainedintherectifiedimages
//调整校正后的相机矩阵,使两个源图像的公共区域都包含在校正后的图像中
cv::Sizesize1(image1.GetSize()),size2(image2.GetSize());
if(!points1.empty())
Camera::SetStereoRectificationROI(points1,size1,image1.camera,points2,size2,image2.camera,R1,R2,K1,K2);
ASSERT(size1==size2);

//computerectificationhomography(fromoriginaltorectifiedimage)
//计算校正的单应性矩阵(描述的是两个图像像素坐标的转换矩阵H[u,v,1]^t=[u',v',1]^t)(从原始图像到校正图像)
constMatrix3x3H1(K1*R1*image1.camera.GetInvK());H=H1;
constMatrix3x3H2(K2*R2*image2.camera.GetInvK());

#if0
{//displayepipolarlinesbeforeandafterrectification
Posepose;
ComputeRelativePose(image1.camera.R,image1.camera.C,image2.camera.R,image2.camera.C,pose.R,pose.C);
constMatrix3x3F(CreateF(pose.R,pose.C,image1.camera.K,image2.camera.K));
std::vectormatches1,matches2;
#if1
FOREACH(i,points1){
matches1.emplace_back(reinterpret_cast(points1[i]));
matches2.emplace_back(reinterpret_cast(points2[i]));
}
#endif
RECTIFY::DrawRectifiedImages(image1.image.clone(),image2.image.clone(),F,H1,H2,matches1,matches2);
}
#endif

//rectifyimages(applyhomographies)
//校正图像,就是利用单应性矩阵,把原图像每个像素坐标转换到校正的图像下。
rectifiedImage1.create(size1);
cv::warpPerspective(image1.image,rectifiedImage1,H1,rectifiedImage1.size());
rectifiedImage2.create(size2);
cv::warpPerspective(image2.image,rectifiedImage2,H2,rectifiedImage2.size());

//markvalidregionscoveredbytherectifiedimages
//标记正确图像覆盖的有效区域
structCompute{
staticvoidMask(Image8U&mask,constcv::Size&sizeh,constcv::Size&size,constMatrix3x3&H){
mask.create(sizeh);
mask.memset(0);
std::vectorcorners(4);
corners[0]=Point2f(0,0);
corners[1]=Point2f((float)size.width,0);
corners[2]=Point2f((float)size.width,(float)size.height);
corners[3]=Point2f(0,(float)size.height);
cv::perspectiveTransform(corners,corners,H);
std::vector>contours(1);
for(inti=0;i<4; ++i)
    contours.front().emplace_back(ROUND2INT(corners[i]));
   cv::drawContours(mask, contours, 0, cv::Scalar(255), cv::FILLED);
  }
 };
 Compute::Mask(mask1, size1, image1.GetSize(), H1);
 Compute::Mask(mask2, size2, image2.GetSize(), H2);

 // from the formula that relates disparity to depth as z=B*f/d where B=-t and d=x_l-x_r
 // and the formula that converts the image projection from right to left x_r=K1*K2.inv()*x_l
 // compute the inverse projection matrix that transforms image coordinates in image 1 and its
 // corresponding disparity value to the 3D point in camera 1 coordinates as:
 // 根据depth=Bf/d的关系,计算投影矩阵Q将校正的视差图转到为校正的深度图。
 ASSERT(ISEQUAL(K1(1,1),K2(1,1)));
 Q = Matrix4x4::ZERO;
 //   Q * [x, y, disparity, 1] = [X, Y, Z, 1] * w
 ASSERT(ISEQUAL(K1(0,0),K2(0,0)) && ISZERO(K1(0,1)) && ISZERO(K2(0,1)));
 Q(0,0) = Q(1,1) = REAL(1);
 Q(0,3) = -K1(0,2);
 Q(1,3) = -K1(1,2);
 Q(2,3) =  K1(0,0);
 Q(3,2) = -REAL(1)/t;
 Q(3,3) =  (K1(0,2)-K2(0,2))/t;

 // compute Q that converts disparity from rectified to depth in original image
 // 计算将视差从校正到原始图像深度转换的Q值
 Matrix4x4 P(Matrix4x4::IDENTITY);
 cv::Mat(4,4,cv::DataType::type,P.val)(cv::Rect(0,0,3,3)));
Q=P*Q;
returntrue;
}

根据求解的转换矩阵进行视差图和深度图相互转换

/**
*@brief 根据原图的深度图计算校正后的图像的视差图,视差图事先根据有效尺寸分配好。
*
*@param[in]depthMap原图的深度图
*@param[in] invH 转换矩阵:把校正图的像素坐标转换到原图
*@param[in]invQ转换矩阵把[x*zy*zz1]*winoriginalimagecoordinates(z即为depth)转到[x'y'disparity1]inrectifiedcoordinates
*@param[in] subpixelSteps 亚像素精度,如果是4则对于精度是0.25,主要是视差值存储的都是整型。所以得到的视差会乘这个值转成整型。具体转回float真值时会除掉这个数
*@param[in]disparityMap视差图
*/
voidSemiGlobalMatcher::Depth2DisparityMap(constDepthMap&depthMap,constMatrix3x3&invH,constMatrix4x4&invQ,DisparitysubpixelSteps,DisparityMap&disparityMap)
{
autopixel=[&](int,intr,intc){
//rc加half窗口的原因是视差图是有效像素开始的起始是从(halfWindowSizeX,halfWindowSizeY)开始的而非(0,0)
constImageRefx(c+halfWindowSizeX,r+halfWindowSizeY);Point2fu;
//把校正图像上的像素坐标转到原图坐标上
ProjectVertex_3x3_2_2(invH.val,x.ptr(),u.ptr());
floatdepth,disparity;
//取深度值depth并转到视差上
if(!depthMap.sampleSafe(depth,u,[](Depthd){returnd>0;})||!Image::Depth2Disparity(invQ,u,depth,disparity))
disparityMap(r,c)=NO_DISP;
else
disparityMap(r,c)=(Disparity)ROUND2INT(disparity*subpixelSteps);
};
ASSERT(threads.IsEmpty());
if(!threads.empty()){
volatileThread::safe_tidxPixel(-1);
FOREACH(i,threads)
threads.AddEvent(newEVTPixelProcess(disparityMap.size(),idxPixel,pixel));
WaitThreadWorkers(threads.size());
}else
for(intr=0;r

责任编辑:彭菁

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 代码
    +关注

    关注

    30

    文章

    4555

    浏览量

    66767
  • 立体视觉
    +关注

    关注

    0

    文章

    36

    浏览量

    9730
  • 三维重建
    +关注

    关注

    0

    文章

    24

    浏览量

    9840

原文标题:极线校正后的视差图转校正前的深度图怎么转,代码怎么实现?

文章出处:【微信号:vision263com,微信公众号:新机器视觉】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    请问DLP3435 T型校正实现方法是靠光传感器实现的吗

    求教下 DLP3435DE T型校正实现方法是靠光传感器实现的吗 ,以及DLP3435的N6脚的3DR引脚是这样定义的
    发表于 02-14 09:45

    请问adxrs646温度校正的多点校正方法是什么?

    Weinberg》这篇文章里描述了一种3点校正方法,并提到了采取多点校正方法能提高到40°/h以内,如果是这样的话可以满足我的设计要求,请问一下具体的多点
    发表于 03-01 13:53

    传感器线性校正方法的原理是什么?

    传感器的非线性校正多种方法,并且也都得到了不同程度的应用。传统的非线性传感器线性化的方法是硬件补偿,这种方法难以做到全程补偿,而且补偿硬件
    发表于 10-30 06:30

    光谱仪的正确校正方法

    产品,在使用过程中应当节约,尽量不要用作其他用途。当光谱校正标样使用完以后,请联系仪器维护工程师,不建议自行购买。一般校正方法如下:全谱型:只需激发单块标样,即可通过软件算法自动完成所有谱线的
    发表于 12-14 16:11

    基于FPGA的两点非均匀校正模块的设计与实现

    两点校正算法是一种行之有效的红外图像非均匀校正方法.本文对两点校正算法进行了分析,并推导出了该算法的定点表示形式.利用FPGA在硬件上实现了该算法,内部采用流水线技术,
    发表于 08-15 11:37 17次下载

    多波束天线通道幅相一致性校正实现

    本文针对多波束天线接收机的通道幅相一致性校正,提出了一种基于自适应算法的校正方法并在FPGA 中实现了该方法。在满足系统要求的前提下,该方法
    发表于 01-16 14:34 17次下载

    三目立体视觉外极线校正及其FPGA实现方法

    三目立体视觉外极线校正及其FPGA实现方法
    发表于 09-17 07:30 16次下载

    线性系统的校正方法

    线性系统的校正方法
    发表于 12-30 15:04 0次下载

    利用纹理映射技术实现鱼眼镜头校正研究

    本文详细介绍了采用纹理映射技术实现鱼眼镜头校正方法。实验表明,该方法不但校正好地完成了镜头的校正
    发表于 09-07 20:02 9次下载

    基于距离徙动校正的弹速补偿FPGA实现方法

    针对高速运动平台弹速补偿的实时性要求,在基于距离徙动校正(Range Cell Migration Compensation,RCMC) 的思想上提出了一种弹速补偿的FPGA实现方法。将距离徙动
    发表于 03-30 09:56 2329次阅读
    基于距离徙动<b class='flag-5'>校正</b>的弹速补偿FPGA<b class='flag-5'>实现</b><b class='flag-5'>方法</b>

    CCD图像采集过程中如何进行实时误差校正两种方法详细说明

    根据引入误差的设备不同,分别介绍了两种误差实时校正方法——信号采集部分的实时误差校正和输出设备的实时误差预校正的原理和实现方法。 两种误差实
    发表于 11-22 17:17 18次下载
    CCD图像采集过程中如何进行实时误差<b class='flag-5'>校正</b>两种<b class='flag-5'>方法</b>详细说明

    基于多体量子纠缠的量子传感实现海森堡极限精度的测量

    据了解,基于多体量子纠缠的量子传感能突破标准量子极限实现海森堡极限精度的测量,然而在实验上制备多粒子纠缠态常常面临着较大的挑战。因此,发展出能达到海森堡极限测量精度且在实验上易于
    的头像 发表于 01-15 17:34 2206次阅读

    数列极限的求解方法及案例分析

    数列极限的求解方法及案例分析
    发表于 03-24 10:25 0次下载
    数列<b class='flag-5'>极限</b>的求解<b class='flag-5'>方法</b>及案例分析

    如何使用FPGA实现三目立体视觉外极线校正方法

    系下对图像进行重取样,使图像的行列对齐。给出了基于FPGA的实时计算三目立体视觉外极线校正的硬件实现方法。在时钟频率为60 MHz,图像可分辨的像素数为640×480时,三目立体视觉外极线校正
    发表于 04-01 10:27 12次下载
    如何使用FPGA<b class='flag-5'>实现</b>三目立体视觉外极线<b class='flag-5'>校正</b>的<b class='flag-5'>方法</b>

    thdp0200探头校正方法和步骤

    thdp0200探头校正方法和步骤 THDP0200探头是一种常用于测量电压、电流、频率等信号的设备。为了确保其测量结果的准确性和可靠性,定期进行探头校正非常重要。本文将详细介绍THDP0200
    的头像 发表于 01-08 15:38 246次阅读