根据相机外参实现单应矩阵计算的理论与实践

点击上方“小白学视觉”,选择加"星标"或“置顶

重磅干货,第一时间送达

单应矩阵介绍

单应性在计算机视觉领域是一个非常重要的概念,它在图像校正、图像拼接、俯视图生成,相机位姿估计、视觉SLAM等领域有非常重要的作用。

单应性(Homography)变换是将一幅图像中的点映射到另一幅图像中相应点的变换关系:

f7e14d49756f1da6ea954e8d49dfa526.png

单应矩阵是一个3x3矩阵,具有8个自由度,通常为归一化后表达式,其尺度为1。

下面展示了不同类型的变换,但都与两个平面之间的变换有关。

(1)真实平面和图像平面

796a1d845a82f82f6b5298685acc73ee.png

(2)由两个相机位置拍摄的平面

fb02c8faceb78e9e78342368efb4c4d2.png

(3)围绕其投影轴旋转的相机采集的图像进行拼接

d28f343885197a505aca4cc2356669f4.png

所以单应性矩阵主要用来解决两个问题:

一是表述真实世界中一个平面与对应它图像的透视变换

二是从通过透视变换实现图像从一种视图变换到另外一种视图

外参求解单应矩阵理论

这里将主要讲解以下已知两个相机的位姿如何实现图像的拼接,主要公式就是根据外参计算H矩阵。

单应性将两个平面之间的变换联系起来,这样就可以计算出从第二个平面视图转到第一个平面视图下相应相机位移,在已知内外参的情况下有

144cdd94353ffa14f63f15775cfba3cc.png

使用齐次坐标系表达式将三维世界点转转到相机坐标系下:

c57d79e8aeaf8f4fd2e9d7f55ac56156.png

使用矩阵乘法可以轻松地将一图像帧中表示的点转换为另一帧图像中:c1Mo是第一帧的位姿,c2Mo是第二帧的位姿。要将相机1中表示的三维点变换为相机2帧的坐标下,其变换公式为:

afb214f44e4bb611efe5ba6040a63a0b.png

以上公式对应的是:同一平面两个不同相机坐标系的单应矩阵。如果要同一平面计算出两个图像间的单应矩阵H,则需要内参,此时左边乘以K,右边乘以K的逆矩阵。

为了更好的理解,这里写了一个demo,并与上述的理论对应(注意这里是将第二帧转到第一帧的坐标系下)。

Mat cameraMatrix = (Mat_<double>(3, 3) << 700.0, 0.0, 320.0,
                       0.0, 700.0, 240.0,
                       0, 0, 1);
Mat R1 = c1Mo(Range(0, 3), Range(0, 3));
Mat R2 = c2Mo(Range(0, 3), Range(0, 3));
 //c1Mo * oMc2
Mat R_2to1 = R1*R2.t();//同一平面两个不同相机坐标系的单应矩阵
// [compute-homography]
Mat H = cameraMatrix * R_2to1 * cameraMatrix.inv();//同一平面计算出两个图像间的单应矩阵H
H /= H.at<double>(2, 2);//归一化
cout << "H:\n" << H << endl;

根据求解的单应矩阵实现两个视图的拼接实例显示如下

1c60b83aa218356559d64d8a48242fb4.png

拼接的结果如下:

warpPerspective(img2, img_stitch, H, Size(img2.cols * 2, img2.rows));
               Mat half = img_stitch(Rect(0, 0, img1.cols, img1.rows));

dce1edd8870e0ff588b7d081baaa3ba7.png

完整代码如下:

void basicPanoramaStitching(const string &img1Path, const string &img2Path)
{
 Mat img1 = imread("Blender_Suzanne1.jpg");
 Mat img2 = imread("Blender_Suzanne2.jpg");
 //! [camera-pose-from-Blender-at-location-1]
 Mat c1Mo = (Mat_<double>(4, 4) << 0.9659258723258972, 0.2588190734386444, 0.0, 1.5529145002365112,
         0.08852133899927139, -0.3303661346435547, -0.9396926164627075, -0.10281121730804443,
         -0.24321036040782928, 0.9076734185218811, -0.342020183801651, 6.130080699920654,
         0, 0, 0, 1);
 //! [camera-pose-from-Blender-at-location-1]
 //! [camera-pose-from-Blender-at-location-2]
 Mat c2Mo = (Mat_<double>(4, 4) << 0.9659258723258972, -0.2588190734386444, 0.0, -1.5529145002365112,
         -0.08852133899927139, -0.3303661346435547, -0.9396926164627075, -0.10281121730804443,
         0.24321036040782928, 0.9076734185218811, -0.342020183801651, 6.130080699920654,
         0, 0, 0, 1);
 //! [camera-pose-from-Blender-at-location-2]
 Mat cameraMatrix = (Mat_<double>(3, 3) << 700.0, 0.0, 320.0,
         0.0, 700.0, 240.0,
         0, 0, 1);
 Mat R1 = c1Mo(Range(0, 3), Range(0, 3));
 Mat R2 = c2Mo(Range(0, 3), Range(0, 3));
 //c1Mo * oMc2
 Mat R_2to1 = R1*R2.t();
 //! [compute-homography]
 Mat H = cameraMatrix * R_2to1 * cameraMatrix.inv();
 H /= H.at<double>(2, 2);
 cout << "H:\n" << H << endl;
 //! [compute-homography]
 //! [stitch]
 Mat img_stitch;
 warpPerspective(img2, img_stitch, H, Size(img2.cols * 2, img2.rows));
 Mat half = img_stitch(Rect(0, 0, img1.cols, img1.rows));
 img1.copyTo(half);
 //! [stitch]
 Mat img_compare;
 Mat img_space = Mat::zeros(Size(50, img1.rows), CV_8UC3);
 hconcat(img1, img_space, img_compare);
 hconcat(img_compare, img2, img_compare);
 imshow("Compare images", img_compare);
 imshow("Panorama stitching", img_stitch);
 waitKey();
        }

以上是根据外参实现了同一相机不同位姿采集的图像的拼接,其主要原理主要是根据外参计算出单应性矩阵,将第二帧采集的图像变换到第一帧视角下的结果,最终实现拼接。这里我想到了前视图转换俯视图的方法,同样也是变换视角的问题,只是这里的俯视图的虚拟相机的参数需要自己设置,有时间再更新。

 
 

好消息!

小白学视觉知识星球

开始面向外开放啦👇👇👇

 
 

e6de75fdc65f68f33365351b9e2d4daa.jpeg

下载1:OpenCV-Contrib扩展模块中文版教程

在「小白学视觉」公众号后台回复:扩展模块中文教程,即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。


下载2:Python视觉实战项目52讲
在「小白学视觉」公众号后台回复:Python视觉实战项目,即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。


下载3:OpenCV实战项目20讲
在「小白学视觉」公众号后台回复:OpenCV实战项目20讲,即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。


交流群

欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~
  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值