点击上方“小白学视觉”,选择加"星标"或“置顶”
重磅干货,第一时间送达
图像处理之理解Homography matrix(单应性矩阵)
单应性矩阵是投影几何中一个术语,本质上它是一个数学概念,但是在OpenCV中却是有几个函数与透视变换相关的函数,都用到了单应性矩阵的概念与知识。小编跟很多人一样,刚开始学习图像处理对单应性矩阵不是很了解,通过项目实践慢慢知道了一些这方面的知识和自己对它的理解,就跟大家分享一下。
单应性矩阵概念
这里说的单应性矩阵主要是指平面单应性矩阵,在三轴坐标中XYZ,Z=1这个有点类似于三维的齐次坐标。单应性矩阵主要用来解决两个问题,
一是表述真实世界中一个平面与对应它图像的透视变换
二是从通过透视变换实现图像从一种视图变换到另外一种视图
首先看一下在三维空间中任意两个平面
上图的中零点分别表示两个平面中任意两个点,a1、a2与b1、b2是这两点对应的两个方向上的线性向量。对于这两个平面直接的关系我们就可以通过这些点从而进一步确立两个平面直接的关系,而两个平面之间的关系用单应性矩阵来描述如下:
H表示单应性矩阵,定义了八个自由度。
这种关系被称为平面单应性。这个当中有一些数学知识推导,感兴趣的大家可以自己去看,我们最重要的是明白这个概念怎么来的。其次知道它的应用场景,下面我们就从应用层面和代码层面来说说单应性矩阵的应用。
- 用来解决拍照时候图像扭曲问题。这个在上一篇文章透视 变换中讲过,但是 当时没有说这个是单应性矩阵的应用。
- 此外还两个计算机图形学的应用场景分布是纹理渲染与计算平面阴影。
- 用来实现图像拼接时候解决对齐问题
应用案例
街拍的时候路两边有很多广告牌,如果在视频实时帧中获取到对应的广告牌位置,就可以获取广告牌的四个角坐标,然后通过准备好的内容,将广告牌内容替换,得到想要的虚拟广告牌效果,而这个过程中最重要的一步,可以通过计算单应性矩阵实现内容替换,演示效果如下:
时代广场的街拍
看到左侧的广告牌不,我们准好了一张图像,准备替换它的内容,准备的图像如下:
最终处理之后的效果如下:
实现代码如下:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
// load images
Mat src = imread("D:/vcprojects/images/times-square.jpg");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
// show images
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
Mat replaceImg = imread("D:/vcprojects/images/kgirls.png");
imshow("adv content", replaceImg);
// 定义两个平面上四个角坐标
vector<Point> src_corners(4);
vector<Point> dst_corners(4);
// 原图像平面四点坐标
src_corners[0] = Point(0, 0);
src_corners[1] = Point(replaceImg.cols, 0);
src_corners[2] = Point(0, replaceImg.rows);
src_corners[3] = Point(replaceImg.cols, replaceImg.rows);
// 目标平面四个角坐标
dst_corners[0] = Point(70, 131);
dst_corners[1] = Point(168,216);
dst_corners[2] = Point(21, 199);
dst_corners[3] = Point(148, 267);
// 计算单应性矩阵与透视变换
Mat h = findHomography(src_corners, dst_corners);
Mat output_img;
warpPerspective(replaceImg, output_img, h, src.size());
// create mask
Mat m1 = Mat::zeros(replaceImg.size(), CV_8UC1);
m1 = Scalar(255);
Mat mask_output;
warpPerspective(m1, mask_output, h, src.size());
imshow("Mask Result", mask_output);
// use mask
Mat result1;
add(output_img, output_img, result1, mask_output);
Mat result2;
bitwise_not(mask_output, mask_output);
add(src, result1, result2, mask_output);
// put them together
Mat result;
add(result1, result2, result);
imshow("Final Result", result);
imwrite("D:/vcprojects/images/result.png", result);
waitKey(0);
return 0;
}
代码中的注释已经很详细啦,最近比较忙,文章发的不多,感谢大家支持!
好消息!
小白学视觉知识星球
开始面向外开放啦👇👇👇
下载1:OpenCV-Contrib扩展模块中文版教程
在「小白学视觉」公众号后台回复:扩展模块中文教程,即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。
下载2:Python视觉实战项目52讲
在「小白学视觉」公众号后台回复:Python视觉实战项目,即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。
下载3:OpenCV实战项目20讲
在「小白学视觉」公众号后台回复:OpenCV实战项目20讲,即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。
交流群
欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~