愷明大神 Mask R-CNN 超實用教程

2021-03-06 機器學習算法與Python學習


原標題 | Mask R-CNN with OpenCV翻 譯 | 天字一號(鄭州大學)、李美麗(華南師範大學)、had_in(電子科技大學)、nengdaiper(北京科技大學)在此教程中,你將學習如何在opencv中使用Mask R-CNN。使用Mask R-CNN,你可以自動分割和構建圖像中每個對象的像素級MASK。我們將應用Mask R-CNN到圖像和視頻流。在上周的博客文章中,你學習了如何使用Yolo物體探測器來檢測圖像中物體(https://www.pyimagesearch.com/2018/11/12/yolo-object-detection-with-opencv/)。對象檢測器,如yolo、faster r-cnn和ssd,生成四組(x,y)坐標,表示圖像中對象的邊界框。從獲取對象的邊界框開始挺好的,但是邊界框本身並不能告訴我們(1)哪些像素屬於前景對象,(2)哪些像素屬於背景。是否可以為圖像中的每個對象生成一個MASK,從而允許我們從背景分割前景對象?答案是肯定的:我們只需要使用Mask R-CNN架構執行實例分割。要了解如何利用opencv的Mask R-CNN應用於圖像和視頻流,繼續看下去吧!正在查找此博客的原始碼?直接跳到下載(https://www.pyimagesearch.com/2018/11/19/mask-r-cnn-with-opencv/#)。在本教程的第一部分中,我們將討論圖像分類、對象檢測、實例分割和語義分割之間的區別。 
這裡,我們將簡要回顧Mask R-CNN架構及其與Faster R-CNN的關係。然後,我將向您展示如何在圖像和視頻流上應用Mask R-CNN與OpenCV。圖1:圖像分類(左上),目標檢測(右上),語義分割(左下),實例分割(右下)。在本教程中,我們將使用Mask R-CNN執行實例分割。(來源:https://arxiv.org/abs/1704.06857)解釋傳統的圖像分類、目標檢測、語義分割和實例分割之間的區別,最好是用可視化方法。在執行傳統的圖像分類時,我們的目標是預測一組標籤來表示輸入圖像的內容(左上角)。  目標檢測建立在圖像分類的基礎上,但這一次需要我們對圖像中每個對象定位。圖像的表徵如下:

每個目標邊界框的坐標(x, y) 

每個邊界框關聯的類別標籤  

左下角是一個語義分割的例子。語義分割算法要求我們將輸入圖像中的每個像素與一個類別標籤(包括一個用於背景的類標籤)關聯起來。注意關注我們語義分割的可視化——注意每個目標是如何分割的,但每個「cube」目標都有相同的顏色。  雖然語義分割算法能夠對圖像中的所有目標進行標記,但它們無法區分同一類的兩個對象。  特別是同一個類別的兩個目標是相互遮擋時,問題更加明顯,我們不知道一個對象的邊界在哪裡結束以及哪裡開始,如圖上兩個紫色立方體所示,我們無法說清楚一個立方體邊界的開始和結束。另一方面,實例分割算法為圖像中的每個對象計算像素級mask,即使對象具有相同的類別標籤(右下角)。在這裡,您可以看到每個立方體都有自己獨特的顏色,這意味著我們的實例分割算法不僅定位了每個獨立的立方體,而且還預測了它們的邊界。  而在本教程,我們將要討論的Mask R-CNN架構就是一個實例分割算法的示例。Mask R-CNN算法是何凱明等人在2017年發表的論文中提出的,Mask R-CNN(https://arxiv.org/abs/1703.06870)。  Mask R-CNN是基於之前的目標檢測工作R-CNN(2013)、Fast R-CNN(2015)、Faster R-CNN(2015),均由Girshick等人完成。  
為了理解Mask R-CNN,讓我們簡要回顧一下R-CNN的變體,從原始的R-CNN開始:  
圖2:初始的R-CNN架構(來源:Girshick等人,2013)  步驟2:提取區域proposals(即,可能包含對象的圖像區域)算法,如選擇性搜索算法(http://www.huppelen.nl/publications/selectiveSearchDraft.pdf)。步驟3:利用遷移學習進行特徵提取,使用預先訓練的CNN計算每個proposals的特徵(這實際上是一個ROI)。  步驟4:使用支持向量機(SVM)對提取的特徵進行分類。 這種方法之所以有效,是因為CNN學習的特徵的魯棒性和可鑑別性。  然而,R-CNN方法的問題在於它非常慢。此外,我們實際上並沒有學習如何通過深度神經網絡進行定位,我們只是在有效地構建一個更高級的HOG +線性SVM檢測器(https://www.pyimagesearch.com/2014/11/10/histogram-oriented-gradients-object-detection/)。為了改進原有的R-CNN, Girshick等人發表了Fast R-CNN算法:圖3:Fast R-CNN架構(來源:Girshick et al., 2015)。 與原始的R-CNN相似,Fast R-CNN仍然使用選擇性搜索來獲取區域建議;然而,本文的新貢獻是感興趣區域(ROI)池化模塊。ROI池化的工作原理是從特徵map中提取一個固定大小的窗口,並使用這些特徵獲得最終的類別標籤和邊界框。這樣做主要好處是,網絡現在可以有效地端到端地進行訓練:

我們輸入一個圖像和對應的實際的邊界框  

提取圖像的特徵map

應用ROI池化,得到ROI特徵向量  

最後, 使用兩組全連接層來獲得(1)類別標籤預測(2)每個proposal的邊框位置。 

雖然網絡現在是可以端到端訓練的,但是由於依賴於選擇性搜索算法,在推斷時性能仍受到了極大的影響。為了使R-CNN的架構更快,我們需要直接利用R-CNN獲得區域proposal:圖4:Faster R-CNN架構(來源:Girshick et al., 2015)  Girshick等人的Faster R-CNN論文將 區域proposals網絡(RPN)引入到神經網絡架構中,減少了對選擇性搜索算法的需求。總的來說,Faster R-CNN架構能夠以大約7-10幀每秒的速度運行,這是通過深度學習實現實時目標檢測的一大進步。  Mask R-CNN算法建立在Faster R-CNN架構的基礎之上,主要有兩個貢獻:

用更精確的ROI align模塊替換ROI Pooling模塊  

從ROI align模塊中插入一個額外的分支  

這個額外的分支的輸入為ROI align模塊的輸出,然後將其輸入到兩個CONV層。我們可以將Mask R-CNN架構可視化如下圖所示:圖5:He等人的Mask R-CNN工作用一個更精確的ROI align模塊替換ROI Polling模塊。然後將ROI模塊的輸出送入兩個CONV層。CONV層的輸出即是掩摸(mask)本身。 注意兩個CONV層的分支來自ROI Align模塊——我們實際生成掩摸由該模塊生成。 我們知道,Faster R-CNN/Mask R-CNN架構利用區域proposal網絡(RPN)生成可能包含對象的圖像區域。這些區域都是根據它們的「可能是目標的評分」(即,給定區域可能包含目標的可能性),然後保留最可能的前N個目標區域。  在原來Faster R-CNN論文中,Girshick等人設置N= 2000,但在實踐中,我們可以用一個小得多的N,比如N={10,100, 200,300},仍然可以得到很好的結果。He等人在他們的論文(https://arxiv.org/abs/1703.06870)中設置N=300,這也是我們這裡使用的值。 所選的300個ROIs中的每一個都要經過網絡的三個並行分支: 

類別標籤預測

邊界框預測

掩摸預測

在預測時,300個ROIs都會經過非極大值抑制算法(https://www.pyimagesearch.com/2014/11/17/non-maximum-suppression-object-detection-python/),然後僅保存可能性前100的檢測框,使得最終得到一個四維的100 x L x 15 x 15張量,L為數據幾種類別標籤的數量,15 x 15是每個類別L的掩摸(mask)的大小。 我們今天使用的掩模R-CNN是在COCO數據集上訓練的(http://cocodataset.org/#home),它有L=90個類,因此掩模R CNN掩模模塊的最終體積大小是100 x 90 x 15 x 15。 圖6:Mask R-CNN過程的可視化,先生成一個15 x 15的掩摸,遮罩改變到圖像的原始尺寸,最後將掩摸覆蓋到原始圖像上。(來源:Python深度學習計算機視覺,ImageNet Bundle) 這裡你可以看到,我們從我們的輸入圖像開始,並通過我們的Mask R-CNN網絡,最終獲得我們的掩摸預測。預測的掩模只有15 x 15的像素,因此我們將掩模的大小調整回原始輸入圖像的尺寸。  最後,調整大小後的掩模可以覆蓋在原始輸入圖像上。要了解更多關於Mask R-CNN工作原理的詳細討論,請參考:  

由何等人發表的Mask R-CNN論文(https://arxiv.org/abs/1703.06870)

我的書, Deep Learning for Computer Vision with Python(https://www.pyimagesearch.com/deep-learning-computer-vision-python-book/),在這本書裡,我將更詳細地討論Mask R-CNNs,包括如何根據自己的數據從零開始訓練自己的Mask R-CNNs。 

我們今天的項目主要由兩個腳本組成,還有其他幾個重要的文件。  我已經按照如下方式構建了這個項目(直接在終端上的tree命令輸出):  基於OpenCV的Mask R-CNN----Shell

$ tree.├── mask-rcnn-coco│   ├── colors.txt│   ├── frozen_inference_graph.pb│   ├── mask_rcnn_inception_v2_coco_2018_01_28.pbtxt│   └── object_detection_classes_coco.txt├── images│   ├── example_01.jpg│   ├── example_02.jpg│   └── example_03.jpg├── videos│   ├──├── output│   ├──├── mask_rcnn.py└── mask_rcnn_video.py 4 directories, 9 files

mask-rcnn-coco/ : Mask R-CNN的模型文件。有四個文件: 

frozen_inference_graph.pb : Mask R-CNN模型的權重文件,是基於COCO數據集上預訓練的權重。 

mask_rcnn_inception_v2_coco_2018_01_28.pbtxt :  Mask R-CNN模型的配置文件。如果你想在你自己的標註的數據上建立並訓練你自己的模型,  參考 Deep Learning for Computer Vision with Python(https://www.pyimagesearch.com/deep-learning-computer-vision-python-book/).

object_detection_classes_coco.txt : 所有90個類別都列在這個文本文件中,每行一個。在文本編輯器中打開它,查看模型可以識別哪些對象。 

colors.txt : 這個文本文件包含六種顏色,可以隨機分配給圖像中檢測到的目標。 

images/ : 我在「Downloads」中提供了三個測試圖像。請隨意添加您自己的圖像進行測試 

videos/ : 這是一個空目錄。實際上,我用從YouTube上搜集的大型視頻進行了測試(Credits下面,就在「Summary」部分的上面)。我更傾向於建議您可以在YouTube上找到一些視頻下載並測試,而不是提供一個真正大的zip文件。或者用你的手機拍一些視頻,然後回到你的電腦前使用它們!

output/ :另一個空目錄,將保存處理過的視頻(假設您將命令行參數設置為輸出到此目錄)。 

現在,我們已經回顧了Mask R-CNNs的工作原理,讓我們動手寫一些Python代碼。  在開始之前,請確保您的Python環境已經安裝了OpenCV 3.4.2/3.4.3或更高版本。您可以按照我的OpenCV安裝教程(https://www.pyimagesearch.com/opencv-tutorials-resources-guides/)來升級/安裝OpenCV。如果您想在5分鐘或更短的時間內啟動和運行,可以考慮使用pip安裝OpenCV(https://www.pyimagesearch.com/2018/09/19/pip-install-opencv/)。如果您有其他一些需求,您可能希望從原始碼編譯OpenCV。  請確保您已經從本博客文章的「Downloads」部分下載了原始碼、訓練過的Mask R-CNN以及示例圖像。然後,打開mask_rcnn.py文件並插入以下代碼:  Mask R-CNN with OpenCV---Python
# import the necessary packagesimport numpy as npimport argparseimport randomimport timeimport cv2import os

首先,我們將在第2-7行導入所需的包。值得注意的是,我們正在導入NumPy和OpenCV包。大多數Python安裝都默認安裝了上所需的其他的包。  現在我們開始解析我們的命令行參數(https://www.pyimagesearch.com/2018/03/12/python-argparse-command-line-arguments/):
Mask R-CNN with OpenCV# construct the argument parse and parse the argumentsap = argparse.ArgumentParser()ap.add_argument("-i", "--image", required=True,help="path to input image")ap.add_argument("-m", "--mask-rcnn", required=True,help="base path to mask-rcnn directory")ap.add_argument("-v", "--visualize", type=int, default=0,help="whether or not we are going to visualize each instance")ap.add_argument("-c", "--confidence", type=float, default=0.5,help="minimum probability to filter weak detections")ap.add_argument("-t", "--threshold", type=float, default=0.3,help="minimum threshold for pixel-wise mask segmentation")args = vars(ap.parse_args())

我們的腳本在終端中運行需要傳遞命令行參數標誌以及參數。我們的參數在第10-21行進行解析,其中前兩行是必需的,其餘的是可選的:

--image : 輸入圖像的路徑。 

--mask-rnn :  Mask R-CNN文件的根路徑  .

--visualize  (可選): 正值表示想要可視化如何在屏幕上提取屏蔽區域。無論哪種方式,我們都將在屏幕上顯示最終的輸出。 

--confidence  (optional): 您可以選擇0-0.5的概率值,該值用於過濾概率較低的檢測區域。 

--threshold  (可選): 我們將為圖像中的每個對象創建一個二進位掩碼,這個閾值將幫助我們過濾掉概率較低的掩碼。我發現默認值0.3時效果較好。

現在我們的命令行參數存儲在args字典中,讓我們加載標籤和顏色:Mask R-CNN with OpenCV---Python
# load the COCO class labels our Mask R-CNN was trained onlabelsPath = os.path.sep.join([args["mask_rcnn"],"object_detection_classes_coco.txt"])LABELS = open(labelsPath).read().strip().split("")
# load the set of colors that will be used when visualizing a given# instance segmentationcolorsPath = os.path.sep.join([args["mask_rcnn"], "colors.txt"])COLORS = open(colorsPath).read().strip().split("")COLORS = [np.array(c.split(",")).astype("int") for c in COLORS]COLORS = np.array(COLORS, dtype="uint8")

24-26行加載COCO對象類別標籤。現在的Mask R-CNN能夠識別90個類,包括人,車輛,標誌,動物,日常用品,體育用品,廚房用品,食物等等!我建議您查看object_detection_classes_cocoa .txt,以查看可用的類別。 這裡我們從路徑加載顏色文件,並執行一些數組轉換操作(第30-33行)。Mask R-CNN with OpenCV---Python
# derive the paths to the Mask R-CNN weights and model configurationweightsPath = 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 diskprint("[INFO] loading Mask R-CNN from disk...")net = cv2.dnn.readNetFromTensorflow(weightsPath, configPath)

首先,我們構建權重和配置路徑(第36-39行),然後通過這些路徑加載模型(第44行)。 在下一個代碼塊中,我們將加載Mask R-CNN神經網絡,輸入一張圖像:Mask R-CNN with OpenCV---Python
# load our input image and grab its spatial dimensionsimage = cv2.imread(args["image"])(H, W) = image.shape[:2]
# construct a blob from the input image and then perform a forward# pass of the Mask R-CNN, giving us (1) the bounding box coordinates# of the objects in the image along with (2) the pixel-wise segmentation# for each specific objectblob = cv2.dnn.blobFromImage(image, swapRB=True, crop=False)net.setInput(blob)start = time.time()(boxes, masks) = net.forward(["detection_out_final", "detection_masks"])end = time.time()
# show timing information and volume information on Mask R-CNNprint("[INFO] Mask R-CNN took {:.6f} seconds".format(end - start))print("[INFO] boxes shape: {}".format(boxes.shape))print("[INFO] masks shape: {}".

Load the input image  and extract dimensions for scaling purposes later (Lines 47 and 48).

Construct a blob  via cv2.dnn.blobFromImage  (Line 54). You can learn why and how to use this function in my previous tutorial(https://www.pyimagesearch.com/2017/11/06/deep-learning-opencvs-blobfromimage-works/).

Perform a forward pass of the blob  through the net  while collecting timestamps (Lines 55-58). The results are contained in two important variables: boxes  and masks .

現在我們已經在圖像上執行了口罩R-CNN的正向傳遞,我們想要過濾+可視化我們的結果。這正是下一個for循環要完成的。它很長,所以我把它分成五個代碼塊,從這裡開始:
# loop over the number of detected objectsfor i in range(0, boxes.shape[2]):# extract the class ID of the detection along with the confidence# (i.e., probability) associated with the predictionclassID = int(boxes[0, 0, i, 1])confidence = boxes[0, 0, i, 2]
# filter out weak predictions by ensuring the detected probability# is greater than the minimum probabilityif confidence > args["confidence"]:# clone our original image so we can draw on itclone = image.copy()
# scale the bounding box coordinates back relative to the# size of the image and then compute the width and the height# of the bounding boxbox = boxes[0, 0, i, 3:7] * np.array([W, H, W, H])(startX, startY, endX, endY) = box.astype("int")boxW = endX - startXboxH = endY - startY

在這個代碼塊中,我們開啟了一個訓練,不斷根據置信度過濾/並進行可視化(第66行)。 我們繼續提取特定檢測對象的分類和置信度(第69行和第70行)。在此基礎之上,我們通過將置信度與命令行參數置信度值進行比較,從而過濾掉置信度較低的預測結果,確保超過該值(第74行)。然後我們縮放對象的邊界框,並計算框的大小(第81-84行)。圖像分割要求我們找到目標所在的所有像素。因此,我們將在對象的頂部放置一個透明的層,以查看我們的算法執行的效果。為了做到這一點,我們將計算一個掩模:Mask R-CNN with OpenCV---Python 
# extract the pixel-wise segmentation for the object, resize# the mask such that it s the same dimensions of the bounding# box, and then finally threshold to create a *binary* maskmask = masks[i, classID]mask = cv2.resize(mask, (boxW, boxH),interpolation=cv2.INTER_NEAREST)mask = (mask > args["threshold"])
# extract the ROI of the imageroi = clone[startY:endY, startX:endX]

在第89-91行,我們提取了對象的像素級分割,並將其調整為原始圖像的尺寸。最後,我們設置掩碼的閾值,使其成為二進位數組/圖像(第92行)。在本文後面的圖8中可以看到遮罩和roi的可視化結果。為了方便起見,下一個代碼塊實現了掩碼、roi和分割實例的可視化,如果通過命令行設置了參數 --visualize的話。Mask R-CNN with OpenCV---Python
# check to see if are going to visualize how to extract the# masked region itselfif args["visualize"] > 0:# convert the mask from a boolean to an integer mask with# to values: 0 or 255, then apply the maskvisMask = (mask * 255).astype("uint8")instance = cv2.bitwise_and(roi, roi, mask=visMask)
# show the extracted ROI, the mask, along with the# segmented instancecv2.imshow("ROI", roi)cv2.imshow("Mask", visMask)cv2.imshow("Segmented", instance)

檢查是否應該可視化ROI、掩模和分割實例(第99行)。  

將掩模從布爾值轉換為整數,其中值「0」表示背景,「255」表示前景(第102行)。  

執行按位掩模以僅僅可視化分割實例本身(第103行)。  

顯示三個結果圖像(第107-109行)。  

同樣,只有通過可選的命令行設置參數 --visualize 標誌時,才會顯示這些可視化圖像(默認情況下不會顯示這些圖像)。 Mask R-CNN with OpenCV---Python
# now, extract *only* the masked region of the ROI by passing# in the boolean mask array as our slice conditionroi = roi[mask]
# randomly select a color that will be used to visualize this# particular instance segmentation then create a transparent# overlay by blending the randomly selected color with the ROIcolor = random.choice(COLORS)blended = ((0.4 * color) + (0.6 * roi)).astype("uint8")
# store the blended ROI in the original imageclone[startY:endY, startX:endX][mask] = blended

113行通過將布爾掩模數組作為切片條件傳遞,只提取ROI的掩模區域。 然後我們將隨機選擇六種顏色中的一種,將透明的覆蓋層應用到對象上(第118行)。 隨後,我們將用roi混合掩模區域(第119行),然後將該混合區域放入圖像clone中(第122行)。 最後,我們將在圖像上繪製矩形和文本類別標籤+ 置信度的值,並顯示結果! Mask R-CNN with OpenCV---Python
# draw the bounding box of the instance on the imagecolor = [int(c) for c in color]cv2.rectangle(clone, (startX, startY), (endX, endY), color, 2)
# draw the predicted label and associated probability of the# instance segmentation on the imagetext = "{}: {:.4f}".format(LABELS[classID], confidence)cv2.putText(clone, text, (startX, startY - 5),cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
# show the output imagecv2.imshow("Output", clone)cv2.waitKey(0)

在對象周圍繪製一個彩色邊框(第125行和第126行)。  構建我們的類別標籤+置信度文本,並在邊界框上面繪製文本(第130-132行)。  顯示圖像,直到按下任意鍵(第135行和第136行)。  確保您已經從本教程的「Downloads」部分下載了原始碼、訓練過的Mask R-CNN和示例圖像。然後,打開您的終端並執行以下操作:Mask R-CNN with OpenCV---Shell
$ python mask_rcnn.py --mask-rcnn mask-rcnn-coco --image images/example_01.jpg[INFO] loading Mask R-CNN from disk...[INFO] Mask R-CNN took 0.761193 seconds[INFO] boxes shape: (1, 1, 3, 7)[INFO] masks shape: (100, 90, 15, 15)

圖7:一個用於汽車場景的口罩R-CNN。Python和OpenCV用於生成掩碼。  在上面的圖片中,你可以看到我們的Mask R-CNN不僅定位了圖片中的每一輛車,還構建了一個像素級掩模,允許我們從圖片中分割每一輛車。 如果我們運行相同的命令,這次提供--visualize參數標誌,我們還可以可視化ROI、掩模和實例:圖8:使用--visuatize標誌參數,我們可以查看用Python和OpenCV構建的mask R-CNN流程的ROI、掩模、分割的中間步驟。 Mask R-CNN with OpenCV---Shell
$ python mask_rcnn.py --mask-rcnn mask-rcnn-coco --image images/example_02.jpg --confidence 0.6[INFO] loading Mask R-CNN from disk...[INFO] Mask R-CNN took 0.676008 seconds[INFO] boxes shape: (1, 1, 8, 7)[INFO] masks shape: (100, 90, 15, 15)

圖9:使用Python和OpenCV,我們可以使用Mask R-CNN執行實例分割。 我們的Mask R-CNN從圖像中正確地檢測並分割了人、狗、馬和卡車。在我們開始在視頻中使用Mask R-CNNs之前,還有最後一個例子:Mask R-CNN with OpenCV---Shell
$ python mask_rcnn.py --mask-rcnn mask-rcnn-coco --image images/example_03.jpg[INFO] loading Mask R-CNN from disk...[INFO] Mask R-CNN took 0.680739 seconds[INFO] boxes shape: (1, 1, 3, 7)[INFO] masks shape: (100, 90, 15, 15)

圖10:在這裡,您可以看到我正在餵比格爾家的小獵犬傑瑪。每個被標識對象的像素級映射都被屏蔽,並透明地覆蓋在對象上。這幅圖像是使用OpenCV和Python使用一個預訓練的Mask R-CNN模型生成的。 在這張圖片中,你可以看到我和傑瑪的照片,這是我家的小獵犬。 我們的面具R-CNN能夠以比較高的置信度檢測和定位我,傑瑪和椅子。 我們已經學會了怎麼將Mask RCNN應用於圖像上,現在我們進一步學習如何在視頻上應用Mask RCNN.打開文件 mask_rcnn_video.py,插入下列代碼:
# import the necessary packagesimport numpy as npimport argparseimport imutilsimport timeimport cv2import os # construct the argument parse and parse the argumentsap = argparse.ArgumentParser()ap.add_argument("-i", "--input", required=True,help="path to input video file")ap.add_argument("-o", "--output", required=True,help="path to output video file")ap.add_argument("-m", "--mask-rcnn", required=True,help="base path to mask-rcnn directory")ap.add_argument("-c", "--confidence", type=float, default=0.5,help="minimum probability to filter weak detections")ap.add_argument("-t", "--threshold", type=float, default=0.3,help="minimum threshold for pixel-wise mask segmentation")args = vars(ap.parse_args())

首先,我們插導入必要的包,設置聲明的參數,緊接著的兩行代碼是放置需要檢測的圖像。
# load the COCO class labels our Mask R-CNN was trained onlabelsPath = os.path.sep.join([args["mask_rcnn"],"object_detection_classes_coco.txt"])LABELS = open(labelsPath).read().strip().split("") # initialize a list of colors to represent each possible class labelnp.random.seed(42)COLORS = np.random.randint(0, 255, size=(len(LABELS), 3),dtype="uint8") # derive the paths to the Mask R-CNN weights and model configurationweightsPath = 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 diskprint("[INFO] loading Mask R-CNN from disk...")net = cv2.dnn.readNetFromTensorflow(weightsPath, configPath)

在加載MaskRCNN網絡之前,需要先加載權重模型和配置文件(第34-42行)。
# initialize the video stream and pointer to output video filevs = cv2.VideoCapture(args["input"])writer = None # try to determine the total number of frames in the video filetry:prop = cv2.cv.CV_CAP_PROP_FRAME_COUNT if imutils.is_cv2() else cv2.CAP_PROP_FRAME_COUNTtotal = int(vs.get(prop))print("[INFO] {} total frames in video".format(total)) # an error occurred while trying to determine the total# number of frames in the video fileexcept:print("[INFO] could not determine # of frames in video")total = -1

我們嘗試確定視頻文件的幀數,並將總的幀數顯示出來。如果不成功的話,程序就會終止,但列印狀態信息,或者我們將這個幀數設置成-1,忽略這一個步驟,不做任何處理。
# loop over frames from the video file streamwhile True:# read the next frame from the file(grabbed, frame) = vs.read() # if the frame was not grabbed, then we have reached the end# of the streamif not grabbed:break # construct a blob from the input frame and then perform a# forward pass of the Mask R-CNN, giving us (1) the bounding box# coordinates of the objects in the image along with (2) the# pixel-wise segmentation for each specific objectblob = cv2.dnn.blobFromImage(frame, swapRB=True, crop=False)net.setInput(blob)start = time.time()(boxes, masks) = net.forward(["detection_out_final","detection_masks"])end = time.time()

我們開始通過定義無限循環來循環所有的幀,並且捕獲第一幀(第 62-64行)。循環地處理視頻,直到滿足退出條件(第68和69行)。然後,我們從幀中構造一個 blob,並在計算通過神經網絡的時間,以便我們可以計算完成所需時間(第 75-80 行)。檢測的結果同時包含了檢測框和蒙版。
# loop over the number of detected objectsfor i in range(0, boxes.shape[2]):# extract the class ID of the detection along with the# confidence (i.e., probability) associated with the# predictionclassID = int(boxes[0, 0, i, 1])confidence = boxes[0, 0, i, 2] # filter out weak predictions by ensuring the detected# probability is greater than the minimum probabilityif confidence > args["confidence"]:# scale the bounding box coordinates back relative to the# size of the frame and then compute the width and the# height of the bounding box(H, W) = frame.shape[:2]box = boxes[0, 0, i, 3:7] * np.array([W, H, W, H])(startX, startY, endX, endY) = box.astype("int")boxW = endX - startXboxH = endY - startY # extract the pixel-wise segmentation for the object,# resize the mask such that it s the same dimensions of# the bounding box, and then finally threshold to create# a *binary* maskmask = masks[i, classID]mask = cv2.resize(mask, (boxW, boxH),interpolation=cv2.INTER_NEAREST)mask = (mask > args["threshold"]) # extract the ROI of the image but *only* extracted the# masked region of the ROIroi = frame[startY:endY, sta

首先我們過濾掉低置信度的檢測結果,然後確定檢測框的坐標和蒙版。
# grab the color used to visualize this particular class,# then create a transparent overlay by blending the color# with the ROIcolor = COLORS[classID]blended = ((0.4 * color) + (0.6 * roi)).astype("uint8") # store the blended ROI in the original frameframe[startY:endY, startX:endX][mask] = blended # draw the bounding box of the instance on the framecolor = [int(c) for c in color]cv2.rectangle(frame, (startX, startY), (endX, endY),color, 2) # draw the predicted label and associated probability of# the instance segmentation on the frametext = "{}: {:.4f}".format(LABELS[classID], confidence)cv2.putText(frame, text, (startX, startY - 5),cv2.FONT_HERSHEY_SIMPLEX, 0.5, col

這裡,我們將興趣區域用顏色表示出來,儲存在原始的框架中。
# check if the video writer is Noneif writer is None:# initialize our video writerfourcc = cv2.VideoWriter_fourcc(*"MJPG")writer = cv2.VideoWriter(args["output"], fourcc, 30,(frame.shape[1], frame.shape[0]), True) # some information on processing single frameif total > 0:elap = (end - start)print("[INFO] single frame took {:.4f} seconds".format(elap))print("[INFO] estimated total time to finish: {:.4f}".format(elap * total)) # write the output frame to diskwriter.write(frame) # release the file pointersprint("[INFO] cleaning up...")writer.release()vs.release()

你會注意到,我沒有在屏幕上顯示每個幀。顯示操作非常耗時,當腳本完成處理時,你仍可以使用任何媒體播放器查看輸出視頻。注意: 此外,OpenCV 不支持 NVIDIA GPU 的 dnn 模塊。目前僅支持數量有限的 GPU,主要是英特爾 GPU。NVIDIA GPU 支持即將推出,但目前我們無法輕鬆地使用具有 OpenCV dnn 的 GPU.現在,我們已經編碼了我們的Mask R-CNN和OpenCV腳本的視頻流,你可以自己嘗試下!然後,你需要使用智慧型手機或其他錄製設備收集你自己的視頻。或者,你也可以像我一樣從 YouTube 下載視頻。
$ python mask_rcnn_video.py --input videos/cats_and_dogs.mp4 --output output/cats_and_dogs_output.avi --mask-rcnn mask-rcnn-coco[INFO] loading Mask R-CNN from disk...[INFO] 19312 total frames in video[INFO] single frame took 0.8585 seconds[INFO] estimated total time to finish: 16579.2047

圖11:在上面的視頻中,你可以找到包含狗和貓的有趣視頻剪輯,並Mask R-CNN應用在上面!(觀看這個視頻:https://youtu.be/T_GXkW0BUyA)下面是第二個例子,這裡應用OpenCV和Mask R-CNN檢測寒冷天氣下滑動的汽車。
$ python mask_rcnn_video.py --input videos/slip_and_slide.mp4 --output output/slip_and_slide_output.avi --mask-rcnn mask-rcnn-coco[INFO] loading Mask R-CNN from disk...[INFO] 17421 total frames in video[INFO] single frame took 0.9341 seconds[INFO] estimated total time to finish: 16272.9920

圖12 利用Python和Opencv將Mask RCNN應用於視頻中的車輛檢測你可以想像一下,將Mask RCNN應用於擁擠道路上,檢查道路擁擠、車禍和需要幫助的車輛。(觀看視頻:https://www.youtube.com/watch?v=8nbzVARfosE)

貓狗:

「Try Not To Laugh Challenge – Funny Cat & Dog Vines compilation 2017」on YouTube(https://www.youtube.com/watch?v=EtH9Yllzjcc)

「Happy rock」 on BenSound(https://www.bensound.com/royalty-free-music/track/happy-rock)

Slip and Slide:

「Compilation of Ridiculous Car Crash and Slip & Slide Winter Weather – Part 1」 on YouTube(https://www.youtube.com/watch?v=i59v0p-gAtk)

「Epic」 on BenSound(https://www.bensound.com/royalty-free-music/track/epic)

圖13:在我的書 Deep Learning for Computer Vision with Python中
Mask RCNN模型的預訓練權重模型是在COCO數據集上訓練得到的。但是,如果你想在自定義數據集上訓練 Mask  R-CNN呢?在我的書Deep Learning for Computer Vision with Python中有詳細介紹。

我教你如何訓練一個Mask R-CNN自動檢測和分割癌性皮膚病變影像-第一步,建立一個自動癌症危險因素分類系統。

為您提供我最喜歡的圖像標註工具,使您能夠為輸入圖像創建蒙版。

向您展示如何在自定義數據集上訓練 Mask R-CNN。

在訓練自己的 Mask  R-CNN 時,為您提供我的最佳實踐、提示和建議。

所有 Mask  R-CNN 章節都包含算法和代碼的詳細說明,確保您能夠成功訓練自己的 Mask R-CNN。要了解有關我的書的更多信息(並獲取免費的示例章節和目錄集),請查看:https://www.pyimagesearch.com/deep-learning-computer-vision-python-book/
總結在這個教程中,你學到了在OpenCV和Python下用Mask R-CNN進行圖像和視頻流中的目標分割。 
像YOLO,SSD和Faster R-CNN這樣的目標檢測方法僅能夠生成圖像中目標的邊界框 — 我們並不能從它們的方法得知目標的實際形狀。而用 Mask R-CNN 我們能得到有相對形狀的顏色塊,從而幫助我們把物體從背景中分離。
進一步說,Mask R-CNN可以幫助我們從傳統計算機視覺算法無法實現的圖像中分割出複雜的物體和形狀。  希望今天的教程能幫到你更好地了解OpenCV 和 Mask R-CNN!via https://www.pyimagesearch.com/2018/11/19/mask-r-cnn-with-opencv/

相關焦點

  • 愷明大神 Mask R-CNN 超實用教程
    對象檢測器,如yolo、faster r-cnn和ssd,生成四組(x,y)坐標,表示圖像中對象的邊界框。從獲取對象的邊界框開始挺好的,但是邊界框本身並不能告訴我們(1)哪些像素屬於前景對象,(2)哪些像素屬於背景。這就引出了一個問題:是否可以為圖像中的每個對象生成一個MASK,從而允許我們從背景分割前景對象?
  • Mask R-CNN
    Mask R-CNN是一種在有效檢測目標的同時輸出高質量的實例分割mask。是對faster r-cnn的擴展,與bbox識別並行的增加一個預測分割mask的分支。Mask R-CNN 可以應用到人體姿勢識別。並且在實例分割、目標檢測、人體關鍵點檢測三個任務都取得了現在最好的效果。效果圖
  • 潮科技行業入門指南 | 深度學習理論與實戰:提高篇(14)——Mask R...
    = results[0] visualize.display_instances(image, r['rois'], r['masks'], r['class_ids'], class_names, r['scores'])檢測結果r包括rois(RoI)、masks(
  • 經典目標檢測方法Faster R-CNN和Mask R-CNN|基於PaddlePaddle深度...
    為了解決特徵不對準的問題,文章作者提出了 RoIAlign 層來解決這個問題,它能準確的保存空間位置,進而提高 mask 的準確率。  將掩模預測 (mask prediction) 和分類預測 (class prediction) 拆解:該框架結構對每個類別獨立的預測一個二值 mask,不依賴分類 (classification) 分支的預測結果  掩模表示 (mask representation):有別於類別,框回歸,這幾個的輸出都可以是一個向量,但是 mask 必須要保持一定的空間結構信息,因此作者採用全連接層
  • 【從零開始學Mask RCNN】一,原理回顧&&項目文檔翻譯
    訓練你自己的數據集閱讀這個例子作為開始:https://engineering.matterport.com/splash-of-color-instance-segmentation-with-mask-r-cnn-and-tensorflow-7c761e238b46?gi=468916310fd5 。
  • 用於圖像分割的卷積神經網絡:從R-CNN到Mask R-CNN
    在 Mask R-CNN 中,在 Faster R-CNN 的 CNN 特徵的頂部添加了一個簡單的完全卷積網絡(FCN),以生成 mask(分割輸出)。請注意它是如何與 Faster R-CNN 的分類和邊界框回歸網絡並行的。Mask R-CNN 通過簡單地向 Faster R-CNN 添加一個分支來輸出二進位 mask,以說明給定像素是否是目標的一部分。
  • 【源頭活水】Sparse R-CNN:簡化版fast rcnn
    算法,是faster rcnn算法的前身,由於其巨大計算量以及無法端到端訓練,故而提出區域提取網絡RPN加上fast rcnn的faster rcnn算法。faster rcnn雖好,但是其複雜度太高了,超參非常多。1.3 relationrelation論文全名是Relation Networks for Object Detection,是微軟將nlp裡面的transformer思想引入到目標檢測中從而加強物體和物體之間的關係,理論和實驗表明確實有性能提升。
  • Mask R-CNN官方實現「又」來了!訓練速度是原來2倍
    2017年,Facebook AI研究團隊又再次提出了Mask R-CNN:通過添加與現有分支並行的對象掩碼(object mask)分支,以增強Faster RCNN在邊框識別上的性能。
  • 一文看懂近年火到不行的CNN圖像識別:從R-CNN到Mask R-CNN
    Mask R-CNN在Faster R-CNN的CNN特徵的上層增加一個全卷積網絡(Fully Convolutional Network,FCN)用於生成mask(分割輸出結果)。它的輸入和輸出如下:- 輸入:CNN特徵圖- 輸出:在當前像素屬於目標的所有位置上為1s 的矩陣,其他位置為0s(這被稱為binary mask)但是Mask R-CNN的作者做了少量調整使得流程按預期工作。RoiAlign - 調整RoIPool使它更加準確
  • FAIR最新視覺論文集錦:FPN,RetinaNet,Mask 和 Mask-X RCNN(含代碼...
    是一個可以調整的超參數。表示樣本分類的概率。 讓大於 0 會降低分類正確樣板的權重。含義與在常規的加權損失函數中相同。論文中被稱為損失函數。master/configs/12_2017_baselines   Keras - https://github.com/matterport/Mask_RCNN/   PyTorch - https://github.com/soeaver/Pytorch_Mask_RCNN/   MXNet - https://github.com/TuSimple/mx-maskrcnn
  • 經典論文速讀-Mask R-CNN
    另一方面,本文將mask預測和類別預測解耦,mask類別由RoI分類來完成,對比FCNs同時預測類別和mask,實例分割表現則很差。的loss,試驗顯示只預測一個類別mask相比FCN同時預測像素多類別標籤,效果要更好。
  • 何愷明團隊:從特徵金字塔網絡、Mask R-CNN到學習分割一切
    公式如下:其中γ是一個可以改變的超參數。是來自分類器的樣本的概率。如果設γ比0大,將減小分類號的樣本的權重。是正常加權損失函數中類的權重。在論文中它被表示為α-balanced loss。需要注意的是,這是分類損失,並與RetinaNet中物體檢測任務的平滑L1損失相結合。
  • 接地氣介紹一下Mask RCNN
    根據 Faster RCNN 計算出來的每個候選框的分數,篩選出一大堆更加準確的 RoI 「對應圖中 selected RoI」,然後用一個 RoI Align 層提取這些 RoI 的特徵,計算出一個 mask,根據 RoI 和原圖的比例,將這個 mask 擴大回原圖,就可以得到一個分割的 mask 了。
  • 從零開始 Mask RCNN 實戰:基於 Win10 + Anaconda 的 Mask RCNN 環境搭建
    同時下載 Mask RCNN 的預訓練模型 「mask_rcnn_coco.h5」,放置於本地 Mask_RCNN 開源庫的根目錄下。「mask_rcnn_coco.h5」 下載地址:https://github.com/matterport/Mask_RCNN/releases在裡面的 Mask R-CNN 2.0 下找到 「mask_rcnn_coco.h5」 並下載。3.
  • 何愷明團隊計算機視覺最新進展:從特徵金字塔網絡、Mask R-CNN到...
    公式如下:  其中γ是一個可以改變的超參數。是來自分類器的樣本的概率。如果設γ比0大,將減小分類號的樣本的權重。是正常加權損失函數中類的權重。在論文中它被表示為α-balanced loss。需要注意的是,這是分類損失,並與RetinaNet中物體檢測任務的平滑L1損失相結合。
  • 輕鬆掌握 MMDetection 中常用算法(二):Faster R-CNN|Mask R-CNN
    在 FPN 提出後,Kaiming He 等進一步對其進行任務擴展,提出了 Mask R-CNN,通過新增 mask 掩碼分支實現實例分割任務,其最大特點是任務擴展性強,通過新增不同分支就可以實現不同的擴展任務。例如可以將 mask 分支替換為關鍵點分支即可實現多人姿態估計。
  • (附代碼)| 從特徵金字塔網絡、Mask R-CNN到學習分割一切
    其中γ是一個可以改變的超參數。,https://github.com/matterport/Mask_RCNN/PyTorchhttps://github.com/soeaver/Pytorch_Mask_RCNN/MXNethttps://github.com/TuSimple/mx-maskrcnn
  • Faster R-CNN
    Mask r-cnn[C]//Computer Vision (ICCV), 2017 IEEE International Conference on. IEEE, 2017: 2980-2988.
  • 代替Mask R-CNN,BlendMask欲做實例預測任務的新基準?
    密集的實例分割方法可以追溯到DeepMask,這是一種自頂向下的方法,可以使用滑動窗口生成密集的實例mask。Mask的表示在每個空間位置被編碼為一維向量。儘管結構簡單,但是在訓練中有幾個問題會阻礙它獲得出色的性能:1)失去了特徵和mask之間的局部一致性;2)特徵表示是多餘的,因為在每個前景特徵處會重複地對掩模進行編碼;3)在使用大步卷積進行下採樣後,位置信息會消減。
  • 算法| 超Mask RCNN速度4倍,僅在單個GPU訓練的實時實例分割算法
    儘管本文使用了全卷積網絡實現,但模板 mask 可以自己在具有平移變換情況下對實例進行定位。最後,作者還提出了 Fast NMS,這比標準 NMS 的快12ms,並且性能損失很小。 這種方法有是三個優點:第一,速度非常快。第二,由於沒使用類似「repool」的方法,mask的質量非常高。第三,這個想法可以泛化。生成原型和mask係數的想法可以添加到現有的目標檢測的算法裡面。