一文詳解OpenCV中的CUDA模塊
如果您使用OpenCV已有一段時間,那么您應(yīng)該已經(jīng)注意到,在大多數(shù)情況下,OpenCV都使用CPU,這并不總能保證您所需的性能。為了解決這個問題,OpenCV在2010年增加了一個新模塊,該模塊使用CUDA提供GPU加速。您可以在下面找到一個展示GPU模塊優(yōu)勢的基準(zhǔn)測試:
注1:文末附【CV】交流群
注2:整理不易,請點贊支持!
作者:天啦嚕 | 來源:3D視覺工坊微信公眾號

簡單列舉下本文要交代的幾個事情:
概述已經(jīng)支持CUDA的OpenCV模塊。
看一下cv :: gpu :: GpuMat(CV2.cuda_GpuMat)。
了解如何在CPU和GPU之間傳輸數(shù)據(jù)。
了解如何利用多個GPU。
編寫一個簡單的演示(C ++和Python),以了解OpenCV提供的CUDA API接口并計算我們可以獲得的性能提升。
一、支持的模塊
據(jù)稱,盡管并未涵蓋所有庫的功能,但該模塊“仍在繼續(xù)增長,并正在適應(yīng)新的計算技術(shù)和GPU架構(gòu)。”
讓我們看一下CUDA加速的OpenCV的官方文檔。在這里,我們可以看到已支持的模塊:
Core part
Operations on Matrices
Background Segmentation
Video Encoding/Decoding
Feature Detection and Description
Image Filtering
Image Processing
Legacy support
Object Detection
Optical Flow
Stereo Correspondence
Image Warping
Device layer
二、GpuMat
為了將數(shù)據(jù)保留在GPU內(nèi)存中,OpenCV引入了一個新的類cv :: gpu :: GpuMat(或Python中的CV2.cuda_GpuMat)作為主要數(shù)據(jù)容器。其界面類似于cv :: Mat(CV2.Mat),從而使向GPU模塊的過渡盡可能平滑。值得一提的是,所有GPU函數(shù)都將GpuMat接收為輸入和輸出參數(shù)。通過這種在代碼中鏈接了GPU算法的設(shè)計,您可以減少在CPU和GPU之間復(fù)制數(shù)據(jù)的開銷。
三、CPU/GUP數(shù)據(jù)傳遞
要將數(shù)據(jù)從GpuMat傳輸?shù)組at,反之亦然,OpenCV提供了兩個函數(shù):
上傳,將數(shù)據(jù)從主機(jī)內(nèi)存復(fù)制到設(shè)備內(nèi)存
下載,將數(shù)據(jù)從設(shè)備內(nèi)存復(fù)制到主機(jī)內(nèi)存。
以下是用C ++寫的一個簡單示例:
四、多個GPU的使用
默認(rèn)情況下,每種OpenCV CUDA算法都使用單個GPU。如果需要利用多個GPU,則必須在GPU之間手動分配工作。要切換活動設(shè)備,請使用cv :: cuda :: setDevice(CV2.cuda.SetDevice)函數(shù)。
五、代碼示例
OpenCV提供了有關(guān)如何使用C ++ API在GPU支持下與已實現(xiàn)的方法一起使用的示例。讓我們在使用Farneback的算法進(jìn)行密集光流計算的示例中,實現(xiàn)一個簡單的演示,演示如何將CUDA加速的OpenCV與C ++一起使用。
我們首先來看一下如何使用CPU來完成此操作。然后,我們將使用GPU進(jìn)行相同的操作。最后,我們將比較經(jīng)過的時間以計算獲得的加速比。
FPS計算
由于我們的主要目標(biāo)是找出算法在不同設(shè)備上的運(yùn)行速度,因此我們需要選擇測量方法。在計算機(jī)視覺中,這樣做的常用方法是計算每秒處理的幀數(shù)(FPS)。
CPU端
1.視頻及其屬性
我們將從視頻捕獲初始化開始,并獲取其屬性,例如幀頻和幀數(shù)。這部分是CPU和GPU部分的通用部分:
2.讀取第一幀
由于算法的特殊性,該算法使用兩幀進(jìn)行計算,因此我們需要先讀取第一幀,然后再繼續(xù)。還需要一些預(yù)處理,例如調(diào)整大小并轉(zhuǎn)換為灰度:
3.讀取并預(yù)處理其他幀
在循環(huán)讀取其余幀之前,我們啟動兩個計時器:一個計時器將跟蹤整個流程的工z作時間,第二個計時器–讀取幀時間。由于Farneback的光流法適用于灰度幀,因此我們需要確保將灰度視頻作為輸入傳遞。這就是為什么我們首先對其進(jìn)行預(yù)處理以將每幀從BGR格式轉(zhuǎn)換為灰度的原因。另外,由于原始分辨率可能太大,因此我們將其調(diào)整為較小的尺寸,就像對第一幀所做的一樣。我們再設(shè)置一個計時器來計算在預(yù)處理階段花費(fèi)的時間:
4.計算密集光流
我們使用稱為calcOpticalFlowFarneback的方法來計算兩幀之間的密集光流:
5.后處理
Farneback的“光流法“輸出二維流矢量。我們將這些輸出轉(zhuǎn)換為極坐標(biāo),以通過色相獲得流動的角度(方向),并通過HSV顏色表示的值獲得流動的距離(幅度)。對于可視化,我們現(xiàn)在要做的就是將結(jié)果轉(zhuǎn)換為BGR空間。之后,我們停止所有剩余的計時器以獲取經(jīng)過的時間:
6.可視化
我們將尺寸調(diào)整為960×540的原始幀可視化,并使用imshow函數(shù)顯示結(jié)果:
這是一個示例“ boat.mp4”視頻的內(nèi)容:

7.時間和FPS計算
我們要做的就是計算流程中每一步花費(fèi)的時間,并測量光流部分和整個流程的FPS:
GPU端
該算法在將其移至CUDA時保持不變,但在GPU使用方面存在一些差異。讓我們再次遍歷整個流程,看看有什么變化:
1.視頻及其屬性
此部分在CPU和GPU部分都是通用的,因此保持不變。
2.讀取第一幀
注意,我們使用相同的CPU函數(shù)來讀取和調(diào)整大小,但是將結(jié)果上傳到cv :: cuda :: GpuMat(cuda_GpuMat)實例:
3.讀取和預(yù)處理其它幀
4.計算密集光流
我們首先使用cv :: cuda :: FarnebackOpticalFlow :: create(CV2.cudaFarnebackOpticalFlow.create)創(chuàng)建cudaFarnebackOpticalFlow類的實例,然后調(diào)用cv :: cuda:FarnebackOpticalFlow :: calc(CV2.cuda_FarnebackOpticalFlow.calc)計算兩個幀之間的光流,而不是使用cv :: calcOpticalFlowFarneback(CV2.calcOpticalFlowFarneback)函數(shù)調(diào)用。
5.后處理
對于后處理,我們使用與CPU端使用的功能相同的GPU變體:
可視化、時間和FPS計算與CPU端相同。
結(jié)果
現(xiàn)在,我們可以在示例視頻中比較來自CPU和GPU版本的指標(biāo)。
我們用于CPU的配置為:
Intel Core i7-8700
Configuration
- device : cpu
- video file : video/boat.mp4
Number of frames: 320
Elapsed time
- full pipeline : 37.355 seconds
- reading : 3.327 seconds
- pre-process : 0.027 seconds
- optical flow : 32.706 seconds
- post-process : 0.641 seconds
Default video FPS : 29.97
Optical flow FPS : 9.75356
Full pipeline FPS : 8.53969
用于GPU的配置為:
Nvidia GeForce GTX 1080 Ti
Configuration
- device : gpu
- video file : video/boat.mp4
Number of frames: 320
Elapsed time
- full pipeline : 8.665 seconds
- reading : 4.821 seconds
- pre-process : 0.035 seconds
- optical flow : 1.874 seconds
- post-process : 0.631 seconds
Default video FPS : 29.97
Optical flow FPS : 170.224
Full pipeline FPS : 36.8148
當(dāng)我們使用CUDA加速時,這使光流計算的速度提高了約17倍!但是不幸的是,我們生活在現(xiàn)實世界中,并不是所有的流程階段都可以加速。因此,對于整個流程,我們只能獲得約4倍的加速。
總結(jié)
本文我們概述了GPU OpenCV模塊并編寫了一個簡單的演示,以了解如何加速Farneback的Optical Flow算法。我們研究了OpenCV為該模塊提供的API,您也可以重用該API來嘗試使用CUDA加速OpenCV算法。
備注:作者也是我們「3D視覺從入門到精通」知識星球特邀嘉賓:一個超干貨的3D視覺學(xué)習(xí)社區(qū)
本文僅做學(xué)術(shù)分享,如有侵權(quán),請聯(lián)系刪文。
3D視覺工坊-CV交流群
已建立3D視覺工坊-CV微信交流群!想要進(jìn)CV學(xué)習(xí)交流群的同學(xué),可以直接加微信號:CV_LAB。加的時候備注一下:CV+學(xué)校+昵稱,即可。然后就可以拉你進(jìn)群了。
強(qiáng)烈推薦大家關(guān)注3D視覺工坊知乎賬號和3D視覺工坊微信公眾號,可以快速了解到最新優(yōu)質(zhì)的3D視覺與SLAM論文。