[OpenCV实战]18 Opencv中的单应性矩阵Homography
目录
《圣经》记载,当时人类联合起来兴建希望能通往天堂的高塔;为了阻止人类的计划,上帝让人类说不同的语言,使人类相互之间不能沟通,计划因此失败。
像“Homography”这样的术语经常提醒我,我们仍然在与沟通斗争。Homography(单应性)是一个简单的概念,却有一个奇怪的名字!
1 介绍
1.1 什么是Homography
考虑图1所示的同一个平面(比如书皮)的两幅图像。红点表示两幅图像中相同的物理坐标点。在计算机视觉术语中,我们称之为对应点。

Homography就是将一张图像上的点映射到另一张图像上对应点的3x3变换矩阵。因此该矩阵我们可以表示为:

让我们考虑一组对应点,
位于第一张图像和
位于第二张图像中。然后,Homography以下列方式映射它们:

1.2 使用Homography进行图像对齐
只要它们位于现实世界中的同一平面上,上述等式对于所有对应点都是正确的。换句话说,您可以将单应性应用于第一张图像,第一张图像中的书籍将与第二张图像中的书籍对齐!见下图。那么对于不在此平面上的点呢?这时再应用 Homography 就无法再对齐到对应点了。比如下图的桌子,地板。对于这种图像中有多个平面的情况,我们就需要针对每一个平面使用单独的Homography进行对齐。

1.3 Homography的应用-全景拼接
在上一节中,我们了解到如果已知两个图像之间的Homography,我们可以将一个图像映射到另一个图像上。但是,有一个很大的问题。图像必须位于同一个平面(书的顶部),并且只有该平面部分才会正确对齐。事实证明,如果您拍摄任何不包括一个平面的场景,然后通过旋转相机拍摄第二张照片,这两张图片就可以通过Homography相关联!您刚刚拍摄的完全随意的3D场景的两个图像可以用Homography相关联。这两个图像将共享一些可以对齐和拼接的公共区域,并且可以获得两个图像的全景图。然而这只是很粗糙的全景拼接,但基本原则是使用Homography和智能拼接。
2 Homography的计算
要计算两个图像之间的单应性,您需要知道两个图像之间至少有4个点对应关系。如果你有超过4个对应点,那就更好了。原因在于对于 H 矩阵,一般设 H22 为 1, 所以 H 有 8 个未知参数。至少需要8 个等式才能求解。而一组对应点可以提供 2 个等式,所以,至少需要 4 组对应点(任意三点不共线)来求得 H。OpenCV将稳健地估计最适合所有对应点的单应性。通常,这些点对应是通过匹配图像之间的SIFT或SURF等特征自动找到的,但在这篇文章中我们只是提前设定特征点。代码如下:
C++代码:
// OpenCV_Homography.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
// Read source image 原图
Mat im_src = imread("./image/book2.jpg");
// Four corners of the book in source image 4个角点
vector<Point2f> pts_src;
pts_src.push_back(Point2f(141, 131));
pts_src.push_back(Point2f(480, 159));
pts_src.push_back(Point2f(493, 630));
pts_src.push_back(Point2f(64, 601));
// Read destination image.目标图
Mat im_dst = imread("./image/book1.jpg");
// Four corners of the book in destination image. 4个对应点
vector<Point2f> pts_dst;
pts_dst.push_back(Point2f(318, 256));
pts_dst.push_back(Point2f(534, 372));
pts_dst.push_back(Point2f(316, 670));
pts_dst.push_back(Point2f(73, 473));
// Calculate Homography 计算Homography需要至少4组对应点.
// pts_src : 源图像点坐标,pts_dst : 结果图像坐标
Mat h = findHomography(pts_src, pts_dst);
// Output image
Mat im_out;
// Warp source image to destination based on homography 仿射变换
warpPerspective(im_src, im_out, h, im_dst.size());
// Display images
imshow("Source Image", im_src);
imshow("Destination Image", im_dst);
imshow("Warped Source Image", im_out);
waitKey(0);
return 0;
}
python代码:
#!/usr/bin/env python
import cv2
import numpy as np
if __name__ == '__main__' :
# Read source image.
im_src = cv2.imread('./image/book2.jpg')
# Four corners of the book in source image
pts_src = np.array([[141, 131], [480, 159], [493, 630],[64, 601]])
# Read destination image.
im_dst = cv2.imread('./image/book1.jpg')
# Four corners of the book in destination image.
pts_dst = np.array([[318, 256],[534, 372],[316, 670],[73, 473]])
# Calculate Homography
h, status = cv2.findHomography(pts_src, pts_dst)
# Warp source image to destination based on homography
im_out = cv2.warpPerspective(im_src, h, (im_dst.shape[1],im_dst.shape[0]))
# Display images
cv2.imshow("Source Image", im_src)
cv2.imshow("Destination Image", im_dst)
cv2.imshow("Warped Source Image", im_out)
cv2.waitKey(0)
3 总结
举个例子,例如虚拟广告牌,把下图1替换下图2的广告,得到下图3



实际步骤很简单
1 用选择上图2时代广场上广告屏的 4 个顶点,作为 pts_dst;
2 选取欲嵌入的图像的 4 个顶点,假设图像尺寸 W x H, 那么 四个顶点就是 (0,0), (0, W-1), (H - 1, 0), (H - 1, W - 1)。作为pts_src 类似下面代码,这样pts_src 和pts_dst就是一组对应点;
// Create a vector of points.
vector<Point2f> pts_src;
pts_src.push_back(Point2f(0,0));
pts_src.push_back(Point2f(size.width - 1, 0));
pts_src.push_back(Point2f(size.width - 1, size.height -1));
pts_src.push_back(Point2f(0, size.height - 1 ));
3 使用 pts_dst 和 pts_src 计算 Homography;运用opencv中的findHomography就行了
// Calculate Homography 计算Homography需要至少4组对应点.
// pts_src : 源图像点坐标,pts_dst : 结果图像坐标
Mat h = findHomography(pts_src, pts_dst);
4 对 源图像应用计算得到的 Homography 从而 混合到 目标图像上;然后计算仿射变化。
// Warp source image
warpPerspective(im_src, im_temp, h, im_temp.size());
由于这个例子代码简单,具体代码就不贴出来了。所有代码见:
https://github.com/luohenyueji/OpenCV-Practical-Exercise
4 参考
https://www.learnopencv.com/homography-examples-using-opencv-python-c/
https://blog.csdn.net/baishuo8/article/details/80777995
[OpenCV实战]18 Opencv中的单应性矩阵Homography的更多相关文章
- 机器学习进阶-案例实战-图像全景拼接-图像全景拼接(RANSCA) 1.sift.detectAndComputer(获得sift图像关键点) 2.cv2.findHomography(计算单应性矩阵H) 3.cv2.warpPerspective(获得单应性变化后的图像) 4.cv2.line(对关键点位置进行连线画图)
1. sift.detectAndComputer(gray, None) # 计算出图像的关键点和sift特征向量 参数说明:gray表示输入的图片 2.cv2.findHomography(kp ...
- 相机标定 和 单应性矩阵H
求解相机参数的过程就称之为相机标定. 1.相机模型中的四个平面坐标系: 1.1图像像素坐标系(u,v) 以像素为单位,是以图像的左上方为原点的图像坐标系: 1.2图像物理坐标系(也叫像平面坐标系)(x ...
- OpenCV仿射变换+投射变换+单应性矩阵
本来想用单应性求解小规模运动的物体的位移,但是后来发现即使是很微小的位移也会带来超级大的误差甚至错误求解,看起来这个方法各种行不通,还是要匹配知道深度了以后才能从三维仿射变换来入手了,纠结~ esti ...
- opencv 仿射变换 投射变换, 单应性矩阵
仿射 estimateRigidTransform():计算多个二维点对或者图像之间的最优仿射变换矩阵 (2行x3列),H可以是部分自由度,比如各向一致的切变. getAffineTransform( ...
- OpenCV 之 平面单应性
上篇 OpenCV 之 图象几何变换 介绍了等距.相似和仿射变换,本篇侧重投影变换的平面单应性.OpenCV相关函数.应用实例等. 1 投影变换 1.1 平面单应性 投影变换 (Projectiv ...
- 单应性(homography)变换的推导
矩阵的一个重要作用是将空间中的点变换到另一个空间中.这个作用在国内的<线性代数>教学中基本没有介绍.要能形像地理解这一作用,比较直观的方法就是图像变换,图像变换的方法很多,单应性变换是其中 ...
- python opencv3 FLANN单应性匹配
git:https://github.com/linyi0604/Computer-Vision 匹配准确率非常高. 单应性指的是图像在投影发生了 畸变后仍然能够有较高的检测和匹配准确率 # codi ...
- 【Computer Vision】图像单应性变换/投影/仿射/透视
一.基础概念 1. projective transformation = homography = collineation. 2. 齐次坐标:使用N+1维坐标来表示N维坐标,例如在2D笛卡尔坐标 ...
- [OpenCV实战]13 OpenCV中使用Mask R-CNN进行对象检测和实例分割
目录 1 背景介绍 1.1 什么是图像分割和实例分割 1.2 Mask-RCNN原理 2 Mask-RCNN在OpenCV中的使用 2.1 模型下载 2.2 模型初始化 2.3 模型加载 2.4 输出 ...
随机推荐
- C# 基础 之:Task 用法
参考来源:https://www.cnblogs.com/zhaoshujie/p/11082753.html 他介绍的可以说是非常详细,附带Demo例子讲解 1.入门 Task看起来像一个Threa ...
- 1.ElasticSearch系列之集群部署
第一步:安装JDK JDK要求jdk1.8+,不安装也可以,ES自带JDK 第二步:系统配置 2.1 禁用交换区 sudo swapoff -a 2.2 开最大文件数的限制 编辑文件 /etc/sec ...
- 后端框架学习-----mybatis(4)
文章目录 4.解决属性名和字段名不一致的问题 4.解决属性名和字段名不一致的问题 1.问题.数据库字段名和属性名不一致,导致查出的数据部分为空 2.resultMap(用于解决数据库表中的字段和属性) ...
- JUC(2)使用condition实现精准通知唤醒
package com.orderPC; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks. ...
- 齐博x1更新了 提供一个部分用户期待已久的功能,修改主题后变为待审
如下图所示,你可以设置哪些用户组修改主题后,就会把原来已审核通过的主题,变为未审核.适合所有频道.
- 11.pygame飞机大战游戏整体代码
主程序 # -*- coding: utf-8 -*- # @Time: 2022/5/20 22:26 # @Author: LiQi # @Describe: 主程序 import pygame ...
- awk变量
awk变量 awk参数 参数 解释 -F 指定分割字段符 -v 定义或修改一个awk内部的变量 -f 从脚本文件中读取awk命令 对于awk而言,变量分为 内置变量 自定义变量 内置变量 解释 FS ...
- Oracle中新建数据表的两种方法
首发微信公众号:SQL数据库运维 原文链接:https://mp.weixin.qq.com/s?__biz=MzI1NTQyNzg3MQ==&mid=2247485212&idx=1 ...
- C#之GCHandle
转载 略谈GCHandle C# - Marshal.StructureToPtr方法简介 Marshal类 两个方法StructureToPtr和PtrToStructure实现序列化 字节 数组 ...
- Scala- Cannot run program "powershell.exe": CreateProcess error=5, 拒绝访问
安装scala后,按照官网的helloworld教程学习执行 sbt new scala/hello-world.g8 的时候,出现下图错误. 解决方案:关闭360