iPhone也有去背的功能,那麼OpenCV能不能做到這件事呢?,答案是可以的
但在背景相當複雜的情況下,結果就不太好,若要好又要設很多條件才能完美切割。
GrabCut 是一種強大的前景提取演算法,特別適合處理具有複雜背景的圖像分割問題。它基於圖割(Graph Cut)的技術進行迭代優化,能夠在給定前景物體的大致區域後,自動分割出前景。
GrabCut 演算法基於 最大流最小割 的圖論技術。圖像中的每個像素被視為圖中的一個節點,而前景和背景被視為兩個特殊的節點:源點(Source) 和 匯點(Sink)。演算法通過最大化像素到這兩個特殊點的連接來進行優化。這意味著,演算法會嘗試尋找一個切割線,將圖像中的節點劃分為前景和背景。
cv2.grabCut
函數的語法:cv2.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode)
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 顯示圖像的函數
def show_image(image, title="Image"):
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.title(title)
plt.axis('off') # 不顯示座標軸
plt.show()
# 讀取圖像
image_path = 'your_image_path.png' # 替換成你的圖像路徑
img = cv2.imread(image_path)
# 初始化掩膜
mask = np.zeros(img.shape[:2], np.uint8)
# 背景和前景模型(由 GrabCut 需要)
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)
# 定義一個矩形來包含前景物體
rect = (350, 200, 300, 300) # 根據圖像大小進行調整 x,y,w,h
# 在原圖上畫出矩形框
img_with_rect = img.copy()
cv2.rectangle(img_with_rect, (rect[0], rect[1]), (rect[0] + rect[2], rect[1] + rect[3]), (0, 255, 0), 2)
# 顯示畫出矩形框的圖像
show_image(img_with_rect, "Image with Rectangle")
# 執行 GrabCut 算法
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 10, cv2.GC_INIT_WITH_RECT)
# 修改掩膜以提取前景
mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
grabcut_result = img * mask2[:, :, np.newaxis]
# 顯示原圖和 GrabCut 結果
show_image(img, "Original Image")
show_image(grabcut_result, "GrabCut Foreground Extraction")
框選想保留的物件位置
先標示前景與背景的區域,設定一個矩形範圍。
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 顯示圖像的函數
def show_image(image, title="Image"):
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.title(title)
plt.axis('off') # 不顯示座標軸
plt.show()
# 讀取圖像
image_path = 'your_image_path.png' # 替換成你的圖像路徑
img = cv2.imread(image_path)
# 初始化掩膜
mask = np.zeros(img.shape[:2], np.uint8)
# 背景和前景模型(由 GrabCut 需要)
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)
# 定義一個矩形來包含前景物體
rect = (350, 200, 300, 300) # 根據圖像大小進行調整 x,y,w,h
# 手動調整掩膜來改善前景檢測
mask[200:500, 350:650] = cv2.GC_FGD # 標記這部分是確定的前景
mask[800:1000, 40:300] = cv2.GC_BGD # 標記這部分是確定的背景
# 再次執行 GrabCut
cv2.grabCut(img, mask, None, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_MASK)
# 修改掩膜以提取前景
mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
grabcut_result = img * mask2[:, :, np.newaxis]
# 顯示原圖和 GrabCut 結果
show_image(img, "Original Image")
show_image(grabcut_result, "GrabCut Foreground Extraction")
設定符合顏色範圍的部分,設定為前景,以下範例設定為紅色的部分,就可只截取氣球的部分了
# 初始化掩膜
mask = np.zeros(img.shape[:2], np.uint8)
# 將圖像轉換為 RGB 色彩空間
RGB_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 定義顏色範圍
lower_color = np.array([150, 0, 0]) # 低閥值
upper_color = np.array([255, 70, 70]) # 高閥值
# 創建遮罩,篩選出符合顏色範圍的部分
mask_red = cv2.inRange(RGB_img, lower_color, upper_color)
# 初始化 GrabCut 所需的掩膜
mask_grabcut = np.zeros(img.shape[:2], np.uint8)
# 使用篩選出的顏色區域更新掩膜,將篩選出的部分設為"可能前景"(cv2.GC_PR_FGD)
mask_grabcut[mask_red > 0] = cv2.GC_PR_FGD