NVIDIA Vision Programming Interface ( VPI )是 NVIDIA 的一個計算機視覺和圖像處理軟件庫,使您能夠在 NVIDIA Jetson 嵌入式設備和離散 GPU 上提供的不同硬件后端上實現(xiàn)加速算法。
庫中的一些算法包括濾波方法、透視扭曲、時間降噪、直方圖均衡化、立體視差和鏡頭畸變校正。 VPI 提供了易于使用的 Python 綁定,以及一個 C ++ API 。
除了 與 OpenCV 接口 , VPI 還能夠與 PyTorch 和其他基于 Python 的庫進行互操作。在本文中,我們將通過一個基于 PyTorch 的對象檢測和跟蹤示例向您展示這種互操作性是如何工作的。有關更多信息,請參閱 視覺編程接口( VPI ) 頁和 Vision 編程接口 文檔。
與 PyTorch 和其他庫的互操作性
根據(jù)您在計算機視覺和深度學習管道中實現(xiàn)的應用程序,您可能必須使用多個庫。開發(fā)此類管道的挑戰(zhàn)之一是這些庫之間交互的效率。例如,當在內存拷貝之間交換圖像數(shù)據(jù)時,可能會由于內存拷貝而出現(xiàn)性能問題。
使用 VPI ,您現(xiàn)在可以與 PyTorch 或任何其他支持__cuda_array_interace__的庫進行互操作。__cuda_array_interface__( CUDA Array Interface )是 Python 中的一個屬性,它支持各種項目(如庫)中類似 GPU Array 對象的不同實現(xiàn)之間的互操作性。
陣列對象(如圖像)可以在一個庫中創(chuàng)建,在另一個庫中修改,而無需復制 GPU 中的數(shù)據(jù)或將其傳遞給 CPU 。

圖 1 VPI 和其他庫之間的互操作性使用 __cuda_array_interface__
時間噪聲抑制以改進目標檢測和跟蹤
噪聲是視頻中跨幀的常見特征。這種時間噪聲會對視頻中目標檢測和跟蹤算法的性能產生負面影響。
VPI 庫提供了一種時間降噪( TNR )算法,這是計算機視覺應用中用于降低視頻數(shù)據(jù)中噪聲的常用方法。
在本演練中,您將在嘈雜的視頻上使用基于 PyTorch 的對象檢測和跟蹤示例。然后應用 VPI 中的 TNR 算法來減少噪聲,從而改進目標檢測和跟蹤。
我們表明,在執(zhí)行 VPI 和 PyTorch 算法的過程中, VPI 和 PyTorch 都可以無縫工作,沒有任何內存拷貝。
該示例包括以下內容:
PyTorch 基于原始輸入視頻的目標檢測與跟蹤
PyTorch 基于 VPI TNR 的干凈輸入視頻目標檢測與跟蹤
使用 CUDA 陣列接口實現(xiàn) VPI 和 PyTorch 之間的互操作性
PyTorch 基于原始輸入視頻的目標檢測與跟蹤
首先,首先定義一個基于 PyTorch 的應用程序來檢測圖像中的對象。此示例應用程序基于 具有 MobileNetV3 主干的 SSDLite ,用于使用 PyTorch 和 Torchvision 進行目標檢測 Example.
創(chuàng)建一個名為PyTorchDetection的類來處理所有 PyTorch 對象和調用。創(chuàng)建此類對象時,應用程序正在將用于對象檢測的預訓練深度學習模型加載到 GPU ,僅用于推理。以下代碼示例顯示了所需的導入和類構造函數(shù)定義:
import torch
import torchvision class PyTorchDetection: def __init__(self): assert torch.cuda.is_available() self.cuda_device = torch.device('cuda') self.convert = torchvision.transforms.Compose([ torchvision.transforms.ConvertImageDtype(torch.float32), torchvision.transforms.Lambda(lambda x: x.permute(2, 0, 1)), torchvision.transforms.Lambda(lambda x: x.unsqueeze(0)), ]) model = torchvision.models.detection.ssdlite320_mobilenet_v3_large(
pretrained=True) self.torch_model = model.eval().to(self.cuda_device)
PyTorchDetection類還負責從陣列創(chuàng)建 CUDA 圖像幀,有效地將其上載到 GPU 。稍后,您將使用 OpenCV 從文件中讀取輸入視頻,其中每個視頻幀都是一個 NumPy 數(shù)組,用作該類創(chuàng)建函數(shù)的輸入。
此外,PyTorchDetection類可以將 CUDA 圖像幀轉換為 CUDA 張量對象,為模型推斷做好準備,并將基于 VPI 的 CUDA 幀轉換為張量。最后一次轉換使用 VPI 的__cuda_array_interface__互操作性來避免復制幀。
def CreateCUDAFrame(self, np_frame): return torch.from_numpy(np_frame).to(self.cuda_device) def ConvertToTensor(self, cuda_frame): return self.convert(cuda_frame) def ConvertFromVPIFrame(self, vpi_cuda_frame): return torch.as_tensor(vpi_cuda_frame, device=self.cuda_device)
除了前面定義的函數(shù)外,PyTorchDetection類還定義了一個函數(shù),在給定scores_threshold值的情況下,可以在當前 OpenCV 幀中檢測和繪制對象:
def DetectAndDraw(self, cv_frame, torch_tensor, title, scores_threshold=0.2): with torch.no_grad(): pred = self.torch_model(torch_tensor) (...)
在這篇文章中,我們省略了代碼,以提請大家注意 PyTorch 模型的預測結果。此處下載或使用本規(guī)范即表示您接受本規(guī)范的條款和條件。 您可以下載并查看代碼 。
下一節(jié)介紹如何使用 VPI 降低輸入視頻中的噪聲,將 VPI 與 PyTorch 耦合以改進其目標檢測。
PyTorch 基于 VPI TNR 的干凈輸入視頻目標檢測與跟蹤
在本節(jié)中,定義一個基于 VPI 的實用程序類VPITemporalNoiseReduction,以清除視頻幀中的噪聲。
創(chuàng)建此類對象時,應用程序加載主 VPI TNR 對象和基于 VPI 的 CUDA 幀以存儲清理后的輸出。以下代碼示例顯示了所需的導入和類構造函數(shù)定義:
import vpi class VPITemporalNoiseReduction: def __init__(self, shape, image_format): if (image_format == 'BGR8'): self.vpi_image_format = vpi.Format.BGR8 else: self.vpi_image_format = vpi.Format.INVALID self.vpi_output_frame = vpi.Image(shape, format=self.vpi_image_format) self.tnr = vpi.TemporalNoiseReduction(shape, vpi.Format.NV12_ER, version=vpi.TNRVersion.V3, backend=vpi.Backend.CUDA)
類的構造函數(shù)需要每個輸入圖像幀的形狀(圖像寬度和高度)和格式。為簡單起見,您只接受BGR8圖像格式,因為這是OpenCV在讀取輸入視頻時使用的格式。
此外,您正在創(chuàng)建 VPI 圖像,以使用提供的形狀和格式存儲輸出幀。然后使用 TNR code 版本 3 和 CUDA 后端為該形狀構造 TNR 對象。 TNR 的輸入格式為 NV12 \ u ER ,與輸入圖像幀中的格式不同。接下來將在Denoise實用程序函數(shù)中處理幀轉換。
def Denoise(self, torch_cuda_frame, tnr_strength=1.0): vpi_input_frame = vpi.asimage(torch_cuda_frame, format=self.vpi_image_format) with vpi.Backend.CUDA: vpi_input_frame = vpi_input_frame.convert(vpi.Format.NV12_ER) vpi_input_frame = self.tnr(vpi_input_frame, preset=vpi.TNRPreset.OUTDOOR_LOW_LIGHT, strength=tnr_strength) vpi_input_frame.convert(out=self.vpi_output_frame) return self.vpi_output_frame
最后一個函數(shù)執(zhí)行輸入圖像幀的實際清理。此函數(shù)用于從基于 PyTorch 的輸入 CUDA 幀中移除噪聲,返回基于 VPI 的輸出 CUDA 幀。
首先使用 PyTorch 函數(shù)將 PyTorch vpi.asimage幀轉換為 VPI 。torch_cuda_frame與vpi_input_frame共享相同的內存空間:即不涉及內存拷貝。
接下來,將輸入幀從給定的輸入格式( BGR8 )轉換為 CUDA 中的 NV12 \ u ER 進行處理。
使用 TNR 預設OUTDOOR_LOW_LIGHT和給定的 TNR 強度,在轉換后的輸入幀上執(zhí)行 TNR 算法。
清理后的輸入幀( TNR 算法的輸出)被轉換回原始格式( BGR8 ),并存儲在基于 VPI 的 CUDA 輸出幀中。
生成的輸出幀將返回,以供 PyTorch 稍后使用。
使用 CUDA 陣列接口實現(xiàn) VPI 和 PyTorch 之間的互操作性
最后,在主模塊中定義一個MainWindow類。此類基于 PySide2 ,并為本例提供了圖形用戶界面。
窗口界面顯示兩個輸出圖像幀,一個僅使用 PyTorch 進行檢測,另一個在 VPI TNR 后使用 PyTorch 。此外,窗口界面包含兩個滑塊,用于控制用于 PyTorch 檢測的分數(shù)閾值和用于去除 VPI 時間噪聲的 TNR 強度。
import cv2
import numpy as np
(...)
from PySide2 import QtWidgets, QtGui, QtCore
(...)
from vpitnr import VPITemporalNoiseReduction
from torchdetection import PyTorchDetection class MainWindow(QMainWindow): def __init__(self, input_path): super().__init__() #-------- OpenCV part -------- self.video_capture = cv2.VideoCapture(input_path) if not self.video_capture.isOpened(): self.Quit() self.input_width = int(self.video_capture.get(cv2.CAP_PROP_FRAME_WIDTH)) self.input_height = int(self.video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT)) self.output_video_shape = (self.input_height * 2, self.input_width, 3) self.output_frame_shape = (self.input_height, self.input_width, 3) self.cv_output_video = np.zeros(self.output_video_shape, dtype=np.uint8) #-------- Main objects of this example -------- self.torch_detection = PyTorchDetection() self.vpi_tnr = VPITemporalNoiseReduction((self.input_width, self.input_height), 'BGR8') (...) def UpdateDetection(self): in_frame = self.cv_input_frame if in_frame is None: return cuda_input_frame = self.torch_detection.CreateCUDAFrame(in_frame) # -------- Top Frame: No VPI --------- cuda_tensor = self.torch_detection.ConvertToTensor(cuda_input_frame) self.torch_detection.DetectAndDraw(self.TopFrame(), cuda_tensor, 'Pytorch only (no VPI)', self.scores_threshold) # -------- Bottom Frame: With VPI --------- vpi_output_frame = self.vpi_tnr.Denoise(cuda_input_frame, self.tnr_strength) with vpi_output_frame.rlock_cuda() as cuda_frame: cuda_output_frame=self.torch_detection.ConvertFromVPIFrame(cuda_frame) cuda_tensor = self.torch_detection.ConvertToTensor(cuda_output_frame) self.torch_detection.DetectAndDraw(self.BottomFrame(), cuda_tensor, 'Pytorch + VPI TNR', self.scores_threshold) (...)
類的構造函數(shù)需要輸入視頻的路徑。它使用OpenCV讀取輸入視頻,并創(chuàng)建一個高度為輸入視頻兩倍的輸出視頻幀。這用于存儲兩個輸出幀,一個僅用于PyTorch輸出,另一個用于VPI+ PyTorch 輸出。
構造函數(shù)還為 PyTorch 檢測和 VPI TNR 創(chuàng)建對象。在本文中,我們省略了創(chuàng)建圖形用戶界面小部件和處理其回調的代碼。我們還省略了創(chuàng)建主窗口和啟動應用程序的代碼。有關 TNR code 這一部分的更多信息,請下載示例。
當有新的輸入視頻幀可用時,調用UpdateDetection函數(shù),從 NumPy OpenCV 輸入幀創(chuàng)建基于 PyTorch 的 CUDA 輸入幀。然后將其轉換為張量,以檢測并繪制PyTorchDetection類。頂部幀的管道直接在輸入視頻幀中運行 PyTorch 檢測。
底部幀的下一條管道首先對基于 PyTorch CUDA 的輸入幀進行去噪。去噪后的輸出是一個名為vpi_output_frame的基于 VPI 的 CUDA 幀,使用rlock_cuda函數(shù)在 CUDA 中鎖定讀取。此函數(shù)為cuda_frame對象中的 VPI CUDA 互操作性提供__cuda_array_interface__。該對象將轉換為 PyTorch CUDA 幀,然后轉換為張量。再次,對管道的結果調用 detect and draw 函數(shù)。第二條管道在 VPI 去噪功能之后運行PyTorchDetection。
結果
圖 3 顯示了在公共場所行人噪聲輸入視頻上,無 VPI TNR 和有 VPI TNR 的 PyTorch 目標檢測和跟蹤的結果。正如您可以從帶有注釋的輸出視頻中看到的那樣,在檢測之前應用去噪可以改善檢測和跟蹤結果(右)。

圖 3 PyTorch 無 VPI TNR 和(右)有 VPI TNR 的目標檢測和跟蹤(左)
視頻幀右下角顯示的每秒幀數(shù)( FPS )( 32.8 僅適用于 PyTorch , 32.1 適用于 VPI + PyTorch )表明,將 VPI 添加到 PyTorch 檢測管道不會增加太多開銷。這在一定程度上是由于避免了從 CUDA 內存到 CPU 內存的每幀超過 20Mb 的拷貝,這是通過使用__cuda_array_interface__啟用的。
總結
在這篇文章中,我們以 PyTorch 對象檢測和跟蹤為例,展示了 VPI 和其他支持__cuda_array_interface__的庫之間的互操作性。在目標檢測和跟蹤之前,您應用了 VPI 的時間噪聲抑制來改進它。我們還證明了在 PyTorch 管道中添加 VPI 不會導致性能損失。
關于作者
Sandeep Hiremath 是NVIDIA 計算機視覺的首席技術產品經理。他是一位經驗豐富的產品領導者,專長于計算機視覺、機器學習和嵌入式系統(tǒng)領域。在NVIDIA ,他負責為汽車、醫(yī)療保健、機器人和研究領域的開發(fā)人員提供一組計算機視覺和圖像處理解決方案的產品愿景和戰(zhàn)略。
André de Almeida Maximo 是 NVIDIA 的系統(tǒng)工程師,專注于嵌入式平臺的軟件。他曾在多家工業(yè)公司的研究中心工作,幫助塑造不同行業(yè)的人工智能。在空閑時間,安德烈喜歡跑步和閱讀小說。
審核編輯:郭婷
-
嵌入式
+關注
關注
5200文章
20459瀏覽量
334370 -
gpu
+關注
關注
28文章
5198瀏覽量
135521 -
計算機
+關注
關注
19文章
7809瀏覽量
93234 -
pytorch
+關注
關注
2文章
813瀏覽量
14857
發(fā)布評論請先 登錄
PyTorch 中RuntimeError分析
是德科技攜手愛立信賦能Pre-6G互操作性驗證
通過恩智浦RW612三頻無線MCU提升多協(xié)議互操作性
IO序列化操作:提升系統(tǒng)互操作性的關鍵技術
Pytorch 與 Visionfive2 兼容嗎?
Matter 1.5版本解析,智能家居又添驚喜
是德科技與HEAD acoustics成功完成新一代eCall系統(tǒng)互操作性測試
DP1363F 多協(xié)議NFC 兼容CLRC663開發(fā)資料
Microchip與AVIVA Links實現(xiàn)ASA-ML互操作性驗證
AMD助力Matrox Video打造下一代AV-over-IP系統(tǒng)
Matter 智能家居的通用語言
解讀新發(fā)布的 Matter 1.4:推動智能家居設備互操作性的關鍵升級
Valens聯(lián)合七家MIPI A-PHY芯片廠商完成互操作性測試,加速中國及全球MIPI A-PHY生態(tài)發(fā)展
改進VPI和PyTorch之間的互操作性
評論