【贈書】巨詳細!使用OpenCV和OpenVINO輕松創(chuàng)建深度學習應用
本文來自6月份出版的新書《OpenCV深度學習應用與性能優(yōu)化實踐》,作者團隊也是OpenCV DNN 模塊的主要貢獻者,是國內唯一的系統(tǒng)介紹OpenCV DNN 推理模塊原理和實踐的書,文末有福利,留言贈書。
OpenCV 是業(yè)界使用最為廣泛的計算機視覺庫,隨著深度學習在計算機視覺領域的廣泛應用,OpenCV 自3.3開始加入對深度學習推理的支持,即OpenCV DNN模塊。
它支持TensorFlow、Caffe、Torch、DarkNet、ONNX 和 OpenVINO 格式的網(wǎng)絡模型,開發(fā)者無需考慮模型格式的差異,直接調用DNN模塊相關接口即可快速創(chuàng)建深度學習應用。
OpenVINO是英特爾推出的視覺推理加速工具包。OpenCV 3.4.1版本加入了英特爾推理引擎后端(英特爾推理引擎是OpenVINO中的一個組件),為英特爾平臺的模型推理進行加速。
本文將以MobileNet-SSD模型為例,展示如何使用OpenCV和OpenVINO快速創(chuàng)建深度學習應用。
在深入代碼之前,讓我們了解一下OpenVINO工具包以及OpenCV是如何跟OpenVINO交互的。
OpenVINO工具包
2018 年 5 月 Intel 發(fā)布了 OpenVINO(Open Visual Inferencing and Neural Network Optimization, 開放視覺推理和神經(jīng)網(wǎng)絡優(yōu)化)工具包,旨在為運行于 Intel 計算平臺的基于神經(jīng)網(wǎng)絡的視覺推理任務提供高性能加速方案。
OpenVINO 提供了一整套在 Intel 計算設備上完成深度學習推理計算的解決方案,它支持 Intel CPU、 GPU、FPGA 和 Movidius 計算棒等多種設備。
OpenVINO 工具包的主要組件是 DLDT(Deep Learning Deployment Toolkit,深度學習部署工具包)。DLDT主要包括模型優(yōu)化器(Model Optimizer)和推理引擎(Inference engine,IE)兩部分。
模型優(yōu)化器負責將各種格式的深度神經(jīng)網(wǎng)絡模型轉換成統(tǒng)一的自定義格式,并在轉換過程中進行模型優(yōu)化;推理引擎接受經(jīng)過模型優(yōu)化器轉換并優(yōu)化的網(wǎng)絡模型,為Intel的各種計算設備提供高性能的神經(jīng)網(wǎng)絡推理運算。
使用 DLDT 進行神經(jīng)網(wǎng)絡模型的部署,典型工作流程如圖所示。

1)訓練一個DLDT 支持的深度學習框架網(wǎng)絡模型(Train a Model)?;
2)使用模型優(yōu)化器對網(wǎng)絡模型進行編譯和優(yōu)化(Run Model Optimizer),生成Openvino IR(Intermediate Representation,中間表示)格式的網(wǎng)絡配置文件(.xml 文件)和模型參數(shù)文件(.bin 文件);
3)調用 Inference Engine(即 Intel 推理引擎)進行網(wǎng)絡運算,并將結果返回給 User Application(應用程序)。
OpenCV如何使用OpenVINO
OpenCV的推理引擎后端使用OpenVINO的推理引擎API完成推理任務。推理引擎后端有兩種工作模式:模型優(yōu)化器模式和構建器模式,如下圖所示。
模型優(yōu)化器模式直接使用DLDT模型優(yōu)化器編譯后的OpenVINO格式(.xml和.bin)的網(wǎng)絡模型進行推理計算,這種模式下,網(wǎng)絡模型將被直接加載到推理引擎中,創(chuàng)建出一個推理引擎網(wǎng)絡對象。而構建器模式則需要在DNN模塊內部將網(wǎng)絡模型逐層轉換成內部表示,并通過推理引擎后端建立內部推理引擎網(wǎng)絡。
相比構建器模式,模型優(yōu)化器模式支持網(wǎng)絡中所有的層,不需要逐層建立DNN網(wǎng)絡,而是直接加載OpenVINO模型到推理引擎,能夠減少在網(wǎng)絡加載和運算推理過程中報錯的情況。
了解了OpenCV 和 OpenVINO 相關內容之后,接下來詳細講解如何基于OpenCV和OpenVINO構建深度學習應用。
基于OpenCV和OpenVINO創(chuàng)建深度學習應用
第一步:安裝OpenVINO
這里我們以 Ubuntu 18.04 上安裝 OpenVINO 為例。從官網(wǎng)注冊并下載OpenVINO開發(fā)包的Linux版本,
官網(wǎng)下載地址:
https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download/linux.html?
如果下載順利,你將得到文件名為 l_openvino_toolkit_p_< 版本號>.tgz 的壓縮包,為了兼容更多的網(wǎng)絡模型,我們選擇安裝目前最新的OpenVINO版本(OpenVINO-2020.3.194)。
OpenVINO開發(fā)包中包含了相應版本的OpenCV,安裝OpenVINO時會默認安裝OpenCV,因此無需額外安裝OpenCV。
1. 解壓并安裝 OpenVINO 開發(fā)包核心組件
$ tar -xvzf l_openvino_toolkit_p_2020.3.194.tgz$ cd l_openvino_toolkit_p_2020.3.194
運行圖形化安裝命令:
$ sudo ./install_GUI.sh然后一路選擇“Next”安裝默認組件即可。如果一切順利,安裝文件將位于/opt/intel/openvino_2020.3.194/,同時會生成一個符號鏈接/opt/intel/openvino 指向最新的安裝目錄。至此,OpenVINO 核心組件安裝完成,接下來安裝依賴包。
2. 安裝依賴包
使用 OpenVINO 寫一個完整的視覺類應用,除了 OpenVINO 本身之外,還需要安裝一些依賴包,包括但不限于 FFMpeg視頻框架、CMake 編譯工具、libusb(Movidius 神經(jīng)計算棒 插件需要用到)等,安裝步驟如下:
$ cd /opt/intel/openvino/install_dependencies運行以下命令安裝必要的依賴包:
$ sudo -E ./install_openvino_dependencies.sh設置環(huán)境變量:
$ source /opt/intel/openvino/bin/setupvars.sh建議將以上環(huán)境變量設置命令加入到用戶的環(huán)境腳本當中,方法如下:
$ vi <用戶目錄>/.bashrc在其中加入以內容:
$ source /opt/intel/openvino/bin/setupvars.sh按 Esc 鍵,然后輸入“:wq”保存并退出。接下來配置模型優(yōu)化器,依次運行以下命令:
$ cd /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites$ sudo ./install_prerequisites.sh
上面這條命令會安裝所有的深度學習框架的支持,如果只希望安裝某一個框架的支持,以安裝Caffe 框架支持為例,可以這么做:
$ sudo ./install_prerequisites_caffe.sh至此,安裝工作結束,下面驗證安裝好的 OpenVINO 環(huán)境是否可以工作。
3. 驗證 OpenVINO 環(huán)境
進入推理引擎示例程序目錄:
$ cd /opt/intel/openvino/deployment_tools/demo運行圖片分類示例程序的驗證腳本:
$ ./demo_squeezenet_download_convert_run.sh如果一切順利,輸出結果將如圖所示。

確保 OpenVINO 安裝成功后,重新啟動電腦:
$ reboot檢查OpenCV版本:
$ python> import cv2 as cv> print(cv.__version__)
如果安裝成功,可以看到如下輸出:
4.3.0-openvino-2020.3.0第二步:模型準備
首先下載MobileNet-SSD的caffe模型:
??模型參數(shù)文件MoblieNetSSD_deploy.caffemodel下載地址:https://drive.google.com/open?id=0B3gersZ2cHIxRm5PMWRoTkdHdHc
??網(wǎng)絡結構文件MoblieNetSSD_deploy.prototxt下載地址:https://raw.githubusercontent.com/chuanqi305/MobileNet-SSD/daef68a6c2f5fbb8c88404266aa28180646d17e0/MobileNetSSD_deploy.prototxt?
模型下載好后,將caffe模型轉換成OpenVINO格式:
1. 進入OpenVINO安裝目錄下的模型優(yōu)化器目錄:
cd /deployment_tools/model_optimizer 2. 使用OpenVINO模型優(yōu)化器腳本mo.py將caffe模型轉換成OpenVINO格式的模型:
python3 mo.py --input_model /MobileNetSSD_deploy.caffemodel --input_proto /MobileNetSSD_deploy.prototxt -o 通過input_model和input_proto 兩個參數(shù)指明模型的參數(shù)和結構,并指定轉換后網(wǎng)絡的存儲路徑。
通過這一步,我們可以得到OpenVINO格式的MobileNet-SSD網(wǎng)絡模型,包括MobileNetSSD_deploy.xml文件和MobileNetSSD_deploy.bin 文件。
第三步:使用OpenVINO模型進行目標檢測
接下來開始進入我們的最后一步,使用轉換好的OpenVINO格式的MobileNet-SSD模型進行實時目標檢測。下面是整個目標檢測過程的流程圖。
流程圖

程序代碼
為方便起見,我們采用Python語言來創(chuàng)建應用。首先導入必要的Python庫,包括numpy、argparse和cv2(OpenCV)。
# 導入必要的庫import numpy as npimport argparseimport cv2
接下來使用argparse對命令行輸入?yún)?shù)進行解析。
# 組建參數(shù)parseparser = argparse.ArgumentParser(description='Script to run MobileNet-SSD object detection network ')parser.add_argument("--video", help="path to video file. If empty, camera's stream will be used")parser.add_argument("--model", type=str, default="MobileNetSSD_deploy",help="path to trained model")parser.add_argument("--thr", default=0.2, type=float, help="confidence threshold to filter out weak detections")args = parser.parse_args()
程序執(zhí)行命令行只需輸入下列 3 個參數(shù)。
? video:圖片或視頻路徑,不設置則從攝像頭讀取數(shù)據(jù)。
? model:訓練好的模型路徑。
? thr:分類閾值。
定義一個變量classNames,存儲分類標簽。注意,我們下載的模型是基于20分類數(shù)據(jù)集訓練出來的,因此這里的類別標簽有20個(加上背景是21個)。也有針對90分類數(shù)據(jù)集訓練的模型,此處需要使用相對應的標簽定義。
# 類別標簽變量.classNames = { 0: 'background',1: 'aeroplane', 2: 'bicycle', 3: 'bird', 4: 'boat',5: 'bottle', 6: 'bus', 7: 'car', 8: 'cat', 9: 'chair',10: 'cow', 11: 'diningtable', 12: 'dog', 13: 'horse',14: 'motorbike', 15: 'person', 16: 'pottedplant',17: 'sheep', 18: 'sofa', 19: 'train', 20: 'tvmonitor' }
定義模型輸入大小,MobileNet-SSD接受的輸入圖片大小為300*300
input_size = (300, 300)接下來通過cv2.dnn.Net_readFromModelOptimizer()函數(shù)讀取轉換好的OpenVINO模型文件,初始化網(wǎng)絡對象 net,并設置加速后端:
# 加載模型net = cv2.dnn.Net_readFromModelOptimizer(args.model+".xml", args.model+".bin")# 設置推理引擎后端net.setPreferableBackend(cv2.dnn.DNN_BACKEND_INFERENCE_ENGINE)
注意,這里cv2.dnn.DNN_BACKEND_INFERENCE_ENGINE指明使用的是推理引擎后端。
# 設置運算設備net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)
推理引擎后端支持多種類型的運算設備,這里指定使用CPU作為運算設備。如果平臺有英特爾集成顯卡,也可以設置成cv2.dnn.DNN_TARGET_OPENCL,使用GPU來進行加速。
下一步設置圖像輸入設備,根據(jù)參數(shù)video選擇可用輸入設備或者輸入路徑:
# 打開視頻文件或攝像頭if args.video:cap = cv2.VideoCapture(args.video)else:cap = cv2.VideoCapture(0)
現(xiàn)在進入程序關鍵步驟,開始循環(huán)處理輸入設備讀到的幀圖像,將讀取到的圖像轉換成網(wǎng)絡輸入:
while True:# 讀取一幀圖像ret, frame = cap.read()# 將圖片轉換成模型輸入blob = cv2.dnn.blobFromImage(frame, 0.007843, input_size, (127.5, 127.5, 127.5), False)
這一步參數(shù)比較多,也比較重要,做一下重點講解:
1)frame是輸入圖像,0.007843是縮放因子,
2)input_size是模型所接受的輸入大小,(127.5, 127.5, 127.5)是圖像均值,它結合前面的縮放因子,在函數(shù)內部對輸入圖像做正規(guī)化處理。
3)False表示不進行R和B通道置換。當模型接受的通道順序和圖像均值的通道順序不一致時,swapRB 需要設置成 true。
接下來是設置網(wǎng)絡輸入和運行網(wǎng)絡推理:
# 轉換后的待輸入對象blob設置為網(wǎng)絡輸入net.setInput(blob)# 開始進行網(wǎng)絡推理運算detections = net.forward()
然后是結果解析。
MobileNet-SSD 模型的檢測結果detections是一個4維數(shù)組,數(shù)組的4個維度大小分別是[1,1,N,7]。
N表示檢測出的對象數(shù)目,7表示每個對象用一個含有7個元素的數(shù)組描述,7個元素分別代表圖片id、類型id、置信度、對象框左上角x坐標,對象框左下角y坐標、對象框右下角x坐標、對象框右下角y坐標,接下來根據(jù)這個4維數(shù)組繪制運行結果。
首先獲取圖像大小,根據(jù)再通過遍歷所有檢測出的對象,通過參數(shù)thr篩除部分置信度較低的對象:
cols = input_size[1]rows = input_size[0]for i in range(detections.shape[2]):confidence = detections[0, 0, i, 2]if confidence > args.thr:class_id = int(detections[0, 0, i, 1])
獲取被檢測對象框的頂點坐標和圖像的縮放比,并獲取實際目標對象框的坐標:
# 目標位置xLeftBottom = int(detections[0, 0, i, 3] * cols)yLeftBottom = int(detections[0, 0, i, 4] * rows)xRightTop = int(detections[0, 0, i, 5] * cols)yRightTop = int(detections[0, 0, i, 6] * rows)# 變換尺度heightFactor = frame.shape[0]/300.0widthFactor = frame.shape[1]/300.0# 獲取目標實際坐標xLeftBottom = int(widthFactor * xLeftBottom)yLeftBottom = int(heightFactor * yLeftBottom)xRightTop = int(widthFactor * xRightTop)yRightTop = int(heightFactor * yRightTop)
最后將檢測結果繪制到原始圖像上:
# 框出目標對象cv2.rectangle(frame, (xLeftBottom, yLeftBottom), (xRightTop, yRightTop),(0, 255, 0))# 標記標簽和置信度if class_id in classNames:label = classNames[class_id] + ": " + str(confidence)labelSize, baseLine = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)yLeftBottom = max(yLeftBottom, labelSize[1])cv2.rectangle(frame, (xLeftBottom, yLeftBottom - labelSize[1]),(xLeftBottom + labelSize[0], yLeftBottom + baseLine),(255, 255, 255), cv2.FILLED)cv2.putText(frame, label, (xLeftBottom, yLeftBottom),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0))print(label) # 輸出類別和置信度cv2.namedWindow("frame", cv2.WINDOW_NORMAL)cv2.imshow("frame", frame)key = cv2.waitKey(1) & 0xFFif key == ord("q"): # 按下q鍵退出程序breakif key == ord("s"): # 按下s鍵保存檢測圖像cv2.imwrite('detection.jpg', frame)
至此,整個目標檢測應用的代碼就完成了,接下來輸入以下命令運行目標檢測程序:
$ python mobilenet_ssd_python.py這里我們使用的默認參數(shù),通過攝像頭直接采集圖像,默認模型采用我們轉換好的MobileNetSSD_deploy(.xml/.bin)文件,閾值設為0.2。
這時候我們可以看到終端中將輸出檢測到的目標置信度,同時在視頻圖像中框處檢測到的目標,左上角為目標分類結果和分類置信度。
終端中的檢測結果輸出:
chair: 0.9978288chair: 0.29011992person: 0.9536861tvmonitor: 0.6713625tvmonitor: 0.26635352...
實際檢測圖像如下:

參考資料
[1] ?Ubuntu 安裝OpenVINO : https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html
[2] 《OpenCV深度學習應用與性能優(yōu)化實踐》
以上內容摘自本月剛剛出版的《OpenCV深度學習應用與性能優(yōu)化實踐》一書,經(jīng)出版方授權發(fā)布。

《OpenCV深度學習應用與性能優(yōu)化實踐》
作者:吳至文,郭葉軍,宗煒,李鵬,趙娟 著
這是國內唯一系統(tǒng)介紹OpenCV 深度學習推理原理與實踐的書,Intel與阿里巴巴高級圖形圖像專家聯(lián)合撰寫,深入解析OpenCV DNN 模塊、基于GPU/CPU的加速實現(xiàn)、性能優(yōu)化技巧與可視化工具,以及人臉活體檢測等應用,涵蓋Intel推理引擎加速等鮮見一手深度信息。
周末福利:本次聯(lián)合高端IT出版商【機械工業(yè)出版社華章公司】為大家?guī)?strong>1?本正版新書。在本文評論中回復談談你對OpenCV的學習體會,8月3日12點前,留言第一名的讀者將獲贈正版圖書1本。
也歡迎在以下鏈接直接購買:
在看,讓更多人看到 ?
