NVIDIA VPI初探(2):只需2行代码轻松实现常见图像算法

2021-10-13 15:01:56 浏览数 (1)

前面文章已经简单介绍NVIDIA VPI视觉开发接口的架构以及主要元素,组成这个高阶封装的易用接口(NVIDIA VPI初探(1):用NVIDIA VPI高阶封装接口,快速开发GPU视觉应用 ),本文重点在于提供更多图像处理的算法,让大家更加深刻体会到VPI的简便性。本文范例在NVIDIA Jeston AGX Xavier上进行,主要以功能实践为主,不做性能方面的比较。

正常使用Jetpack 4.5.1之后版本安装Jetson设备,就会连同VPI开发库一起安装好,不过samples部分可能需要手动安装,请检查/opt/nvidia/vpi下面是否有samples文件夹?如果没有的话,直接执行下面命令就可以安装:

代码语言:javascript复制
$ sudo apt install libnvvpi1 vpi1-dev vpi1-samples vpi1-demos

现在就能在samples目录下看到有15个项目以及一个assets的数据目录。

一开始先挑两个最简单的算法合并在一起演示,可以节省一些重复的设定代码,这样就能更清楚看到VPI的简便。

下面代码是将Samples的01-convolue_2d与04-rescale合并的代码,并且直接指定输入与输出文件,全部都用CUDA这个后端进行计算:

代码语言:javascript复制
import cv2, vpi            # 这个顺序不能颠倒
import numpy as np
from PIL import Image

# 指定输入文件
IMG_INPUT1  = "/usr/src/tensorrt/data/resnet50/binoculars.jpeg"
IMG_INPUT4  = "/home/nvidia/Desktop/maskTest2.png"
# 设定使用的后端
backend = vpi.Backend.CUDA
# 为范例1定义一个简单的边缘检测的卷积核
kernel = [[ 1, 0, -1], [ 0, 0,  0], [-1, 0, 1]]
# 为范例4定义宽与高的缩放倍数
scale_w = 0.3
scael_h = 0.5 

# 将第1个范例使用的图像,用vpi.image类读入图像,并转换成灰阶格式
input1 = vpi.asimage(np.asarray(Image.open(IMG_INPUT1)))
input1 = input1.convert(vpi.Format.U8, backend=backend)
# 将第4个范例使用的图像,用vpi.image类读入图像,并转换成NV12格式
input4 = vpi.asimage(np.asarray(Image.open(IMG_INPUT4)))
temp = input4.convert(vpi.Format.NV12_ER, backend=backend)
# 开始计算:
with backend: 
#===== 01-convolve_2d
    output1 = input1.convolution(kernel, border=vpi.Border.ZERO)
#===== 04-harris_corners
    temp = temp.rescale((int(input4.width*scale_w), int(input4.height*scale_h)))
    output4 = temp.convert(input4.format, backend=backend)
# 将结果写入文件:
Image.fromarray(output1.cpu()).save('01-convolve_2d.png')
Image.fromarray(output4.cpu()).save('04-scaled.png')

可以看到上面在处理卷积计算与缩放的计算,在VPI也就是一行代码的事情,其他部分主要都是在做格式转换的任务,其实也都是一行指令就完成很多任务了。

这个合并代码的用意,就是让大家能更清楚感受到VPI提供的高阶封装接口,能让开发者如此轻松就完成过去相对复杂的事情。现在来看看输出结果:

1

01-convolve_2d:透过卷积计算找出图像的边缘线条,左边是原图、右边是结果:

2

04-rescale:将图像执行任意比例缩放,下面是原图,左上角黄框内是缩放后结果:

3

如果觉得这些范例太过简单,请继续尝试02-stereo_disparity的Python实验,这里就不列出个别目录里main.py的代码内容,请自行开启。

VPI将最核心耗时的算法封装成一道简单指令。在02-stereo_disparity/main.py第92行“disparity = vpi.stereodisp(参数)”就是这样的用法,后面的工作再根据disparity结果去进行格式、颜色空间、置信图的转换。

现在就执行以下指令来进行实验:

代码语言:javascript复制
$ cd /opt/nvidia/vpi1/samples/02-stereo_disparity
 $ python3 main.py cuda ../assets/chair_stereo_left.png 
../assets/chair_stereo_right.png

下面是执行的输出结果:

4

接着再看看03-harris_corners/main.py第59行“corners,scores = input.harriscorners(sensitivity=0.01)”也是一样的状况,整个计算也是一道指令就完成,后面再根据corners去绘制“角点”的位置,并根据scores给定不同的颜色。

这里只推荐修改最后一行“cv2.circle(out_data, kpt, 5, color, -1)”的粗体参数,将半径分改为5以上的值,否则所画的圆点太小,不容易识别出效果。

我们挑选assets/fisheye下面的image-002.jpg作为输入,可以找到更多的“角点(corner)”。请执行以下指令来体验这个范例:

代码语言:javascript复制
$ cd /opt/nvidia/vpi1/samples/03-harris_corners
 $ python3 main.py cuda ../assets/fisheye/image-002.jpg

下面是执行的输出结果:

如何?这几个范例都是让大家体验到,VPI将一些常用算法封装成简单指令的形式,对开发人员来说是非常便利的,而且大幅度提高可阅读性。

这几个范例中都使用到OpenCV库,这就能证明VPI并不是要全面取代OpenCV,而是为计算机视觉的“算法”部分,提供更有效的调用方法,更快速地在NVIDIAGPU设备上开发出高效的应用。

近期活动:

0 人点赞