圖像分割
-
基於閾值
優點:灰度閾值化,簡單,快速,廣泛用於硬件處理圖像,如:FPGA實時圖像處理
場景:各個物體不接觸,物體和背景灰度值差別較明顯,閾值處理效果好 -
基於邊緣
返回結果:邊緣檢測的結果是點,不能作為圖像分割的點,需要進一步處理,將邊緣點沿着圖形邊界連接,形成邊緣鏈。
檢測算子: Sobel, Laplace, Canny
import cv2 as cv
import numpy as np
# 基於閾值
def water_shed(img_path):
img = cv.imread(img_path)
# 原圖灰度處理,輸出單通道圖片
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 二值化處理Otsu算法
reval_0, dst_otsu = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV|cv.THRESH_OTSU)
# 二值化處理Triangle算法
reval_t, dst_tri = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV|cv.THRESH_TRIANGLE)
# 滑動窗口尺寸
kernel = np.ones((3, 3), np.uint8)
# 形態學處理:開處理,膨脹邊緣
opening = cv.morphologyEx(dst_tri, cv.MORPH_OPEN, kernel, iterations=2)
# 膨脹處理背景區域
dilate_bg = cv.dilate(opening, kernel, iterations=3)
# 計算開處理圖像到鄰域非零像素距離
dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5)
# 正則處理
norm = cv.normalize(dist_transform, 0, 255, cv.NORM_MINMAX)
# 閾值處理距離圖像,獲取圖像前景圖
retval_D, dst_fg = cv.threshold(dist_transform, 0.5 * dist_transform.max(), 255, 0)
# 前景圖格式轉換
dst_fg = np.uint8(dst_fg)
# 未知區域計算:背景減去前景
unknown = cv.subtract(dilate_bg, dst_fg)
cv.imshow("Difference value", unknown)
cv.imwrite(r'D:\workplace\data\opencv\unknown_reginon.png', unknown)
# 處理連接區域
retval_C, marks = cv.connectedComponents(dst_fg)
cv.imshow('Connect marks', marks)
cv.imwrite(r'D:\workplace\data\opencv\connect_marks.png', marks)
# 處理掩模
marks = marks + 1
marks[unknown == 255] = 0
cv.imshow("marks undown", marks)
# 分水嶺算法分割
marks = cv.watershed(img, marks)
# 繪制分割線
img[marks == -1] = [255, 0, 255]
cv.imshow("Watershed", img)
cv.imwrite(r'D:\workplace\data\opencv\watershed.png', img)
cv.waitKey(0)
# 基於邊緣
def cutImage(sourceDir):
# 讀取圖片
img = cv.imread(sourceDir)
# 灰度化
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 高斯模糊處理:去噪(效果最好)
blur = cv.GaussianBlur(gray, (9, 9), 0)
# Sobel計算XY方向梯度
gradX = cv.Sobel(gray, ddepth=cv.CV_32F, dx=1, dy=0)
gradY = cv.Sobel(gray, ddepth=cv.CV_32F, dx=0, dy=1)
# 計算梯度差
gradient = cv.subtract(gradX, gradY)
# 絕對值
gradient = cv.convertScaleAbs(gradient)
# 高斯模糊處理:去噪(效果最好)
blured = cv.GaussianBlur(gradient, (9, 9), 0)
# 二值化
_ , dst = cv.threshold(blured, 90, 255, cv.THRESH_BINARY)
# 滑動窗口
kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE, (107, 76))
# 形態學處理:形態閉處理(腐蝕)
closed = cv.morphologyEx(dst, cv.MORPH_CLOSE, kernel)
# 腐蝕與膨脹迭代
closed = cv.erode(closed, None, iterations=4)
closed = cv.dilate(closed, None, iterations=4)
# 獲取輪廓
_, cnts, _ = cv.findContours(closed.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
c = sorted(cnts, key=cv.contourArea, reverse=True)[0]
rect = cv.minAreaRect(c)
box = np.int0(cv.boxPoints(rect))
draw_img = cv.drawContours(img.copy(), [box], -1, (0, 0, 255), 3)
cv.imshow("Box", draw_img)
cv.imwrite(r'D:\workplace\data\opencv\monkey.png', draw_img)
cv.waitKey(0)
if __name__ == '__main__':
sourceDir = r"D:\workplace\data\opencv\football.jpg"
cutImage(sourceDir)
