在本文中,我們將向您展示如何在 Jetson 產(chǎn)品系列上運(yùn)行時(shí)間降噪( TNR )示例應(yīng)用程序。
在 Jetson 設(shè)備上設(shè)置 VPI
通過 SDK 管理器設(shè)置 Jetson 設(shè)備時(shí),請確保選中 Jetson SDK 組件框。然后在設(shè)備閃存時(shí)安裝 VPI 。
安裝完成后,可以在以下路徑下找到 VPI :
/opt/nvidia/vpi1/
要驗(yàn)證環(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 在運(yùn)行離散 GPU 的 x86 機(jī)器上也受支持。有關(guān)更多信息,請參閱 VPI – Vision 編程接口文檔中的 Installation 。
TNR 示例應(yīng)用程序
VPI 提供了一組 CV 算法,這些算法利用多個(gè)后端高效地使用設(shè)備的可用計(jì)算資源。 TNR 是在 Jetson 設(shè)備上運(yùn)行的計(jì)算機(jī)視覺應(yīng)用程序中常用的一種降噪方法。本文使用 TNR 示例應(yīng)用程序來演示如何使用 VPI 中的一些關(guān)鍵概念和組件來實(shí)現(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)用程序和算法的更多信息,請參閱以下參考資料:
時(shí)間降噪示例應(yīng)用程序
時(shí)域降噪算法
算法版本和后端支持
硬件引擎在 VPI 中被命名為 backends 。通過使用 Jetson 設(shè)備固有的可用系統(tǒng)級并行性,這些后端使您能夠卸載可并行處理階段并加速應(yīng)用程序。后端是 CPU 、 CUDA ( GPU )、 PVA 和 VIC 。特定后端引擎的確切可用性取決于應(yīng)用程序部署到的 Jetson 平臺。有關(guān)特定平臺上可用算法、后端支持和后端可用性的更多信息,請參閱 Algorithms 。
VPI 目前為 TNR 提供了兩種不同的實(shí)現(xiàn),每種實(shí)現(xiàn)都適合不同的場景和需求。這些版本采用雙邊濾波平滑平坦區(qū)域,同時(shí)保留邊緣,和時(shí)間無限脈沖響應(yīng)( IIR )濾波與運(yùn)動(dòng)檢測器的結(jié)合,以處理跨幀的時(shí)間噪聲。
VPI_TNR_V2 – 與 VPI_TNR_V3 相比,該版本提供了更輕的噪音降低,并且具有一定程度的可配置性,即可以調(diào)整照明條件以更好地適應(yīng)給定場景。這個(gè)版本有一個(gè)減少的計(jì)算需求,這轉(zhuǎn)化為速度。它適用于執(zhí)行時(shí)間比降噪質(zhì)量更重要的用例。
VPI_TNR_V3 —用于需要更好質(zhì)量的降噪的用例。與 VPI_TNR_V2 相比,使用這個(gè)變體,您應(yīng)該期望計(jì)算需求會增加。除此之外,還進(jìn)一步擴(kuò)展了可配置性。建議用于具有挑戰(zhàn)性的弱光場景。
VPI_TNR_DEFAULT – 您可以使用默認(rèn)值,而不是指定確切的版本,該值選擇給定后端支持的噪聲抑制最強(qiáng)的版本。
在決定哪個(gè)算法版本適合您的用例時(shí),需要考慮的另一個(gè)標(biāo)準(zhǔn)是它對不同后端和設(shè)備的支持。下表總結(jié)了 TNR 支持。
VPI_TNR_V2 和 VPI_TNR_V3 都允許顯式設(shè)置要捕獲的場景的照明條件,從而啟用調(diào)整。這在低光場景或以高增益捕獲的流的上下文中是重要的,所述低光場景或流可能包含更高的噪聲級,并且因此要求更高的噪聲降低水平。
較高的強(qiáng)度級別可能會影響幀的紋理區(qū)域中的細(xì)節(jié)數(shù)量,從而使其平滑。另一個(gè)副作用是在有快速移動(dòng)物體的場景中重影。支持的場景照明條件在類型(室內(nèi)、室外)和強(qiáng)度(低、中、高)方面有所不同,如下表所示。
使用不同的版本和相關(guān)的照明條件預(yù)設(shè),您可以根據(jù)用例的具體情況調(diào)整 TNR 算法。這可以通過所謂的強(qiáng)度系數(shù)進(jìn)一步定制。它是一個(gè)浮動(dòng)參數(shù),范圍從 0 到 1 ,其中較大的值對應(yīng)于增加的去噪強(qiáng)度。
VPI 應(yīng)用程序
VPI 的一個(gè)關(guān)鍵方面是如何管理和協(xié)調(diào)在不同后端之間運(yùn)行應(yīng)用程序所需的資源。使用 VPI ,可以避免在處理階段之間浪費(fèi)內(nèi)存拷貝。 VPI 為實(shí)現(xiàn)高效的內(nèi)存管理而實(shí)施的另一種機(jī)制是在其接口處進(jìn)行內(nèi)存包裝。
利用 VPI 的所有內(nèi)存管理特性取決于代碼的結(jié)構(gòu)。最佳實(shí)踐是將代碼視為三階段工作流:
Initialization
處理回路
Cleanup
大部分內(nèi)存分配應(yīng)該在初始化階段進(jìn)行。對于在可用資源受限的設(shè)備上運(yùn)行的嵌入式應(yīng)用程序,這一點(diǎn)尤為重要。除此之外,還可以更有效、更謹(jǐn)慎地進(jìn)行內(nèi)存管理,以避免可能的內(nèi)存泄漏。
VPI 中的一個(gè)好做法是指定使用內(nèi)存的后端。在這點(diǎn)上,只將 VPI 對象訂閱到所需的后端集可以保證在管道在這些后端之間流動(dòng)時(shí)獲得最有效的內(nèi)存路徑。
處理循環(huán)是執(zhí)行處理管道的地方。想象一下,一個(gè)應(yīng)用程序在一個(gè)包含數(shù)百個(gè)單獨(dú)幀的視頻文件上迭代。主循環(huán)將主要負(fù)責(zé)對像素信息執(zhí)行所需的變換,以實(shí)現(xiàn)給定計(jì)算機(jī)視覺任務(wù)的預(yù)期結(jié)果。
最后,清理階段處理在任務(wù)執(zhí)行期間使用的資源的所有必要釋放和釋放。堅(jiān)持這種模式可以使 VPI 盡可能使用最有效的處理管道,并幫助您堅(jiān)持良好的編碼實(shí)踐。
與 OpenCV 接口
VPI 與 OpenCV 的互操作性是該庫的一個(gè)顯著特征。如果您熟悉 OpenCV ,您可以輕松地將 VPI 與工作流集成,或者擴(kuò)展現(xiàn)有的數(shù)據(jù)管道,以便更好地使用 VPI 提供的硬件加速。
TNR 示例中通過以下實(shí)用函數(shù)演示了這一點(diǎn),該函數(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 對象是直觀的,但它的用法也可以擴(kuò)展到其他類型的數(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 —一個(gè)重載函數(shù),它以兩種不同的方式將 cv:Mat 對象包裝到 VPIImage 中。第一種方法嘗試直接從輸入類型推斷格式(遵循特定的規(guī)則),而第二種方法將顯式格式作為其參數(shù)之一。
vpiImageSetWrappedOpenCVMat – 重用為特定 cv::Mat 對象定義的包裝器來包裝新的傳入 cv::Mat 對象。這里的重點(diǎn)是避免在第一時(shí)間創(chuàng)建包裝時(shí)產(chǎn)生的內(nèi)存分配,這樣效率更高。傳入的 cv::Mat 對象必須呈現(xiàn)與創(chuàng)建時(shí)使用的原始對象相同的特征(格式和尺寸)。
流創(chuàng)建
main 函數(shù)捕獲設(shè)置 VPI 管道以完成工作的相關(guān)步驟。管道的定義很簡單,也很直觀。在 VPI 中,管道是一個(gè)或多個(gè)數(shù)據(jù)流的組合,這些數(shù)據(jù)流流經(jīng)不同的處理階段。
圖 1 以一種通用的方式顯示了管道及其構(gòu)建塊(流、緩沖區(qū)、算法等)。為了簡單起見,省略了一些組件。
圖 1 通用 VPI 管道。
流的目的是強(qiáng)制執(zhí)行一個(gè)排隊(duì)的步驟序列,數(shù)據(jù)需要通過該序列來完成特定的計(jì)算機(jī)視覺任務(wù)。這些步驟可能包括數(shù)據(jù)的預(yù)處理或后處理,甚至包括 TNR 之類的成熟算法。圖 2 顯示了 VPIStream 對象的示例。
圖 2 VPIStream 對象。
VPI 可適應(yīng)各種不同的管道復(fù)雜性。您可以用一個(gè)流實(shí)現(xiàn)一個(gè)簡單的管道,或者用幾個(gè)不同階段的并行流實(shí)現(xiàn)一個(gè)更復(fù)雜的實(shí)現(xiàn),并將這些并行流卸載到不同的計(jì)算后端。這是 API 的一個(gè)強(qiáng)大功能,因?yàn)樗鼓軌颢@得對 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));
選擇的后端正在傳遞到流中。這是一個(gè)可選步驟。使用零值將啟用所有可用的后端。但是,分配一組特定的后端是推薦的做法,因?yàn)樗兄趦?yōu)化內(nèi)存分配。
TNR 有效載荷
有效負(fù)載基本上是管道執(zhí)行期間所需的臨時(shí)資源。例如,有效負(fù)載可以是中間內(nèi)存緩沖區(qū),用于存儲流的后續(xù)階段之間交換的數(shù)據(jù)。包括 TNR 在內(nèi)的許多算法都需要顯式地創(chuàng)建有效負(fù)載,具體實(shí)現(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 算法版本
照明條件
降噪強(qiáng)度
對算法有效負(fù)載的引用
最終,該函數(shù)創(chuàng)建一個(gè)有效負(fù)載并將其綁定到指定的后端。
圖像緩沖區(qū)
除了創(chuàng)建流和有效負(fù)載外,還必須創(chuàng)建 VPI 算法所需的圖像緩沖區(qū)。在 TNR 中,使用雙邊和 IIR 濾波器的組合,因此需要三個(gè)不同的緩沖器,即當(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)迭代來自視頻文件的每個(gè)單獨(dú)幀,并執(zhí)行必要的連續(xù)步驟以獲得所需的結(jié)果。
當(dāng)從視頻中收集幀時(shí),第一步是使用前面描述的實(shí)用程序函數(shù)將其包裝成 VPIImage 對象。
186 frameBGR = ToVPIImage(frameBGR, cvFrame);
包裝完成后, VPI 現(xiàn)在可以對 VPIImage 對象中的像素?cái)?shù)據(jù)進(jìn)行操作。因?yàn)?TNR 要求幀是 NV12 格式,所以需要一個(gè)轉(zhuǎn)換步驟。
188 // First convert it to NV12 189 CHECK_STATUS(vpiSubmitConvertImageFormat(stream,VPI_BACKEND_CUDA, frameBGR, imgCurrent, NULL));
在此階段,轉(zhuǎn)換圖像的特定任務(wù)與先前實(shí)例化的流相關(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 算法,請?jiān)O(shè)置以下參數(shù):
- 與算法關(guān)聯(lián)的流
- 后端
- 算法有效負(fù)載,如前面實(shí)例化的一樣
- 圖像緩沖區(qū):以前和當(dāng)前的輸入和輸出
在第一次迭代(curFrame == 1
)時(shí),緩沖區(qū)上沒有有效的前一個(gè)映像,而是傳遞一個(gè)空指針。對于下面的迭代,緩沖區(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));
在這一點(diǎn)上,必須提到 VPI 對流階段實(shí)施了非阻塞異步范例。這對于作為后端分布在不同協(xié)處理器之間的工作負(fù)載的平滑和高效的編排是必不可少的。對于進(jìn)一步的步驟,請確保在繼續(xù)之前已完成向流發(fā)出的所有活動(dòng)。這時(shí)同步功能就派上用場了。
199 CHECK_STATUS(vpiStreamSync(stream));
VPI 現(xiàn)在確保與流相關(guān)的所有正在進(jìn)行的活動(dòng)在進(jìn)入管道的下一個(gè)階段之前都已完成。同步完成后,幀就可以在連接到指定后端的輸出緩沖區(qū)中使用了。為了能夠?qū)⑵鋵懭胼敵鲆曨l流(在這種情況下是一個(gè)文件),必須鎖定圖像,以便 CPU 可以使用緩沖區(qū)。
這就解釋了為什么在鎖定幀之前進(jìn)行同步是避免處理問題的關(guān)鍵步驟。因?yà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 。鎖定時(shí), 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 元素被實(shí)例化:單個(gè)流、 TNR 算法負(fù)載以及用于先前和當(dāng)前輸入和輸出圖像的圖像緩沖區(qū)。
輸入幀被包裝到 VPIImage 緩沖區(qū)中。
緩沖區(qū)上的像素?cái)?shù)據(jù)被轉(zhuǎn)換成 NV12 ,以便 TNR 算法可以處理它。當(dāng)算法完成執(zhí)行時(shí),它會恢復(fù)到原始格式。
圖像緩沖區(qū)被鎖定,以便 CPU 可以訪問數(shù)據(jù)。將圖像提供給視頻輸出后,可以解鎖緩沖區(qū), VPI 可以進(jìn)一步處理它。
概括
在本文中,我們向您展示了如何在 Jetson 產(chǎn)品系列上運(yù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í)計(jì)算機(jī)圖形學(xué)。
審核編輯:郭婷
-
嵌入式
+關(guān)注
關(guān)注
5150文章
19665瀏覽量
317459 -
gpu
+關(guān)注
關(guān)注
28文章
4944瀏覽量
131223 -
SDK
+關(guān)注
關(guān)注
3文章
1077瀏覽量
49078
發(fā)布評論請先 登錄
NVIDIA RTX AI加速FLUX.1 Kontext現(xiàn)已開放下載
NVIDIA推出全新硅光網(wǎng)絡(luò)交換機(jī)
如何降低AD5689R的輸出噪聲?
場效應(yīng)管驅(qū)動(dòng)電路設(shè)計(jì) 如何降低場效應(yīng)管的噪聲
傅立葉變換在圖像處理中的作用
哪些措施能降低電機(jī)的噪聲?
aic3254有沒有降低環(huán)境噪聲的算法?
高斯卷積核函數(shù)在圖像采樣中的意義
ivc102如何將噪聲降低到10mv以內(nèi)呢?
電源濾波器是如何降低電源噪聲的

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

降低TPS84259模塊的輸出紋波和噪聲

評論