在本文中,我們將向您展示如何在 Jetson 產(chǎn)品系列上運行時間降噪( TNR )示例應(yīng)用程序。
在 Jetson 設(shè)備上設(shè)置 VPI
通過 SDK 管理器設(shè)置 Jetson 設(shè)備時,請確保選中 Jetson SDK 組件框。然后在設(shè)備閃存時安裝 VPI 。
安裝完成后,可以在以下路徑下找到 VPI :
/opt/nvidia/vpi1/
要驗證環(huán)境設(shè)置是否正確,請將 VPI 示例應(yīng)用程序復(fù)制到主目錄中,然后構(gòu)建 TNR 示例。
$ vpi1_install_samples.sh $HOME $ cd $HOME/NVIDIA_VPI–samples/09-tnr $ cmake . $ make
VPI 在運行離散 GPU 的 x86 機器上也受支持。有關(guān)更多信息,請參閱 VPI – Vision 編程接口文檔中的 Installation 。
TNR 示例應(yīng)用程序
VPI 提供了一組 CV 算法,這些算法利用多個后端高效地使用設(shè)備的可用計算資源。 TNR 是在 Jetson 設(shè)備上運行的計算機視覺應(yīng)用程序中常用的一種降噪方法。本文使用 TNR 示例應(yīng)用程序來演示如何使用 VPI 中的一些關(guān)鍵概念和組件來實現(xiàn)自己的應(yīng)用程序。
我們將在本帖中介紹以下主題:
創(chuàng)建構(gòu)建 VPI 管道所需的元素
了解如何與 OpenCV 進(jìn)行互操作
向流提交處理任務(wù)
同步流中的任務(wù)
鎖定圖像緩沖區(qū)以便可以從 CPU 訪問
TNR 樣本可在以下路徑中找到:
$HOME/NVIDIA_VPI–samples/09-tnr/main.cpp
有關(guān)示例應(yīng)用程序和算法的更多信息,請參閱以下參考資料:
時間降噪示例應(yīng)用程序
時域降噪算法
算法版本和后端支持
硬件引擎在 VPI 中被命名為 backends 。通過使用 Jetson 設(shè)備固有的可用系統(tǒng)級并行性,這些后端使您能夠卸載可并行處理階段并加速應(yīng)用程序。后端是 CPU 、 CUDA ( GPU )、 PVA 和 VIC 。特定后端引擎的確切可用性取決于應(yīng)用程序部署到的 Jetson 平臺。有關(guān)特定平臺上可用算法、后端支持和后端可用性的更多信息,請參閱 Algorithms 。
VPI 目前為 TNR 提供了兩種不同的實現(xiàn),每種實現(xiàn)都適合不同的場景和需求。這些版本采用雙邊濾波平滑平坦區(qū)域,同時保留邊緣,和時間無限脈沖響應(yīng)( IIR )濾波與運動檢測器的結(jié)合,以處理跨幀的時間噪聲。
VPI_TNR_V2 – 與 VPI_TNR_V3 相比,該版本提供了更輕的噪音降低,并且具有一定程度的可配置性,即可以調(diào)整照明條件以更好地適應(yīng)給定場景。這個版本有一個減少的計算需求,這轉(zhuǎn)化為速度。它適用于執(zhí)行時間比降噪質(zhì)量更重要的用例。
VPI_TNR_V3 —用于需要更好質(zhì)量的降噪的用例。與 VPI_TNR_V2 相比,使用這個變體,您應(yīng)該期望計算需求會增加。除此之外,還進(jìn)一步擴展了可配置性。建議用于具有挑戰(zhàn)性的弱光場景。
VPI_TNR_DEFAULT – 您可以使用默認(rèn)值,而不是指定確切的版本,該值選擇給定后端支持的噪聲抑制最強的版本。
在決定哪個算法版本適合您的用例時,需要考慮的另一個標(biāo)準(zhǔn)是它對不同后端和設(shè)備的支持。下表總結(jié)了 TNR 支持。
VPI_TNR_V2 和 VPI_TNR_V3 都允許顯式設(shè)置要捕獲的場景的照明條件,從而啟用調(diào)整。這在低光場景或以高增益捕獲的流的上下文中是重要的,所述低光場景或流可能包含更高的噪聲級,并且因此要求更高的噪聲降低水平。
較高的強度級別可能會影響幀的紋理區(qū)域中的細(xì)節(jié)數(shù)量,從而使其平滑。另一個副作用是在有快速移動物體的場景中重影。支持的場景照明條件在類型(室內(nèi)、室外)和強度(低、中、高)方面有所不同,如下表所示。
使用不同的版本和相關(guān)的照明條件預(yù)設(shè),您可以根據(jù)用例的具體情況調(diào)整 TNR 算法。這可以通過所謂的強度系數(shù)進(jìn)一步定制。它是一個浮動參數(shù),范圍從 0 到 1 ,其中較大的值對應(yīng)于增加的去噪強度。
VPI 應(yīng)用程序
VPI 的一個關(guān)鍵方面是如何管理和協(xié)調(diào)在不同后端之間運行應(yīng)用程序所需的資源。使用 VPI ,可以避免在處理階段之間浪費內(nèi)存拷貝。 VPI 為實現(xiàn)高效的內(nèi)存管理而實施的另一種機制是在其接口處進(jìn)行內(nèi)存包裝。
利用 VPI 的所有內(nèi)存管理特性取決于代碼的結(jié)構(gòu)。最佳實踐是將代碼視為三階段工作流:
Initialization
處理回路
Cleanup
大部分內(nèi)存分配應(yīng)該在初始化階段進(jìn)行。對于在可用資源受限的設(shè)備上運行的嵌入式應(yīng)用程序,這一點尤為重要。除此之外,還可以更有效、更謹(jǐn)慎地進(jìn)行內(nèi)存管理,以避免可能的內(nèi)存泄漏。
VPI 中的一個好做法是指定使用內(nèi)存的后端。在這點上,只將 VPI 對象訂閱到所需的后端集可以保證在管道在這些后端之間流動時獲得最有效的內(nèi)存路徑。
處理循環(huán)是執(zhí)行處理管道的地方。想象一下,一個應(yīng)用程序在一個包含數(shù)百個單獨幀的視頻文件上迭代。主循環(huán)將主要負(fù)責(zé)對像素信息執(zhí)行所需的變換,以實現(xiàn)給定計算機視覺任務(wù)的預(yù)期結(jié)果。
最后,清理階段處理在任務(wù)執(zhí)行期間使用的資源的所有必要釋放和釋放。堅持這種模式可以使 VPI 盡可能使用最有效的處理管道,并幫助您堅持良好的編碼實踐。
與 OpenCV 接口
VPI 與 OpenCV 的互操作性是該庫的一個顯著特征。如果您熟悉 OpenCV ,您可以輕松地將 VPI 與工作流集成,或者擴展現(xiàn)有的數(shù)據(jù)管道,以便更好地使用 VPI 提供的硬件加速。
TNR 示例中通過以下實用函數(shù)演示了這一點,該函數(shù)將使用 OpenCV 捕獲的輸入視頻幀包裝到 VPI 圖像對象中。
69 // Utility function to wrap a cv::Mat into a VPIImage 70 static VPIImage ToVPIImage(VPIImage image, const cv::Mat &frame) 71 { 72 if (image == nullptr) 73 { 74 // Create a VPIImage that wraps the frame 75 CHECK_STATUS(vpiImageCreateOpenCVMatWrapper(frame, 0, &image)); 76 } 77 else 78 { 79 // reuse existing VPIImage wrapper to wrap the new frame. 80 CHECK_STATUS(vpiImageSetWrappedOpenCVMat(image, frame)); 81 } 82 return image; 83 }
從更深入地研究前面描述的函數(shù)開始。它意味著將 OpenCV 矩陣( cv::Mat )對象包裝到 VPI 圖像對象( VPIImage )。要上下文化, VPI 圖像基本上是任何可以用寬度、高度和格式來描述的 2D 數(shù)據(jù)結(jié)構(gòu)。盡管將圖像數(shù)據(jù)視為 VPIImage 對象是直觀的,但它的用法也可以擴展到其他類型的數(shù)據(jù),例如二維向量場和熱圖。
The utility wrapping function invokes two other functions that pertain to the VPI OpenCVInterop.hpp module, which aims to provide useful infrastructure to integrate OpenCV-based code with VPI.
vpiImageCreateOpenCVMatWrapper —一個重載函數(shù),它以兩種不同的方式將 cv:Mat 對象包裝到 VPIImage 中。第一種方法嘗試直接從輸入類型推斷格式(遵循特定的規(guī)則),而第二種方法將顯式格式作為其參數(shù)之一。
vpiImageSetWrappedOpenCVMat – 重用為特定 cv::Mat 對象定義的包裝器來包裝新的傳入 cv::Mat 對象。這里的重點是避免在第一時間創(chuàng)建包裝時產(chǎn)生的內(nèi)存分配,這樣效率更高。傳入的 cv::Mat 對象必須呈現(xiàn)與創(chuàng)建時使用的原始對象相同的特征(格式和尺寸)。
流創(chuàng)建
main 函數(shù)捕獲設(shè)置 VPI 管道以完成工作的相關(guān)步驟。管道的定義很簡單,也很直觀。在 VPI 中,管道是一個或多個數(shù)據(jù)流的組合,這些數(shù)據(jù)流流經(jīng)不同的處理階段。
圖 1 以一種通用的方式顯示了管道及其構(gòu)建塊(流、緩沖區(qū)、算法等)。為了簡單起見,省略了一些組件。
圖 1 通用 VPI 管道。
流的目的是強制執(zhí)行一個排隊的步驟序列,數(shù)據(jù)需要通過該序列來完成特定的計算機視覺任務(wù)。這些步驟可能包括數(shù)據(jù)的預(yù)處理或后處理,甚至包括 TNR 之類的成熟算法。圖 2 顯示了 VPIStream 對象的示例。
圖 2 VPIStream 對象。
VPI 可適應(yīng)各種不同的管道復(fù)雜性。您可以用一個流實現(xiàn)一個簡單的管道,或者用幾個不同階段的并行流實現(xiàn)一個更復(fù)雜的實現(xiàn),并將這些并行流卸載到不同的計算后端。這是 API 的一個強大功能,因為它使您能夠獲得對 Jetson 設(shè)備提供的系統(tǒng)級并行性的更多控制。
下面的代碼示例演示如何在 TNR 示例中創(chuàng)建流。
143 VPIStream stream; 144 // PVA backend doesn't have currently Convert Image Format algorithm. 145 // Use the CUDA backend to do that. 146 CHECK_STATUS(vpiStreamCreate(VPI_BACKEND_CUDA | backend, &stream));
選擇的后端正在傳遞到流中。這是一個可選步驟。使用零值將啟用所有可用的后端。但是,分配一組特定的后端是推薦的做法,因為它有助于優(yōu)化內(nèi)存分配。
TNR 有效載荷
有效負(fù)載基本上是管道執(zhí)行期間所需的臨時資源。例如,有效負(fù)載可以是中間內(nèi)存緩沖區(qū),用于存儲流的后續(xù)階段之間交換的數(shù)據(jù)。包括 TNR 在內(nèi)的許多算法都需要顯式地創(chuàng)建有效負(fù)載,具體實現(xiàn)如下。
172 // Create a TNR payload configured to process NV12 173 // frames under outdoor low-light scenarios. 174 VPIPayload tnr; 175 CHECK_STATUS(vpiCreateTemporalNoiseReduction(backend, w, h, VPI_IMAGE_FORMAT_NV12_ER, VPI_TNR_DEFAULT, 176 VPI_TNR_PRESET_INDOOR_LOW_LIGHT, 1, &tnr));
對于 TNR 有效負(fù)載,請?zhí)峁┮韵聟?shù):
圖像尺寸(寬度和高度)
Backend
圖像數(shù)據(jù)格式(目前僅支持 NV12 )
TNR 算法版本
照明條件
降噪強度
對算法有效負(fù)載的引用
最終,該函數(shù)創(chuàng)建一個有效負(fù)載并將其綁定到指定的后端。
圖像緩沖區(qū)
除了創(chuàng)建流和有效負(fù)載外,還必須創(chuàng)建 VPI 算法所需的圖像緩沖區(qū)。在 TNR 中,使用雙邊和 IIR 濾波器的組合,因此需要三個不同的緩沖器,即當(dāng)前和先前的圖像輸入和圖像輸出。
可以按如下方式創(chuàng)建圖像緩沖區(qū):
167 VPIImage imgPrevious, imgCurrent, imgOutput; 168 CHECK_STATUS(vpiImageCreate(w, h,VPI_IMAGE_FORMAT_NV12_ER, 0, &imgPrevious)); 169 CHECK_STATUS(vpiImageCreate(w, h,VPI_IMAGE_FORMAT_NV12_ER, 0, &imgCurrent)); 170 CHECK_STATUS(vpiImageCreate(w, h,VPI_IMAGE_FORMAT_NV12_ER, 0, &imgOutput));
這將創(chuàng)建具有以下指定特征的空緩沖區(qū):
圖像尺寸(寬度和高度)
格式(根據(jù)算法要求)
圖像標(biāo)志(當(dāng)前用于分配后端)
指向返回所創(chuàng)建映像的 VPIImage 句柄的變量的指針
流處理
在構(gòu)建塊已經(jīng)就位的情況下,您可以轉(zhuǎn)到主處理循環(huán),在那里執(zhí)行降噪算法。在 TNR 樣本上,循環(huán)迭代來自視頻文件的每個單獨幀,并執(zhí)行必要的連續(xù)步驟以獲得所需的結(jié)果。
當(dāng)從視頻中收集幀時,第一步是使用前面描述的實用程序函數(shù)將其包裝成 VPIImage 對象。
186 frameBGR = ToVPIImage(frameBGR, cvFrame);
包裝完成后, VPI 現(xiàn)在可以對 VPIImage 對象中的像素數(shù)據(jù)進(jìn)行操作。因為 TNR 要求幀是 NV12 格式,所以需要一個轉(zhuǎn)換步驟。
188 // First convert it to NV12 189 CHECK_STATUS(vpiSubmitConvertImageFormat(stream,VPI_BACKEND_CUDA, frameBGR, imgCurrent, NULL));
在此階段,轉(zhuǎn)換圖像的特定任務(wù)與先前實例化的流相關(guān)聯(lián)。除此之外,任務(wù)被設(shè)置為在 GPU 上執(zhí)行。輸入幀的圖像緩沖區(qū)以及剛剛從cv::Mat
對象包裝的數(shù)據(jù)都用于此目的。
格式轉(zhuǎn)換完成后,可以將輸入緩沖區(qū)傳遞給 TNR 算法進(jìn)行處理。
191 // Apply TNR 192 // For first frame, you must pass nullptr as the previous frame, this resets the internal 193 // state. 194 CHECK_STATUS(vpiSubmitTemporalNoiseReduction(stream, 0, tnr, curFrame == 1 ? nullptr : imgPrevious, 195 imgCurrent, imgOutput)); 196
要調(diào)用 TNR 算法,請設(shè)置以下參數(shù):
- 與算法關(guān)聯(lián)的流
- 后端
- 算法有效負(fù)載,如前面實例化的一樣
- 圖像緩沖區(qū):以前和當(dāng)前的輸入和輸出
在第一次迭代(curFrame == 1
)時,緩沖區(qū)上沒有有效的前一個映像,而是傳遞一個空指針。對于下面的迭代,緩沖區(qū)將相應(yīng)地填充。在執(zhí)行 TNR 算法之后,輸出緩沖區(qū)可以從 NV12 轉(zhuǎn)換回以前的 BGR 格式。
197 // Convert output back to BGR 198 CHECK_STATUS(vpiSubmitConvertImageFormat(stream,VPI_BACKEND_CUDA, imgOutput, frameBGR, NULL));
在這一點上,必須提到 VPI 對流階段實施了非阻塞異步范例。這對于作為后端分布在不同協(xié)處理器之間的工作負(fù)載的平滑和高效的編排是必不可少的。對于進(jìn)一步的步驟,請確保在繼續(xù)之前已完成向流發(fā)出的所有活動。這時同步功能就派上用場了。
199 CHECK_STATUS(vpiStreamSync(stream));
VPI 現(xiàn)在確保與流相關(guān)的所有正在進(jìn)行的活動在進(jìn)入管道的下一個階段之前都已完成。同步完成后,幀就可以在連接到指定后端的輸出緩沖區(qū)中使用了。為了能夠?qū)⑵鋵懭胼敵鲆曨l流(在這種情況下是一個文件),必須鎖定圖像,以便 CPU 可以使用緩沖區(qū)。
這就解釋了為什么在鎖定幀之前進(jìn)行同步是避免處理問題的關(guān)鍵步驟。因為 VPI 是異步操作的,所以在沒有同步的情況下,緩沖區(qū)會在前一階段完成之前被鎖定。結(jié)果是不可預(yù)測的。
201 // Now add it to the output video stream 202 VPIImageData imgdata; 203 CHECK_STATUS(vpiImageLock(frameBGR,VPI_LOCK_READ, &imgdata)); 204 205 cv::Mat outFrame; 206 CHECK_STATUS(vpiImageDataExportOpenCVMat(imgdata, &outFrame)); 207 outVideo << outFrame; ?208 ?209???????????? CHECK_STATUS(vpiImageUnlock(frameBGR));
如您所見,鎖定的緩沖區(qū)由 CPU 處理,以供進(jìn)一步使用。鎖被設(shè)置為只讀,然后圖像緩沖區(qū)被映射到 CPU 。鎖定時, VPI 無法在緩沖區(qū)上工作。在 CPU 將輸出幀提供給視頻編碼器后,緩沖區(qū)可以被解鎖并被 VPI 進(jìn)一步使用。
VPI 數(shù)據(jù)流
TNR 示例應(yīng)用程序可以概括為以下數(shù)據(jù)流。其他的小步驟也是應(yīng)用程序不可分割的一部分,但是為了簡單起見,圖 3 中只包含了宏步驟。
圖 3 TNR 示例應(yīng)用程序中的數(shù)據(jù)流。
從視頻流或文件中收集輸入幀。 OpenCV 已用于此目的。
必要的 VPI 元素被實例化:單個流、 TNR 算法負(fù)載以及用于先前和當(dāng)前輸入和輸出圖像的圖像緩沖區(qū)。
輸入幀被包裝到 VPIImage 緩沖區(qū)中。
緩沖區(qū)上的像素數(shù)據(jù)被轉(zhuǎn)換成 NV12 ,以便 TNR 算法可以處理它。當(dāng)算法完成執(zhí)行時,它會恢復(fù)到原始格式。
圖像緩沖區(qū)被鎖定,以便 CPU 可以訪問數(shù)據(jù)。將圖像提供給視頻輸出后,可以解鎖緩沖區(qū), VPI 可以進(jìn)一步處理它。
概括
在本文中,我們向您展示了如何在 Jetson 產(chǎn)品系列上運行 TNR 示例應(yīng)用程序。
關(guān)于作者
Maycon da Silva Carvalho 是 Jetson 的現(xiàn)場應(yīng)用工程師。他負(fù)責(zé)與部署基于 Jetson 的應(yīng)用程序的不同行業(yè)的客戶進(jìn)行多學(xué)科技術(shù)合作。
Rodolfo Schulz de Lima 是 VPI 的首席工程師。他擁有 UFRJ 里約熱內(nèi)盧聯(lián)邦大學(xué)電子工程學(xué)士學(xué)位,并在巴西里約熱內(nèi)盧的 IMPA (純數(shù)學(xué)和應(yīng)用數(shù)學(xué)研究所)學(xué)習(xí)計算機圖形學(xué)。
審核編輯:郭婷
-
嵌入式
+關(guān)注
關(guān)注
5152文章
19673瀏覽量
317540 -
gpu
+關(guān)注
關(guān)注
28文章
4946瀏覽量
131233 -
SDK
+關(guān)注
關(guān)注
3文章
1077瀏覽量
49096
發(fā)布評論請先 登錄
NVIDIA RTX AI加速FLUX.1 Kontext現(xiàn)已開放下載
NVIDIA推出全新硅光網(wǎng)絡(luò)交換機
如何降低AD5689R的輸出噪聲?
場效應(yīng)管驅(qū)動電路設(shè)計 如何降低場效應(yīng)管的噪聲
傅立葉變換在圖像處理中的作用
哪些措施能降低電機的噪聲?
aic3254有沒有降低環(huán)境噪聲的算法?
高斯卷積核函數(shù)在圖像采樣中的意義
ivc102如何將噪聲降低到10mv以內(nèi)呢?
電源濾波器是如何降低電源噪聲的

如何使用無代碼無傳感器BLDC電機驅(qū)動器降低電機噪聲

評論