巨詳細!使用OpenCV和OpenVINO輕鬆創建深度學習應用
CV君:本文來自6月份出版的新書 《 OpenCV深度學習應用與性能優化實踐 》 ,作者團隊也是OpenCV DNN 模塊的主要貢獻者,是國內唯一的系統介紹OpenCV DNN 推理模塊原理和實踐的書,文末有福利,留言贈書 8 本。
OpenCV 是業界使用最爲廣泛的計算機視覺庫,隨着深度學習在計算機視覺領域的廣泛應用,OpenCV 自3.3開始加入對深度學習推理的支持,即OpenCV DNN模塊。
它支持TensorFlow、Caffe、Torch、DarkNet、ONNX 和 OpenVINO 格式的網絡模型,開發者無需考慮模型格式的差異,直接調用DNN模塊相關接口即可快速創建深度學習應用。
OpenVINO是英特爾推出的視覺推理加速工具包。OpenCV 3.4.1版本加入了英特爾推理引擎後端(英特爾推理引擎是OpenVINO中的一個組件),爲英特爾平臺的模型推理進行加速。
本文將以MobileNet-SSD模型爲例,展示如何使用OpenCV和OpenVINO快速創建深度學習應用。
在深入代碼之前,讓我們瞭解一下OpenVINO工具包以及OpenCV是如何跟OpenVINO交互的。
OpenVINO工具包
2018 年 5 月 Intel 發佈了 OpenVINO(Open Visual Inferencing and Neural Network Optimization, 開放視覺推理和神經網絡優化)工具包,旨在爲運行於 Intel 計算平臺的基於神經網絡的視覺推理任務提供高性能加速方案。
OpenVINO 提供了一整套在 Intel 計算設備上完成深度學習推理計算的解決方案,它支持 Intel CPU、 GPU、FPGA 和 Movidius 計算棒等多種設備。
OpenVINO 工具包的主要組件是 DLDT(Deep Learning Deployment Toolkit,深度學習部署工具包)。DLDT主要包括模型優化器(Model Optimizer)和推理引擎(Inference engine,IE)兩部分。
模型優化器負責將各種格式的深度神經網絡模型轉換成統一的自定義格式,並在轉換過程中進行模型優化;推理引擎接受經過模型優化器轉換並優化的網絡模型,爲Intel的各種計算設備提供高性能的神經網絡推理運算。
使用 DLDT 進行神經網絡模型的部署,典型工作流程如圖所示。
1)訓練一個DLDT 支持的深度學習框架網絡模型(Train a Model) ;
2)使用模型優化器對網絡模型進行編譯和優化(Run Model Optimizer),生成Openvino IR(Intermediate Representation,中間表示)格式的網絡配置文件(.xml 文件)和模型參數文件(.bin 文件);
3)調用 Inference Engine(即 Intel 推理引擎)進行網絡運算,並將結果返回給 User Application(應用程序)。
OpenCV如何使用OpenVINO
OpenCV的推理引擎後端使用OpenVINO的推理引擎API完成推理任務。推理引擎後端有兩種工作模式:模型優化器模式和構建器模式,如下圖所示。
模型優化器模式直接使用DLDT模型優化器編譯後的OpenVINO格式(.xml和.bin)的網絡模型進行推理計算,這種模式下,網絡模型將被直接加載到推理引擎中,創建出一個推理引擎網絡對象。而構建器模式則需要在DNN模塊內部將網絡模型逐層轉換成內部表示,並通過推理引擎後端建立內部推理引擎網絡。
相比構建器模式,模型優化器模式支持網絡中所有的層,不需要逐層建立DNN網絡,而是直接加載OpenVINO模型到推理引擎,能夠減少在網絡加載和運算推理過程中報錯的情況。
瞭解了OpenCV 和 OpenVINO 相關內容之後,接下來詳細講解如何基於OpenCV和OpenVINO構建深度學習應用。
基於OpenCV和OpenVINO創建深度學習應用
第一步:安裝OpenVINO
這裏我們以 Ubuntu 18.04 上安裝 OpenVINO 爲例。從官網註冊並下載OpenVINO開發包的Linux版本,
官網下載地址:
https://software.intel.com/content/www/us/en/develop/tools/openvino-toolkit/choose-download/linux.html
如果下載順利,你將得到文件名爲 l_openvino_toolkit_p_< 版本號>.tgz 的壓縮包,爲了兼容更多的網絡模型,我們選擇安裝目前最新的OpenVINO版本(OpenVINO-2020.3.194)。
OpenVINO開發包中包含了相應版本的OpenCV,安裝OpenVINO時會默認安裝OpenCV,因此無需額外安裝OpenCV 。
1. 解壓並安裝 OpenVINO 開發包核心組件
$ 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 神經計算棒 插件需要用到)等,安裝步驟如下:
$ cd /opt/intel/openvino/install_dependencies
運行以下命令安裝必要的依賴包:
$ sudo -E ./install_openvino_dependencies.sh
設置環境變量:
$ source /opt/intel/openvino/bin/setupvars.sh
建議將以上環境變量設置命令加入到用戶的環境腳本當中,方法如下:
$ vi <用戶目錄>/.bashrc
在其中加入以內容:
$ source /opt/intel/openvino/bin/setupvars.sh
按 Esc 鍵,然後輸入“:wq”保存並退出。接下來配置模型優化器,依次運行以下命令:
$ cd /opt/intel/openvino/deployment_tools/model_optimizer/install_prerequisites
$ sudo ./install_prerequisites.sh
上面這條命令會安裝所有的深度學習框架的支持,如果只希望安裝某一個框架的支持,以安裝Caffe 框架支持爲例,可以這麼做:
$ sudo ./install_prerequisites_caffe.sh
至此,安裝工作結束,下面驗證安裝好的 OpenVINO 環境是否可以工作。
3. 驗證 OpenVINO 環境
進入推理引擎示例程序目錄:
$ 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模型:
• 模型參數文件MoblieNetSSD_deploy.caffemodel下載地址: https://drive.google.com/open?id=0B3gersZ2cHIxRm5PMWRoTkdHdHc
• 網絡結構文件MoblieNetSSD_deploy.prototxt下載地址: https://raw.githubusercontent.com/chuanqi305/MobileNet-SSD/daef68a6c2f5fbb8c88404266aa28180646d17e0/MobileNetSSD_deploy.prototxt
模型下載好後,將caffe模型轉換成OpenVINO格式:
1. 進入OpenVINO安裝目錄下的模型優化器目錄:
cd <INSTALL_DIR>/deployment_tools/model_optimizer
2. 使用OpenVINO模型優化器腳本mo.py將caffe模型轉換成OpenVINO格式的模型:
python3 mo.py --input_model <working_dir>/MobileNetSSD_deploy.caffemodel --input_proto <working_dir>/MobileNetSSD_deploy.prototxt -o <output_path>
通過input_model和input_proto 兩個參數指明模型的參數和結構,並指定轉換後網絡的存儲路徑。
通過這一步,我們可以得到OpenVINO格式的MobileNet-SSD網絡模型,包括MobileNetSSD_deploy.xml文件和MobileNetSSD_deploy.bin 文件。
第三步:使用OpenVINO模型進行目標檢測
接下來開始進入我們的最後一步,使用轉換好的OpenVINO格式的MobileNet-SSD模型進行實時目標檢測。下面是整個目標檢測過程的流程圖。
流程圖
程序代碼
爲方便起見,我們採用Python語言來創建應用。首先導入必要的Python庫,包括numpy、argparse和cv2(OpenCV)。
# 導入必要的庫
import numpy as np
import argparse
import cv2
接下來使用argparse對命令行輸入參數進行解析。
# 組建參數parse
parser = 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()
程序執行命令行只需輸入下列 3 個參數。
• video:圖片或視頻路徑,不設置則從攝像頭讀取數據。
• model:訓練好的模型路徑。
• thr:分類閾值。
定義一個變量classNames,存儲分類標籤。注意,我們下載的模型是基於20分類數據集訓練出來的,因此這裏的類別標籤有20個(加上背景是21個)。也有針對90分類數據集訓練的模型,此處需要使用相對應的標籤定義。
# 類別標籤變量.
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()函數讀取轉換好的OpenVINO模型文件,初始化網絡對象 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來進行加速。
下一步設置圖像輸入設備,根據參數video選擇可用輸入設備或者輸入路徑:
# 打開視頻文件或攝像頭
if args.video:
cap = cv2.VideoCapture(args.video)
else:
cap = cv2.VideoCapture(0)
現在進入程序關鍵步驟,開始循環處理輸入設備讀到的幀圖像,將讀取到的圖像轉換成網絡輸入:
while True:
# 讀取一幀圖像
ret, frame = cap.read()
# 將圖片轉換成模型輸入
blob = cv2.dnn.blobFromImage(frame, 0.007843, input_size, (127.5, 127.5, 127.5), False)
這一步參數比較多,也比較重要,做一下重點講解:
1)frame是輸入圖像,0.007843是縮放因子,
2)input_size是模型所接受的輸入大小,(127.5, 127.5, 127.5)是圖像均值,它結合前面的縮放因子,在函數內部對輸入圖像做正規化處理。
3)False表示不進行R和B通道置換。當模型接受的通道順序和圖像均值的通道順序不一致時,swapRB 需要設置成 true。
接下來是設置網絡輸入和運行網絡推理:
# 轉換後的待輸入對象blob設置爲網絡輸入
net.setInput(blob)
# 開始進行網絡推理運算
detections = net.forward()
然後是結果解析。
MobileNet-SSD 模型的檢測結果detections是一個4維數組,數組的4個維度大小分別是[1,1,N,7]。
N表示檢測出的對象數目,7表示每個對象用一個含有7個元素的數組描述,7個元素分別代表圖片id、類型id、置信度、對象框左上角x座標,對象框左下角y座標、對象框右下角x座標、對象框右下角y座標,接下來根據這個4維數組繪製運行結果。
首先獲取圖像大小,根據再通過遍歷所有檢測出的對象,通過參數 thr 篩除部分置信度較低的對象:
# 獲取輸入圖像尺寸(300x300)
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: # Filter prediction
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.0
widthFactor = 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) & 0xFF
if key == ord("q"): # 按下q鍵退出程序
break
if key == ord("s"): # 按下s鍵保存檢測圖像
cv2.imwrite('detection.jpg', frame)
至此,整個目標檢測應用的代碼就完成了,接下來輸入以下命令運行目標檢測程序:
$ python mobilenet_ssd_python.py
這裏我們使用的默認參數,通過攝像頭直接採集圖像,默認模型採用我們轉換好的MobileNetSSD_deploy(.xml/.bin)文件,閾值設爲0.2。
這時候我們可以看到終端中將輸出檢測到的目標置信度,同時在視頻圖像中框處檢測到的目標,左上角爲目標分類結果和分類置信度。
終端中的檢測結果輸出:
chair: 0.9978288
chair: 0.29011992
person: 0.9536861
tvmonitor: 0.6713625
tvmonitor: 0.26635352
...
實際檢測圖像如下:
參考資料
[1] Ubuntu 安裝OpenVINO : https://docs.openvinotoolkit.org/latest/_docs_install_guides_installing_openvino_linux.html
[2] 《OpenCV深度學習應用與性能優化實踐》
以上內容摘自本月剛剛出版的《 OpenCV深度學習應用與性能優化實踐 》一書,經出版方授權發佈。
《OpenCV深度學習應用與性能優化實踐》
作者:吳至文,郭葉軍,宗煒,李鵬,趙娟 著
這本書CV君作序推薦!這是國內唯一系統介紹OpenCV 深度學習推理原理與實踐的書, Intel與阿里巴巴高級圖形圖像專家聯合撰寫,深入解析OpenCV DNN 模塊、基於GPU/CPU的加速實現、性能優化技巧與可視化工具,以及人臉活體檢測等應用,涵蓋Intel推理引擎加速等 鮮見一手 深度信息。
端午福利: 本次聯合高端IT出版商【機械工業出版社華章公司】爲大家帶來
8 本正版新書。在本文評論中回覆 談談你對OpenCV的學習體會 , 6月29日17 點前,留言 最走心對大家最有幫助的 (由CV君確定) 8 名的讀者將獲贈正版圖書1本(在其他活動中已獲贈本書者,重複參加無效)。
也歡迎在以下鏈接直接購買:
備註:OpenCV
OpenCV交流羣
關注最新最前沿的OpenCV學習技術,
若已爲CV君其他賬號好友請直接私信。
我愛計算機視覺
在看,讓更多人看到