Python 使用Opencv的GrabCut 算法實現前景檢測以及分水嶺算法實現圖像分割

本人新書《玩轉Python網絡爬蟲》,可在天貓、京東等商城搜索查閱,項目深入淺出,適合爬蟲初學者或者是已經有一些網絡爬蟲編寫經驗,但希望更加全面、深入理解Python爬蟲的開發人員。

———-歡迎加入學習交流QQ羣:657341423


OpenCV的前景檢測是由grabCut函數實現。grabCut是一種算法,算法原理說明如下:
這裏寫圖片描述這裏寫圖片描述


函數原型:

grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode=None)

img - 輸入圖像
mask-掩模圖像,用來確定那些區域是背景,前景,可能是前景/背景等。可以設置爲:cv2.GC_BGD,cv2.GC_FGD,cv2.GC_PR_BGD,cv2.GC_PR_FGD,或者直接輸入 0,1,2,3 也行。
rect - 包含前景的矩形,格式爲 (x,y,w,h)
bdgModel, fgdModel - 算法內部使用的數組. 你只需要創建兩個大小爲 (1,65),數據類型爲 np.float64 的數組。
iterCount - 算法的迭代次數
mode - cv2.GC_INIT_WITH_RECT 或 cv2.GC_INIT_WITH_MASK,使用矩陣模式還是蒙板模式。


示例一

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('varese.jpg')
mask = np.zeros(img.shape[:2], np.uint8)

# zeros(shape, dtype=float, order='C'),參數shape代表形狀,(1,65)代表1行65列的數組,dtype:數據類型,可選參數,默認numpy.float64
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)

rect = (1, 1, img.shape[1], img.shape[0])
# 函數原型:grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode=None)
# img - 輸入圖像
# mask-掩模圖像,用來確定那些區域是背景,前景,可能是前景/背景等。可以設置爲:cv2.GC_BGD,cv2.GC_FGD,cv2.GC_PR_BGD,cv2.GC_PR_FGD,或者直接輸入 0,1,2,3 也行。
# rect - 包含前景的矩形,格式爲 (x,y,w,h)
# bdgModel, fgdModel - 算法內部使用的數組. 你只需要創建兩個大小爲 (1,65),數據類型爲 np.float64 的數組。
# iterCount - 算法的迭代次數
# mode cv2.GC_INIT_WITH_RECT 或 cv2.GC_INIT_WITH_MASK,使用矩陣模式還是蒙板模式。
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 10, cv2.GC_INIT_WITH_RECT)

# np.where 函數是三元表達式 x if condition else y的矢量化版本
# result = np.where(cond,xarr,yarr)
# 當符合條件時是x,不符合是y,常用於根據一個數組產生另一個新的數組。
# | 是邏輯運算符or的另一種表現形式
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
# mask2[:, :, np.newaxis] 增加維度
img = img * mask2[:, :, np.newaxis]

# 顯示圖片
plt.subplot(121), plt.imshow(img)
plt.title("grabcut"), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(cv2.cvtColor(cv2.imread('varese.jpg'), cv2.COLOR_BGR2RGB))
plt.title("original"), plt.xticks([]), plt.yticks([])
plt.show()

這裏寫圖片描述
參數mask的x、y座標設置和參數iterCount 的設置都對前景檢測有一定的影響。

在上述例子中,還可以將函數參數mode 改爲GC_INIT_WITH_MASK模式實現,可參考:鏈接地址


分水嶺算法實現圖像分割
分水嶺算法原理解釋:請點擊
示例二

import numpy as np
import cv2
from matplotlib import pyplot as plt

# 參考教程:https://blog.csdn.net/u010682375/article/details/72765064
img = cv2.imread('basil.jpg')
# 圖片灰度處理
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# threshold函數是二化值處理
# ret, dst = cv2.threshold(src, thresh, maxval, type)
# 參數說明:
# src:輸入圖,只能輸入單通道圖像,通常來說爲灰度圖
# dst:輸出圖
# thresh:閾值
# maxval:當像素值超過了閾值(或者小於閾值,根據type來決定),所賦予的值
# type:二值化操作的類型,包含以下5 種類型:cv2.THRESH_BINARY;cv2.THRESH_BINARY_INV;cv2.THRESH_TRUNC;cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# 生成3x3的核
kernel = np.ones((3, 3), np.uint8)
# morphologyEx函數是圖像進行膨脹後再腐蝕的操作,去除噪聲數據,參考https://blog.csdn.net/u010682375/article/details/70026569
# 參數src:二值化後的圖像
# 參數op:形態運算的類型
# 參數iterations:腐蝕次數和膨脹次數
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)

# dilate函數是膨脹,與morphologyEx的作用相似
sure_bg = cv2.dilate(opening,kernel,iterations=3)

# 確認背景區域位置,distanceTransform函數是距離變換,參考https://blog.csdn.net/liubing8609/article/details/78483667
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
# threshold函數是二化值處理
ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)

# Finding unknown region
sure_fg = np.uint8(sure_fg)
# subtract計算兩個數組或數組和標量之間的元素差異,這裏計算背景和前景的差異值
unknown = cv2.subtract(sure_bg, sure_fg)

# 標記
ret, markers = cv2.connectedComponents(sure_fg)

# Add one to all labels so that sure background is not 0, but 1
markers = markers + 1

# Now, mark the region of unknown with zero
markers[unknown==255] = 0
# watershed實現分水嶺算法
markers = cv2.watershed(img, markers)
img[markers == -1] = [255,0,0]
# 顯示圖像
plt.imshow(img)
plt.show()

運行結果:
這裏寫圖片描述
從結果看到,有些葉子能分割很好,有些葉子是無法分割。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章