使用OpenCV透视变换技术实现坐标变换实践

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

1. 概述

1.1. 需求

在局部空间无GPS定位视频监控过程中把视频识别到物体位置投射到空间平面坐标系中获取物体在局部空间的平面坐标。

1.2. 解决方案

使用图像透视变换技术。

1.3. 透视变换概念

透视变换是指利用透视中心、像点、目标点三点共线的条件按透视旋转定律使承影面(透视面)绕迹线(透视轴)旋转某一角度破坏原有的投影光线束仍能保持承影面上投影几何图形不变的变换。简而言之就是将一个平面通过一个投影矩阵投影到指定平面上。

透视变换Perspective Transform和仿射变换Affine Transform在图像还原、局部变化处理方面有重要意义。通常在2D平面中仿射变换的应用比较多在3D平面中透视变换占领地位较高。两种变换原理相似结果也相似可以针对不同场合选择适合方法。

在这里插入图片描述

2. 透视变换原理

透视变换
( x y z ) = ( a 11 a 12 a 13 a 21 a 22 a 23 a 31 a 32 a 33 ) ( u v 1 ) \begin{pmatrix} x\\ y\\ z \end{pmatrix} = \begin{pmatrix} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ a_{31} & a_{32} & a_{33} \end{pmatrix} \begin{pmatrix} u\\ v\\ 1 \end{pmatrix} xyz = a11a21a31a12a22a32a13a23a33 uv1
上述公式中 u , v u,v u,v代表原始图像坐标 x , y x,y x,y为经过透视变换的图片坐标其中变换矩阵为 3 × 3 3\times3 3×3形式。进而可以得到

x = a 11 u + a 12 v + a 13 x=a_{11}u + a_{12} v+ a_{13} x=a11u+a12v+a13
y = a 21 u + a 22 v + a 23 y=a_{21}u + a_{22} v+ a_{23} y=a21u+a22v+a23
z = a 31 u + a 32 v + a 33 z=a_{31}u + a_{32} v + a_{33} z=a31u+a32v+a33

在原图上取4点坐标与新图对应相当于列出方程组解出变换矩阵。
通过变换矩阵在输入原图像坐标的情况下可以直接求解新图平面坐标。
x ′ = x z = a 11 u + a 12 v + a 13 a 31 u + a 32 v + a 33 x' = \frac{x}{z} = \frac{a_{11}u + a_{12} v+ a_{13}}{a_{31}u + a_{32} v + a_{33}} x=zx=a31u+a32v+a33a11u+a12v+a13
y ′ = y z = a 21 u + a 22 v + a 23 a 31 u + a 32 v + a 33 y' = \frac{y}{z} = \frac{a_{21}u + a_{22} v+ a_{23}}{a_{31}u + a_{32} v + a_{33}} y=zy=a31u+a32v+a33a21u+a22v+a23

其中 ( x , y ) (x,y) (x,y)是原图坐标 ( x ’ , y ’ ) (x’,y’) (x,y)是变换后的坐标 a 11 , a 12 , a 21 , a 22 , a 31 , a 32 a_{11},a_{12},a_{21},a_{22},a_{31},a_{32} a11,a12,a21,a22,a31,a32为旋转量 a 13 , a 23 , a 33 a_{13},a_{23},a_{33} a13,a23,a33为平移量。因为透视变换是非线性的所以不能齐次性表示透视变换矩阵为 3 × 3 3\times3 3×3

透视变换的方程组有8个未知数所以要求解就需要找到4组映射点四个点就刚好确定了一个三维空间。

3. OpenCV透视变换

3.1. 关于OpenCV透视变换函数

投影变换Projective mapping也称透视变换Perspective transformation是建立两平面场之间的对应关系 将图片投影到一个新的视平面Viewing plane。

OpenCV 提供了 cv2.warpPerspective 函数实现投影变换的操作。

函数说明

cv2.getPerspectiveTransform(src, dst[,solveMethod]) → MP
cv2.warpPerspective(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]]) → dst
  • 函数cv2.getPerspectiveTransform 根据图像中不共线的 4 个点在变换前后的对应位置求得 ( 3 × 3 3\times3 3×3) 变换矩阵
  • 函数cv2.warpPerspective 使用该 ( 3 × 3 3\times3 3×3) 变换矩阵即可求出变换后的图像。标量进行加法运算。

参数说明

  • src变换前图像四边形顶点坐标
  • dst变换后图像四边形顶点坐标
  • solveMethod矩阵分解方法传递给 cv2.solve 求解变换矩阵 MP
  • cv2.DECOMP_LU选择最优轴的高斯消去法默认方法
  • cv2.DECOMP_SVD奇异值分解SVD方法
  • cv2.DECOMP_EIG特征值分解方法src 必须对称
  • cv2.DECOMP_QRQR正交三角分解
  • cv2.DECOMP_CHOLESKYCholesky LLT 分解
  • MP透视变换矩阵3行3列
  • dsize 输出图像的大小二元元组 (width, height)
  • dst变换操作的输出图像可选项
  • flags插值方法整型int可选项
  • cv2.INTER_LINEAR线性插值默认选项
  • cv2.INTER_NEAREST最近邻插值
  • cv2.INTER_AREA区域插值
  • cv2.INTER_CUBIC三次样条插值
  • cv2.INTER_LANCZOS4Lanczos 插值
  • borderMode边界像素方法整型int可选项默认值为 cv2.BORDER_REFLECT
  • borderValue边界填充模式可选项默认值为 0黑色填充
  • 返回值dst透视变换操作的输出图像ndarray 多维数组

3.2. 透视变换实践设计

为了便于坐标转换先设定图片像素为坐标第一步由图1的标准图经透视变换为图2相当于3维空间中某个视角获取到的图像第二步再由图2相当于实际情况下视频某个空间视角获得的图像复原恢复到图3过程中产生变换矩阵以此计算新的坐标。
在这里插入图片描述

3.2.1. 透视变换图像

此部分代码为由图1变换到图2。

import cv2
import numpy as np

img = cv2.imread("A1.png")
height, width = img.shape[:2]
# print(height, width)

# 变换前的四个点
srcArr = np.float32([[0, 0], [515, 0], [0, 613], [515, 613]])
# 变换后的四个点
dstArr = np.float32([[100, 413], [415, 413], [0, 613], [515, 613]])
# 获取变换矩阵
MM = cv2.getPerspectiveTransform(srcArr, dstArr)
dst = cv2.warpPerspective(img, MM, (width, height))

# 输出保存变换后的图像
cv2.imwrite("pe.png", dst)

3.2.2. 透视变换复原图像及获取像素坐标

import cv2
import numpy as np

img = cv2.imread("pe.png")
height, width = img.shape[:2]
# print(height, width)

# 变换前的四个点
srcArr = np.float32([[100, 413], [415, 413], [0, 613], [515, 613]])
# 变换后的四个点
dstArr = np.float32([[0, 0], [515, 0], [0, 613], [515, 613]])

# 求解获取变换矩阵
MM = cv2.getPerspectiveTransform(srcArr, dstArr)
print(MM)
# 输出复原图像
dst = cv2.warpPerspective(img, MM, (width, height))
cv2.imwrite("A2.png", dst)

# 自定义坐标转换函数
def cvt_pos(u , v, mat):
    x = (mat[0][0]*u+mat[0][1]*v+mat[0][2])/(mat[2][0]*u+mat[2][1]*v+mat[2][2])
    y = (mat[1][0]*u+mat[1][1]*v+mat[1][2])/(mat[2][0]*u+mat[2][1]*v+mat[2][2])
    return (int(x), int(y))
 
# 调用函数
u, v = 100,413
x,y = cvt_pos(u, v, MM)
print(x,y)

其中变换矩阵MM结果为
在这里插入图片描述
最后返回像素坐标 ( x , y ) = ( 0 , 0 ) (x, y) = (0, 0) (x,y)=(0,0)

4. 像素转换到私有坐标系

在实际场景下经透视复原的图像像素坐标与实际私有坐标成比例变换获取比例的方法如下。
在这里插入图片描述
首先选取变换的基准在图像上选取四个a,b,c,d点中其中两个邻居的点a,b作为基准并且这两个点的在图像变换或求解变换矩阵时像素坐标不变其中
L1 = L2 h1 = h2

接着计算获取ab两点间像素距离与实际平台私有坐标中ab两点的距离其中
k = D ′ D k = \frac{D'}{D} k=DD
式中的 D ′ D' D为图像中距离 D D D为私有坐标系平面上的距离。

则私有坐标系平面上坐标为 x , y = k x ′ , k y ′ x, y = kx', ky' x,y=kx,ky

5. 小结

虽然此方案理论及实验可行但是工程上实施将比较麻烦主要涉及到每个视频点的4点定位以及实际坐标测定。

模拟路况中间图为”视频角度的图片“还原投射图的效果如右侧的图片与左侧原图比较则图中上面的车明显变虚。
在这里插入图片描述
假设标准原图为496、887像素实际地面宽度为992cm相当于每个像素为2cm。求解变换矩阵为
在这里插入图片描述
选取中间黄色车左前角像素坐标为261655还原投射图像素坐标为270461对应实际地面私有坐标为540922cm。

欢迎讨论。

参考

[1]. 电子小呆比. Opencv-python 求原坐标点透视变换后对应坐标点. . CSDN博客. 2022.04
[2]. 小凡. 图像处理的仿射变换与透视变换. 知乎. 2019.04
[3]. 泠山. 仿射变换和透视变换. CSDN博客. 2022.10
[4]. 秋山丶雪绪. Python OpenCV 单目相机标定、坐标转换相关代码包括鱼眼相机. CSDN博客. 2022.12
[5]. 王吉吉丫. 图像矫正–python_OpenCV实现透视变换. CSDN博客. 2021.09
[6]. YouCans. 【OpenCV 例程200篇】34. 图像的投影变换cv2.getPerspectiveTransform. CSDN博客. 2022.07
[7]. 草原上唱山歌. 几何变换中的仿射变换和透视变换的原理python. CSDN博客. 2022.03
[8]. 一马归一码. Python 计算机视觉五特别篇 —— 透视变换. CSDN博客. 2022.04

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6