图像的分割与修复
图像分割的基本概念
- 什么是图像分割
将前景物体从背景中分离出来。
- 图像分割的方法
之前的很多方法都是图像分割的前置步骤,比如腐蚀、膨胀、二值化等等。图像分割方法又分为传统的图像分割方法和基于深度学习的图像分割方法。
- 传统的图像分割方法
- 分水岭法
- GrabCut方法
- MeanShift法
- 背景扣除
- 分水岭法原理
上图表示图像有一定的梯度,0代表黑色,代表比较低洼的地方,白色是255,代表一个峰点。当我们使用不同的颜色向低洼处灌水。
当两个低洼处的水要打通的时候,此时这个颜色就会产生一个冲突。在冲突点的地方设置一个边界点,这样就将不同的区域给分割开来。但它也是有问题的。
当图像中存在过多的极小区域而产生许多小的集水盆,但实际上我们真正想要的是一个大块,视为一个整体。但通过分水岭法就可能分成很多的小块。对于传统的分水岭法可能会把一张图切割的很碎,不利于我们后面的处理。
但幸运的是,OpenCV的分水岭法可以将一大块分成一整块。
- 分水岭法的处理步骤
- 标记背景
- 标记前景
- 标记未知域
- 进行分割
现在我们要对这张图片进行分割
代码语言:javascript复制import cv2
import numpy as np
if __name__ == "__main__":
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
img = cv2.imread("/Users/admin/Documents/9527.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化,cv2.THRESH_OTSU表示自适应阈值
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV cv2.THRESH_OTSU)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
# 进行两次开运算
open = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
# 进行一次膨胀
bg = cv2.dilate(open, kernel, iterations=1)
# 获取前景物体,计算非0值到离它距离最近的0值之间的距离
# cv2.DIST_L2为距离的计算方式,这里为欧式距离
# maskSize:扫描时的卷积核大小,L1时用3*3,L2时用5*5
dist = cv2.distanceTransform(open, cv2.DIST_L2, 5)
ret, fg = cv2.threshold(dist, 0.7 * dist.max(), 255, cv2.THRESH_BINARY)
fg = np.uint8(fg)
# 获取未知区域
unknow = cv2.subtract(bg, fg)
# 创建连通域,求所有非0相同像素的连通域,它还有一个参数为连通周围的4个还是
# 8个,默认为8个
ret, marker = cv2.connectedComponents(fg)
marker = 1
marker[unknow == 255] = 0
# 进行图像分割
result = cv2.watershed(img, marker)
img[result == -1] = [0, 0, 255]
while True:
cv2.imshow('img', img)
key = cv2.waitKey()
if key & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
运行结果
GrabCut方法