日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用opencv实现实例分割,一学就会|附源码

發布時間:2025/6/17 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用opencv实现实例分割,一学就会|附源码 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

無論是從酒店房間接聽電話、在辦公里樓工作,還是根本不想在家庭辦公室等情況,電話會議模糊功能都可以讓會議與會者專注于自己,這樣的功能對于在家工作并希望保護其家庭成員隱私的人特別有用。
為了實現這樣的功能,微軟利用計算機視覺、深度學習以及實例分割技術實現。
在之前的博文中,介紹了如何利用YOLO以及OpenCV實現目標檢測的功能,今天將采用Mask R-CNN來構建視頻模糊功能。

使用OpenCV進行實例分割


https://youtu.be/puSN8Dg-bdI


在本教程的第一部分中,將簡要介紹實例分割;之后將使用實例分割和OpenCV來實現:
  • 從視頻流中檢測出用戶并分割;
  • 模糊背景;
  • 將用戶添加回流本身;

什么是實例分割?


圖1:對象檢測和實例分割之間的區別


如上圖所示,對于對象檢測(左圖,Object Detection)而言,在各個對象周圍繪制出一個框。 實例分割(右圖,Instance Segmentation)而言,是需要嘗試確定哪些像素屬于對應的對象。通過上圖,可以清楚地看到兩者之間的差異。
執行對象檢測時,是需要:
  • 計算每個對象的邊界框(x,y的)-坐標;
  • 然后將類標簽與每個邊界框相關聯;

從上可以看出,對象檢測并沒有告訴我們關于對象本身的形狀,而只獲得了一組邊界框坐標。而另一方面,實例分割需要計算出一個逐像素掩模用于圖像中的每個對象。
即使對象具有相同的類標簽,例如上圖中的兩只狗,我們的實例分割算法仍然報告總共三個獨特的對象:兩只狗和一只貓。
使用實例分割,可以更加細致地理解圖像中的對象——比如知道對象存在于哪個(x,y)坐標中。此外,通過使用實例分割,可以輕松地從背景中分割前景對象。
本文使用Mask R-CNN進行實例分割。

項目結構

項目樹:

$ 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模型的權重,這些權重是在COCO數據集上預先訓練所得到的;
    • mask_rcnn_inception_v2_coco_2018_01_28 .pbtxt:Mask R-CNN模型的配置文件,如果你想在自己的數據集上構建及訓練自己的模型,可以參閱網上的一些資源更改該配置文件。
    • object_detection_classes_coco.txt:此文本文件中列出了數據集中包含的90個類,每行表示一個類別。
  • instance_segmentation .py:背景模糊腳本,本文的核心內容, 將詳細介紹該代碼并評估其算法性能。

使用OpenCV實現實例分割

下面開始使用OpenCV實現實例分割。首先打開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

在開始編寫腳本時,首先需要導入必要的包,并且需要配置好編譯環境。本文使用的OpenCV版本為3.4.3。如果個人的計算機配置文件不同,需要對其進行更新。強烈建議將此軟件放在隔離的虛擬環境中,推薦使用conda安裝。
下面解析命令行參數:

# construct the argument parse and parse the arguments ap = argparse.ArgumentParser() 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") ap.add_argument("-k", "--kernel", type=int, default=41,help="size of gaussian blur kernel") args = vars(ap.parse_args())

每個命令行參數的描述可以在下面找到:

  • mask-rcnn:Mask R-CNN目錄的基本路徑;
  • confidence:濾除弱檢測的最小概率,可以將此值的默認值設置為0.5,也可以通過命令行傳遞不同的值;
  • threshold:像素掩碼分割的最小閾值,默認設置為 0.3;
  • kernel:高斯模糊內核的大小,默認設置41,這是通過實驗得到的經驗值;

下面加載數據集的標簽和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)

標簽文件位于mask-rcnn - coco目錄,指定好路徑后就可以加載標簽文件了。同樣地, weightsPath和configPath也執行類型的操作。
基于這兩個路徑,利用dnn模塊初始化神經網絡。在開始處理視頻幀之前,需要將Mask R-CNN加載到內存中(只需要加載一次)。
下面構建模糊內核并啟動網絡攝像頭視頻流:

# construct the kernel for the Gaussian blur and initialize whether # or not we are in "privacy mode" K = (args["kernel"], args["kernel"]) privacy = False# initialize the video stream, then allow the camera sensor to warm up print("[INFO] starting video stream...") vs = VideoStream(src=0).start() time.sleep(2.0)

模糊內核元組也通過行命令設定。此外,項目有兩種模式:“正常模式”和“隱私模式”。因此, 布爾值privacy用于模式邏輯,上述代碼將其初始化為False。
網絡攝像頭視頻流用VideoStream(src=0).start(),首先暫停兩秒鐘以讓傳感器預熱。
初始化了所有變量和對象后,就可以從網絡攝像頭開始處理幀了:

# loop over frames from the video file stream while True:# grab the frame from the threaded video streamframe = vs.read()# resize the frame to have a width of 600 pixels (while# maintaining the aspect ratio), and then grab the image# dimensionsframe = imutils.resize(frame, width=600)(H, W) = frame.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(frame, swapRB=True, crop=False)net.setInput(blob)(boxes, masks) = net.forward(["detection_out_final","detection_masks"])

在每次迭代中,將抓取一幀并將其調整為設定的寬度,同時保持縱橫比。此外,為了之后的縮放操作,繼續并提取幀的尺寸。然后,構建一個blob并完成前向傳播網絡。
結果輸出是boxes和masks,雖然需要用到掩碼(mask),但還需要使用邊界框(boxes)中包含的數據。
下面對索引進行排序并初始化變量:

# sort the indexes of the bounding boxes in by their corresponding# prediction probability (in descending order)idxs = np.argsort(boxes[0, 0, :, 2])[::-1]# initialize the mask, ROI, and coordinates of the person for the# current framemask = Noneroi = Nonecoords = None

通過其對應的預測概率對邊界框的索引進行排序,假設具有最大相應檢測概率的人是我們的用戶。然后初始化mask、roi以及邊界框的坐標。
遍歷索引并過濾結果:

# loop over the indexesfor i in idxs:# 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]# if the detection is not the 'person' class, ignore itif LABELS[classID] != "person":continue# 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 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")coords = (startX, startY, endX, endY)boxW = endX - startXboxH = endY - startY

從idxs開始循環,然后,使用框和當前索引提取classID和 置信度。隨后,執行第一個過濾器—— “人”。如果遇到任何其他對象類,繼續下一個索引。下一個過濾器確保預測的置信度超過通過命令行參數設置的閾值。
如果通過了該測試,那么將邊界框坐標縮放回圖像的相對尺寸,然后提取坐標和對象的寬度/高度。
計算掩膜并提取ROI:

# 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 and break from the loop (since we make# the assumption there is only *one* person in the frame# who is also the person with the highest prediction# confidence)roi = frame[startY:endY, startX:endX][mask]break

上述代碼首先提取掩碼,并調整其大小,之后應用閾值來創建二進制掩碼本身。示例如下圖所示:


圖2:使用OpenCV和實例分割在網絡攝像頭前通過實例分割計算的二進制掩碼


從上圖中可以看到,假設所有白色像素都是人(即前景),而所有黑色像素都是背景。使用掩碼后,通過NumPy陣列切片計算roi。之后循環斷開,這是因為你找到最大概率的人了。
如果處于“隱私模式”,需要進行初始化輸出幀并計算模糊: # 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

其輸出幀只是原始幀的副本。
如果我們倆都:

  • 有一個非空的掩膜;
  • 處于“ 隱私模式”;
  • ... ...

然后將使用模糊背景并將掩碼應用于輸出幀。
下面顯示輸出以及圖像處理按鍵:

# show the output framecv2.imshow("Video Call", output)key = cv2.waitKey(1) & 0xFF# if the `p` key was pressed, toggle privacy modeif key == ord("p"):privacy = not privacy# if the `q` key was pressed, break from the loopelif key == ord("q"):break# do a bit of cleanup cv2.destroyAllWindows() vs.stop()

keypresses被獲取其值,有兩個值可供選擇,但會導致不同的行為:

  • “p”:按下此鍵時, 打開或關閉“ 隱私模式”;
  • “q”:如果按下此鍵,將跳出循環并“退出”腳本;

每當退出時,上述代碼就會關閉打開的窗口并停止視頻流。

實例分割結果

現在已經實現了OpenCV實例分割算法,下面看看其實際應用!
打開一個終端并執行以下命令:

$ python instance_segmentation.py --mask-rcnn mask-rcnn-coco --kernel 41 [INFO] loading Mask R-CNN from disk... [INFO] starting video stream...

圖3:演示了一個用于網絡聊天的“隱私過濾器”
通過啟用“隱私模式”,可以:

  • 使用OpenCV實例分割查找具有最大相應概率的人物檢測(最可能是最接近相機的人);
  • 模糊視頻流的背景;
  • 將分割的、非模糊的人重疊到視頻流上;

下面列出一個視頻演示(需外網):


https://youtu.be/puSN8Dg-bdI


看完視頻會立即注意到,并沒有獲得真正的實時性能——每秒只處理幾幀。為什么是這樣?
要回答這些問題,請務必參考以下部分。

限制、缺點和潛在的改進

第一個限制是最明顯的——OpenCV實例分割的實現太慢而無法實時運行。在CPU上運行,每秒只能處理幾幀。為了獲得真正的實時實例分割性能,需要利用到GPU。
但其中存在的問題是:

  • OpenCV對其dnn模塊的GPU支持相當有限;
  • 目前,它主要支持英特爾GPU;
  • NVIDIA CUDA GPU支持正在開發中,但目前尚未推出;

一旦OpenCV正式支持dnn模塊的NVIDIA GPU版本, 就能夠更輕松地構建實時(甚至超實時)的深度學習應用程序。但就目前而言,本文的實例分割教程只作為演示:
此外,也可以做出的另一項改進與分割的人重疊在模糊的背景上有關。當將本文的實現與Microsoft的Office 365視頻模糊功能進行比較時,就會發現Microsoft會更加“流暢”。但也可以通過利用一些alpha混合來模仿這個功能。
對實例分割管道進行簡單而有效的更新可能是:

  • 使用形態學操作來增加蒙版的大小;
  • 在掩膜本身涂抹少量高斯模糊,幫助平滑掩碼;
  • 將掩碼值縮放到范圍[0,1];
  • 使用縮放蒙版創建alpha圖層;
  • 在模糊的背景上疊加平滑的掩膜+人;

或者,也可以計算掩膜本身的輪廓,然后應用掩膜近似來幫助創建“更平滑”的掩碼。

總結

看完本篇文章,你應該學習了如何使用OpenCV、Deep Learning和Python實現實例分割了吧。實例分割大體過程如下:

  • 檢測圖像中的每個對象;
  • 計算每個對象的逐像素掩碼;

注意,即使對象屬于同一類,實例分割也應為每個對象返回唯一的掩碼;

作者信息

Adrian Rosebrock ,機器學習,人工智能,圖像處理
本文由阿里云云棲社區組織翻譯。?
文章原標題《Instance segmentation with OpenCV》,譯者:海棠,審校:Uncle_LLD。?
文章為簡譯,更為詳細的內容,請查看原文。

總結

以上是生活随笔為你收集整理的使用opencv实现实例分割,一学就会|附源码的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。