VPI - 视觉编程接口

3.2 版本

C API

C API 提供了对所有 VPI 功能的底层访问。它使开发者能够更好地控制资源管理和管道构建,从而在时间和内存消耗方面实现更高效的处理。

要求

  • Ubuntu 18.04 或 20.04
  • c++ 编译器 (已使用 g++-8.2 测试)
  • cmake >= 3.8,用于构建项目
  • OpenCV >= 3.2,用于图像输入/输出例程

在终端中,运行以下命令来安装所需的软件包

apt-get install g++ cmake libopencv-dev

创建 CMake 项目

创建 cmake 项目以构建应用程序,如下所示。

1 cmake_minimum_required(VERSION 3.5)
2 
3 project(vpi_blur)
4 
5 # 这指示 cmake 查找系统上安装的最新
6 # vpi 实例。
7 find_package(vpi REQUIRED)
8 find_package(OpenCV REQUIRED)
9 
10 # 创建模糊可执行目标
11 add_executable(vpi_blur main.cpp)
12 
13 # 它使用 vpi 和 opencv。CMake 将自动
14 # 设置正确的头文件和库文件目录,
15 # 并使 hello_work 链接到这些库。
16 target_link_libraries(vpi_blur vpi opencv_core opencv_imgproc opencv_imgcodecs)

请注意,cmake 会自动为可执行文件设置 VPI 头文件和库路径。无需手动定义它们。

编写图像模糊应用程序

将以下代码复制到名为 main.cpp 的文件中。为了简洁起见,特意省略了错误检查。有关包含适当错误处理的完整应用程序,请参阅 2D 卷积示例。注释解释了它的工作原理。

30 #include <opencv2/core/version.hpp>
31 #include <opencv2/imgproc/imgproc.hpp>
32 #if CV_MAJOR_VERSION >= 3
33 # include <opencv2/imgcodecs.hpp>
34 #else
35 # include <opencv2/highgui/highgui.hpp>
36 #endif
37 
38 #include <iostream>
39 
40 // 所有 vpi 头文件都在 vpi/ 目录下
41 #include <vpi/OpenCVInterop.hpp>
42 
43 #include <vpi/Image.h>
44 #include <vpi/Stream.h>
45 
46 // 我们需要的算法:
47 // - 图像格式转换
48 // - 用于模糊的盒式滤波器
49 #include <vpi/algo/BoxFilter.h>
51 
52 int main(int argc, char *argv[])
53 {
54  if (argc != 2)
55  {
56  std::cerr << "必须传递要模糊的输入图像" << std::endl;
57  return 1;
58  }
59 
60  // 阶段 1:初始化 ---------------------------------
61 
62  // 首先加载输入图像
63  cv::Mat cvImage = cv::imread(argv[1]);
64  if (cvImage.data == NULL)
65  {
66  std::cerr << "无法打开输入图像" << std::endl;
67  return 2;
68  }
69 
70  // 现在创建流。传递 0 允许提交给它的算法在任何可用的后端中运行。
71  // 在任何可用的后端中。
72  VPIStream stream;
73  vpiStreamCreate(0, &stream);
74 
75  // 现在将加载的图像包装到 VPIImage 对象中,以供 VPI 使用。
76  // VPI 将根据 cvImage 拥有的通道数推断图像类型。
77  // 在这种情况下,对于 OpenCV,它有 3 个通道,它将推断为 BGR8。
78  VPIImage image;
79  vpiImageCreateWrapperOpenCVMat(cvImage, 0, &image);
80 
81  // 由于我们想要处理输入图像的灰度版本,让我们创建一个
82  // 将存储它的图像。
83  VPIImage imageGray;
84  vpiImageCreate(cvImage.cols, cvImage.rows, VPI_IMAGE_FORMAT_U8, 0, &imageGray);
85 
86  // 现在创建输出图像,单通道无符号 8 位通道。图像生命周期由
87  // VPI 管理。
88  VPIImage blurred;
89  vpiImageCreate(cvImage.cols, cvImage.rows, VPI_IMAGE_FORMAT_U8, 0, &blurred);
90 
91  // 阶段 2:主要处理 --------------------------------------
92 
93  // 预处理输入,将其从 BGR8 转换为灰度
94  vpiSubmitConvertImageFormat(stream, VPI_BACKEND_CUDA, image, imageGray, NULL);
95 
96  // 提交算法任务以进行处理,以及输入和输出
97  // 参数是:
98  // 1. 算法将在其上运行的流
99  // 2. 将执行它的硬件后端。这里指定了 CUDA,但它可以是 CPU 或
100  // PVA(在 Jetson Xavier 设备上)。无需进一步更改程序即可使其在
101  // 不同的硬件上执行。
102  // 3. 要模糊的输入图像。
103  // 4. 包含结果的输出图像。
104  // 5 和 6. 盒式滤波器大小,在本例中为 5x5
105  // 7. 当算法尝试对图像边界外的像素进行采样时的边界扩展。
106  // VPI_BORDER_ZERO 将将所有此类像素视为 0。
107  vpiSubmitBoxFilter(stream, VPI_BACKEND_CUDA, imageGray, blurred, 5, 5, VPI_BORDER_ZERO);
108 
109  // 阻塞当前线程,直到流完成提交给它的所有任务为止。
110  vpiStreamSync(stream);
111 
112  // 最后检索输出图像内容并将其输出到磁盘
113 
114  // 锁定输出图像以从 cpu 内存中检索其数据
115  VPIImageData outData;
117 
118  // 从检索到的数据构造 cv::Mat。
119  cv::Mat cvOut;
120  vpiImageDataExportOpenCVMat(outData, &cvOut);
121 
122  // 现在将其写入磁盘
123  imwrite("tutorial_blurred.png", cvOut);
124 
125  // 完成处理输出图像,别忘了解锁它。
126  vpiImageUnlock(blurred);
127 
128  // 阶段 3:清理 --------------------------------------
129 
130  // 销毁所有创建的对象。
131  vpiStreamDestroy(stream);
132  vpiImageDestroy(image);
133  vpiImageDestroy(imageGray);
134  vpiImageDestroy(blurred);
135 
136  return 0;
137 }
声明了实现盒式滤波器算法的函数。
声明了处理图像格式转换的函数。
#define VPI_IMAGE_FORMAT_U8
具有一个 8 位无符号整数通道的单平面。
用于处理 VPI 图像的函数和结构。
用于处理 OpenCV 与 VPI 的互操作性的函数。
声明了处理 VPI 流的函数。
VPIStatus vpiSubmitBoxFilter(VPIStream stream, uint64_t backend, VPIImage input, VPIImage output, int32_t kernelWidth, int32_t kernelHeight, VPIBorderExtension border)
在图像上运行 2D 盒式滤波器。
VPIStatus vpiSubmitConvertImageFormat(VPIStream stream, uint64_t backend, VPIImage input, VPIImage output, const VPIConvertImageFormatParams *params)
将图像内容转换为所需的格式,并可选择缩放和偏移。
void vpiImageDestroy(VPIImage img)
销毁图像实例。
struct VPIImageImpl * VPIImage
图像的句柄。
定义: Types.h:256
VPIStatus vpiImageLockData(VPIImage img, VPILockMode mode, VPIImageBufferType bufType, VPIImageData *data)
获取图像对象的锁并返回图像内容。
VPIStatus vpiImageCreate(int32_t width, int32_t height, VPIImageFormat fmt, uint64_t flags, VPIImage *img)
使用指定的标志创建空图像实例。
VPIStatus vpiImageUnlock(VPIImage img)
释放图像对象上的锁。
@ VPI_IMAGE_BUFFER_HOST_PITCH_LINEAR
主机可访问,平面采用线性内存布局。
定义: Image.h:172
存储有关图像特性和内容的信息。
定义: Image.h:234
VPIStatus vpiImageCreateWrapperOpenCVMat(const cv::Mat &mat, VPIImageFormat fmt, uint64_t flags, VPIImage *img)
使用给定的图像格式将 cv::Mat 包装在 VPIImage 中。
VPIStatus vpiImageDataExportOpenCVMat(const VPIImageData &imgData, cv::Mat *mat)
使用来自锁定 VPIImage 的 VPIImageData 中的数据填充现有的 cv::Mat。
struct VPIStreamImpl * VPIStream
流的句柄。
定义: Types.h:250
VPIStatus vpiStreamSync(VPIStream stream)
阻塞调用线程,直到此流队列中的所有提交命令都完成(队列为空)...
void vpiStreamDestroy(VPIStream stream)
销毁流实例并释放所有硬件资源。
VPIStatus vpiStreamCreate(uint64_t flags, VPIStream *stream)
创建流实例。
@ VPI_BACKEND_CUDA
CUDA 后端。
定义: Types.h:93
@ VPI_BORDER_ZERO
图像外部的所有像素均被视为零。
定义: Types.h:278
@ VPI_LOCK_READ
仅锁定内存以进行读取。
定义: Types.h:617

构建和测试应用程序

在一切就绪后,执行

cmake .
make

可执行文件 vpi_blur 在同一目录中创建。

要运行应用程序,请执行

./vpi_blur <图像文件名>

<图像文件名> 替换为磁盘上的某个图像。