使用opencv实现实例分割,一学就会|附源码
無論是從酒店房間接聽電話、在辦公里樓工作,還是根本不想在家庭辦公室等情況,電話會議模糊功能都可以讓會議與會者專注于自己,這樣的功能對于在家工作并希望保護其家庭成員隱私的人特別有用。
為了實現(xiàn)這樣的功能,微軟利用計算機視覺、深度學(xué)習(xí)以及實例分割技術(shù)實現(xiàn)。
在之前的博文中,介紹了如何利用YOLO以及OpenCV實現(xiàn)目標(biāo)檢測的功能,今天將采用Mask R-CNN來構(gòu)建視頻模糊功能。
使用OpenCV進行實例分割
https://youtu.be/puSN8Dg-bdI
在本教程的第一部分中,將簡要介紹實例分割;之后將使用實例分割和OpenCV來實現(xiàn):
- 從視頻流中檢測出用戶并分割;
- 模糊背景;
- 將用戶添加回流本身;
什么是實例分割?
圖1:對象檢測和實例分割之間的區(qū)別
如上圖所示,對于對象檢測(左圖,Object Detection)而言,在各個對象周圍繪制出一個框。 實例分割(右圖,Instance Segmentation)而言,是需要嘗試確定哪些像素屬于對應(yīng)的對象。通過上圖,可以清楚地看到兩者之間的差異。
執(zhí)行對象檢測時,是需要:
- 計算每個對象的邊界框(x,y的)-坐標(biāo);
- 然后將類標(biāo)簽與每個邊界框相關(guān)聯(lián);
從上可以看出,對象檢測并沒有告訴我們關(guān)于對象本身的形狀,而只獲得了一組邊界框坐標(biāo)。而另一方面,實例分割需要計算出一個逐像素掩模用于圖像中的每個對象。
即使對象具有相同的類標(biāo)簽,例如上圖中的兩只狗,我們的實例分割算法仍然報告總共三個獨特的對象:兩只狗和一只貓。
使用實例分割,可以更加細致地理解圖像中的對象——比如知道對象存在于哪個(x,y)坐標(biāo)中。此外,通過使用實例分割,可以輕松地從背景中分割前景對象。
本文使用Mask R-CNN進行實例分割。
項目結(jié)構(gòu)
項目樹:
$ tree --dirsfirst . ├── mask-rcnn-coco │?? ├── frozen_inference_graph.pb │?? ├── mask_rcnn_inception_v2_coco_2018_01_28.pbtxt │?? └── object_detection_classes_coco.txt └── instance_segmentation.py1 directory, 4 files項目包括一個目錄(由三個文件組成)和一個Python腳本:
-
mask-rcnn-coco/:Mask R-CNN模型目錄包含三個文件:
- frozen_inference_graph .pb:Mask R-CNN模型的權(quán)重,這些權(quán)重是在COCO數(shù)據(jù)集上預(yù)先訓(xùn)練所得到的;
- mask_rcnn_inception_v2_coco_2018_01_28 .pbtxt:Mask R-CNN模型的配置文件,如果你想在自己的數(shù)據(jù)集上構(gòu)建及訓(xùn)練自己的模型,可以參閱網(wǎng)上的一些資源更改該配置文件。
- object_detection_classes_coco.txt:此文本文件中列出了數(shù)據(jù)集中包含的90個類,每行表示一個類別。
- instance_segmentation .py:背景模糊腳本,本文的核心內(nèi)容, 將詳細介紹該代碼并評估其算法性能。
使用OpenCV實現(xiàn)實例分割
下面開始使用OpenCV實現(xiàn)實例分割。首先打開instance_segmentation .py文件并插入以下代碼:
# import the necessary packages from imutils.video import VideoStream import numpy as np import argparse import imutils import time import cv2 import os在開始編寫腳本時,首先需要導(dǎo)入必要的包,并且需要配置好編譯環(huán)境。本文使用的OpenCV版本為3.4.3。如果個人的計算機配置文件不同,需要對其進行更新。強烈建議將此軟件放在隔離的虛擬環(huán)境中,推薦使用conda安裝。
下面解析命令行參數(shù):
每個命令行參數(shù)的描述可以在下面找到:
- mask-rcnn:Mask R-CNN目錄的基本路徑;
- confidence:濾除弱檢測的最小概率,可以將此值的默認值設(shè)置為0.5,也可以通過命令行傳遞不同的值;
- threshold:像素掩碼分割的最小閾值,默認設(shè)置為 0.3;
- kernel:高斯模糊內(nèi)核的大小,默認設(shè)置41,這是通過實驗得到的經(jīng)驗值;
下面加載數(shù)據(jù)集的標(biāo)簽和OpenCV實例分割模型:
# load the COCO class labels our Mask R-CNN was trained on labelsPath = os.path.sep.join([args["mask_rcnn"],"object_detection_classes_coco.txt"]) LABELS = open(labelsPath).read().strip().split("\n")# derive the paths to the Mask R-CNN weights and model configuration weightsPath = os.path.sep.join([args["mask_rcnn"],"frozen_inference_graph.pb"]) configPath = os.path.sep.join([args["mask_rcnn"],"mask_rcnn_inception_v2_coco_2018_01_28.pbtxt"])# load our Mask R-CNN trained on the COCO dataset (90 classes) # from disk print("[INFO] loading Mask R-CNN from disk...") net = cv2.dnn.readNetFromTensorflow(weightsPath, configPath)標(biāo)簽文件位于mask-rcnn - coco目錄,指定好路徑后就可以加載標(biāo)簽文件了。同樣地, weightsPath和configPath也執(zhí)行類型的操作。
基于這兩個路徑,利用dnn模塊初始化神經(jīng)網(wǎng)絡(luò)。在開始處理視頻幀之前,需要將Mask R-CNN加載到內(nèi)存中(只需要加載一次)。
下面構(gòu)建模糊內(nèi)核并啟動網(wǎng)絡(luò)攝像頭視頻流:
模糊內(nèi)核元組也通過行命令設(shè)定。此外,項目有兩種模式:“正常模式”和“隱私模式”。因此, 布爾值privacy用于模式邏輯,上述代碼將其初始化為False。
網(wǎng)絡(luò)攝像頭視頻流用VideoStream(src=0).start(),首先暫停兩秒鐘以讓傳感器預(yù)熱。
初始化了所有變量和對象后,就可以從網(wǎng)絡(luò)攝像頭開始處理幀了:
在每次迭代中,將抓取一幀并將其調(diào)整為設(shè)定的寬度,同時保持縱橫比。此外,為了之后的縮放操作,繼續(xù)并提取幀的尺寸。然后,構(gòu)建一個blob并完成前向傳播網(wǎng)絡(luò)。
結(jié)果輸出是boxes和masks,雖然需要用到掩碼(mask),但還需要使用邊界框(boxes)中包含的數(shù)據(jù)。
下面對索引進行排序并初始化變量:
通過其對應(yīng)的預(yù)測概率對邊界框的索引進行排序,假設(shè)具有最大相應(yīng)檢測概率的人是我們的用戶。然后初始化mask、roi以及邊界框的坐標(biāo)。
遍歷索引并過濾結(jié)果:
從idxs開始循環(huán),然后,使用框和當(dāng)前索引提取classID和 置信度。隨后,執(zhí)行第一個過濾器—— “人”。如果遇到任何其他對象類,繼續(xù)下一個索引。下一個過濾器確保預(yù)測的置信度超過通過命令行參數(shù)設(shè)置的閾值。
如果通過了該測試,那么將邊界框坐標(biāo)縮放回圖像的相對尺寸,然后提取坐標(biāo)和對象的寬度/高度。
計算掩膜并提取ROI:
上述代碼首先提取掩碼,并調(diào)整其大小,之后應(yīng)用閾值來創(chuàng)建二進制掩碼本身。示例如下圖所示:
圖2:使用OpenCV和實例分割在網(wǎng)絡(luò)攝像頭前通過實例分割計算的二進制掩碼
從上圖中可以看到,假設(shè)所有白色像素都是人(即前景),而所有黑色像素都是背景。使用掩碼后,通過NumPy陣列切片計算roi。之后循環(huán)斷開,這是因為你找到最大概率的人了。
如果處于“隱私模式”,需要進行初始化輸出幀并計算模糊: # initialize our output frameoutput = frame.copy()# if the mask is not None *and* we are in privacy mode, then we# know we can apply the mask and ROI to the output imageif mask is not None and privacy:# blur the output frameoutput = cv2.GaussianBlur(output, K, 0)# add the ROI to the output frame for only the masked region(startX, startY, endX, endY) = coordsoutput[startY:endY, startX:endX][mask] = roi
其輸出幀只是原始幀的副本。
如果我們倆都:
- 有一個非空的掩膜;
- 處于“ 隱私模式”;
- ... ...
然后將使用模糊背景并將掩碼應(yīng)用于輸出幀。
下面顯示輸出以及圖像處理按鍵:
keypresses被獲取其值,有兩個值可供選擇,但會導(dǎo)致不同的行為:
- “p”:按下此鍵時, 打開或關(guān)閉“ 隱私模式”;
- “q”:如果按下此鍵,將跳出循環(huán)并“退出”腳本;
每當(dāng)退出時,上述代碼就會關(guān)閉打開的窗口并停止視頻流。
實例分割結(jié)果
現(xiàn)在已經(jīng)實現(xiàn)了OpenCV實例分割算法,下面看看其實際應(yīng)用!
打開一個終端并執(zhí)行以下命令:
圖3:演示了一個用于網(wǎng)絡(luò)聊天的“隱私過濾器”
通過啟用“隱私模式”,可以:
- 使用OpenCV實例分割查找具有最大相應(yīng)概率的人物檢測(最可能是最接近相機的人);
- 模糊視頻流的背景;
- 將分割的、非模糊的人重疊到視頻流上;
下面列出一個視頻演示(需外網(wǎng)):
https://youtu.be/puSN8Dg-bdI
看完視頻會立即注意到,并沒有獲得真正的實時性能——每秒只處理幾幀。為什么是這樣?
要回答這些問題,請務(wù)必參考以下部分。
限制、缺點和潛在的改進
第一個限制是最明顯的——OpenCV實例分割的實現(xiàn)太慢而無法實時運行。在CPU上運行,每秒只能處理幾幀。為了獲得真正的實時實例分割性能,需要利用到GPU。
但其中存在的問題是:
- OpenCV對其dnn模塊的GPU支持相當(dāng)有限;
- 目前,它主要支持英特爾GPU;
- NVIDIA CUDA GPU支持正在開發(fā)中,但目前尚未推出;
一旦OpenCV正式支持dnn模塊的NVIDIA GPU版本, 就能夠更輕松地構(gòu)建實時(甚至超實時)的深度學(xué)習(xí)應(yīng)用程序。但就目前而言,本文的實例分割教程只作為演示:
此外,也可以做出的另一項改進與分割的人重疊在模糊的背景上有關(guān)。當(dāng)將本文的實現(xiàn)與Microsoft的Office 365視頻模糊功能進行比較時,就會發(fā)現(xiàn)Microsoft會更加“流暢”。但也可以通過利用一些alpha混合來模仿這個功能。
對實例分割管道進行簡單而有效的更新可能是:
- 使用形態(tài)學(xué)操作來增加蒙版的大小;
- 在掩膜本身涂抹少量高斯模糊,幫助平滑掩碼;
- 將掩碼值縮放到范圍[0,1];
- 使用縮放蒙版創(chuàng)建alpha圖層;
- 在模糊的背景上疊加平滑的掩膜+人;
或者,也可以計算掩膜本身的輪廓,然后應(yīng)用掩膜近似來幫助創(chuàng)建“更平滑”的掩碼。
總結(jié)
看完本篇文章,你應(yīng)該學(xué)習(xí)了如何使用OpenCV、Deep Learning和Python實現(xiàn)實例分割了吧。實例分割大體過程如下:
- 檢測圖像中的每個對象;
- 計算每個對象的逐像素掩碼;
注意,即使對象屬于同一類,實例分割也應(yīng)為每個對象返回唯一的掩碼;
作者信息
Adrian Rosebrock ,機器學(xué)習(xí),人工智能,圖像處理
本文由阿里云云棲社區(qū)組織翻譯。?
文章原標(biāo)題《Instance segmentation with OpenCV》,譯者:海棠,審校:Uncle_LLD。?
文章為簡譯,更為詳細的內(nèi)容,請查看原文。
總結(jié)
以上是生活随笔為你收集整理的使用opencv实现实例分割,一学就会|附源码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设计模式-创建型模式-建造者模式
- 下一篇: 火眼金睛算法,教你海量短文本场景下去重