概述
透视变换算法允许校正因相机相对于被拍摄物体平面的未对准而引起的透视畸变。例如,当相机指向挂在墙上的画框,但从下方向上看时,就会发生这种情况。生成的图像的相对边将不再平行。
如果已知相机相对于画框的位置、倾斜度和摇摄角度,则可以推导出 3x3 透视变换,这将扭曲图像,以使画框的相对边彼此平行,如下所示。
输入 | 变换 | 已校正 |
| \begin{bmatrix} 0.5386 & 0.1419 & -74\\ -0.4399 & 0.8662 & 291.5\\ -0.0005 & 0.0003 & 1 \end{bmatrix}
| |
实现
透视变换矩阵将源图像映射到目标图像。变换可以用下面的公式进行数学描述
\begin{align*} \mathsf{y} = \mathsf{H}_p \mathsf{x} = \begin{bmatrix} \mathsf{A} & \mathsf{t} \\ \mathsf{p}^\intercal & p \end{bmatrix} \mathsf{x} \end{align*}
或,展开矩阵和向量
\begin{align*} \begin{bmatrix} y_u \\ y_v \\ y_w \end{bmatrix} &= \begin{bmatrix} a_{11} & a_{12} & t_u \\ a_{21} & a_{22} & t_v \\ p_0 & p_1 & p \end{bmatrix} \begin{bmatrix}x_u \\ x_v \\ 1 \end{bmatrix} \\ \end{align*}
在这些公式中,
- \(\mathsf{H}_p\) 是投影矩阵
- \(\mathsf{x}\) 是源图像中的齐次坐标。
- \(\mathsf{y}\) 是目标图像中的齐次坐标。
- \(\mathsf{A}\) 是一个 2x2 非奇异矩阵,带有线性分量。
- \(\mathsf{t}\) 是平移分量。
- \(\mathsf{p},p\) 是投影分量。\(p\) 通常为 1。
\(\mathsf{y}\) 在输出图像上的投影由下式给出
\begin{align*} \begin{bmatrix} y'_u \\ y'_v \end{bmatrix} &= \begin{bmatrix} y_u/y_w \\ y_v/y_w \end{bmatrix} \end{align*}
这些公式通过执行反向操作来有效实现,即,对目标像素应用逆变换,并从源图像中采样相应的值。如果传递了标志 VPI_WARP_INVERSE,则该操作将假定用户的矩阵已反转,并且不会再次尝试反转它。如果矩阵必须由 VPI 反转,则传递零。
\begin{align*} \mathsf{H}_p^{-1} &= \begin{bmatrix}h_{11} & h_{12} & h_{13} \\ h_{21} & h_{22} & h_{23} \\ h_{31} & h_{32} & h_{33}\end{bmatrix} \\ \mathrm{dst}(u,v) &= \mathrm{src}\left(\frac{h_{11}u+h_{12}v+h_{13}}{h_{31}u+h_{32}v+h_{33}},\frac{h_{21}u+h_{22}v+h_{23}}{h_{31}u+h_{32}v+h_{33}}\right), \forall (u,v) \in \mathrm{dst} \end{align*}
C API 函数
有关实现该算法的限制、约束和后端列表,请查阅以下函数的参考文档
用法
语言
- 导入 VPI 模块
- 定义要应用的 3x3 透视变换。
xform = [[ 0.5386, 0.1419, -74 ],
[ -0.4399, 0.8662, 291.5 ],
[ -0.0005, 0.0003, 1 ]]
- 在 VPI 图像输入中应用透视变换,将结果返回到新的 VPI 图像中。
with vpi.Backend.CUDA
output = input.perspwarp(xform)
- 初始化阶段
- 包含定义透视变换函数的头文件。
- 定义输入图像对象。
struct VPIImageImpl * VPIImage
图像句柄。
- 创建输出图像。在本例中,输入和输出具有相同的尺寸,但它们也可能不同。但是,图像格式必须匹配。
int32_t w, h;
VPIStatus vpiImageGetFormat(VPIImage img, VPIImageFormat *format)
获取图像格式。
VPIStatus vpiImageCreate(int32_t width, int32_t height, VPIImageFormat fmt, uint64_t flags, VPIImage *img)
使用指定的标志创建空的图像实例。
VPIStatus vpiImageGetSize(VPIImage img, int32_t *width, int32_t *height)
以像素为单位获取图像尺寸。
- 创建将在其中提交算法以执行的流。
struct VPIStreamImpl * VPIStream
流的句柄。
VPIStatus vpiStreamCreate(uint64_t flags, VPIStream *stream)
创建流实例。
- 处理阶段
- 定义要应用的 3x3 透视变换。请注意,变换在每次调用中不必相同。
{
{ 0.5386, 0.1419, -74 },
{-0.4399, 0.8662, 291.5},
{-0.0005, 0.0003, 1 }
};
float VPIPerspectiveTransform[3][3]
表示 2D 透视变换。
- 将算法连同所有参数一起提交到流。该算法将由 CPU 后端执行。
VPIStatus vpiSubmitPerspectiveWarp(VPIStream stream, uint64_t backend, VPIImage input, const VPIPerspectiveTransform xform, VPIImage output, const VPIWarpGrid *grid, VPIInterpolationType interp, VPIBorderExtension border, uint64_t flags)
向流提交透视变换操作。
@ VPI_BORDER_ZERO
图像外部的所有像素均被视为零。
- 可选地,等待直到处理完成。
VPIStatus vpiStreamSync(VPIStream stream)
阻塞调用线程,直到此流队列中的所有提交命令都完成(队列为空)。
- 清理阶段
- 释放流、输入和输出图像所持有的资源。
void vpiImageDestroy(VPIImage img)
销毁图像实例。
void vpiStreamDestroy(VPIStream stream)
销毁流实例并释放所有硬件资源。
有关更多信息,请参阅 VPI - Vision Programming Interface 的“C API 参考”部分中的 透视变换。
性能
有关如何使用下表性能表的信息,请参阅 算法性能表。
在比较测量结果之前,请查阅 比较算法运行时间。
有关性能基准测试方式的更多信息,请参阅 性能基准。
-