概述
卷积算法使用提供的 2D 核对输入图像执行 2D 卷积操作。当核不可分离且其尺寸小于 5x5 时,此方法非常有用。在其他情况下,通常最好使用可分离卷积算法,因为它速度更快。
输入 | 核 | 输出 |
| \[ \begin{bmatrix} 1 & 0 & -1 \\ 0 & 0 & 0 \\ -1 & 0 & 1 \end{bmatrix} \]
| |
实现
离散 2D 卷积是使用以下离散函数实现的
\[ I'[x,y] = \sum_{m=0}^{k_h} \sum_{n=0}^{k_w} K[m,n] \times I[x-(n-\lfloor k_w/2 \rfloor), y-(m-\lfloor k_h/2 \rfloor) ] \]
其中
- \(I\) 是输入图像。
- \(I'\) 是结果图像。
- \(K\) 是卷积核。
- \(k_w,k_h\) 分别是核的宽度和高度。
- 注意
- 大多数计算机视觉库期望在调用其卷积函数之前反转内核。VPI 则不然,我们实现的是实际的卷积,而不是互相关。当然,如果内核是对称的,则这无关紧要。
C API 函数
有关实现该算法的限制、约束和后端列表,请查阅以下函数的参考文档
用法
语言
- 导入 VPI 模块
- 定义一个 3x3 卷积核以执行边缘检测。
kernel = [[ 1, 0, -1],
[ 0, 0, 0],
[-1, 0, 1]]
- 使用 CPU 后端和给定的核,在输入图像上运行卷积滤波器。输入和输出均为 VPI 图像。
with vpi.Backend.CUDA
output = input.convolution(kernel, border=vpi.Border.ZERO)
- 初始化阶段
- 包含定义所需函数和结构的头文件。
- 定义输入图像对象。
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 边缘检测器。
float kernel[3 * 3] = { 1, 0,-1,
0, 0, 0,
-1, 0, 1};
- 将算法提交到流,传递内核和其他参数。它将由 CPU 后端执行。
VPIStatus vpiSubmitConvolution(VPIStream stream, uint64_t backend, VPIImage input, VPIImage output, const float *kernelData, int32_t kernelWidth, int32_t kernelHeight, VPIBorderExtension border)
在图像上运行通用 2D 卷积。
@ VPI_BORDER_ZERO
图像外部的所有像素均被视为零。
- (可选)等待直到处理完成。
VPIStatus vpiStreamSync(VPIStream stream)
阻塞调用线程,直到此流队列中的所有提交命令完成(队列为空)。
- 清理阶段
- 释放流以及输入和输出图像所持有的资源。
void vpiImageDestroy(VPIImage img)
销毁图像实例。
void vpiStreamDestroy(VPIStream stream)
销毁流实例并释放所有硬件资源。
有关完整示例,请参阅图像卷积。
有关更多信息,请参阅VPI - 视觉编程接口的“C API 参考”部分中的卷积。
性能
有关如何使用下表中的性能信息,请参阅算法性能表。
在比较测量结果之前,请查阅比较算法运行时间。
有关性能基准测试方式的更多信息,请参阅性能基准。
-