图像分割
-
基于阈值
优点:灰度阈值化,简单,快速,广泛用于硬件处理图像,如: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)