图像的分割与修复
1. 图像分割的基本概念
图像分割: 将前景物体从背景中分离出来.
图像分割分为传统图像分割和基于深度学习的图像分割方法.
传统图像分割就是使用OpenCV进行的图像分割.
传统图像分割方法有:
- 分水岭法
- GrabCut法
- MeanShift法
- 背景扣除
2. 分水岭法
分水岭分割方法是基于图像形态学和图像结构来实现的一种图像分割方法.
现实中我们可以或者说可以想象有山有湖的景象,那么那一定是水绕山,山围水的情形。当然在需要的时候,要人工构筑分水岭,以防集水盆之间的互相穿透。而区分高山(plateaus)与水的界线,以及湖与湖之间的间隔或 都是连通的关系,就是分水岭(watershed)。
我们绘制灰度图像的梯度图, 可以得到近似下图的梯度走势.梯度低的地方我们可以认为是低洼区或者山谷, 梯度高的地方可以认为是山峰. 我们往山谷中注水, 为了防止山谷中的水溢出汇合我们可以在汇合的地方筑起堤坝, 可将堤坝看做是对图像分割后形成的边界. 这就是分水岭算法的基本原理.
分水岭法的问题
OpenCV中的分水岭法已经解决此问题.
分水岭法涉及的API
- distanceTransform(img, distanceType, maskSize)计算img中非零值到距离它最近的0值之间的距离
- img 要处理的图像
- distanceType 计算距离的方式: DIST_L1, DIST_L2
- maskSize:进行扫描时的kernel的大小, L1用3, L2用5
- connectedComponents(image[, labels[, connectivity[, ltype]]]) 求连通域, 用0标记图像的背景,用大于0的整数标记其他对象
- connectivity: 4, 8(默认)
- watershed(image, markers) 执行分水岭法
- markers: 它是一个与原始图像大小相同的矩阵,int32数据类型,表示哪些是背景哪些是前景。分水岭算法将标记的0的区域视为不确定区域,将标记为1的区域视为背景区域,将标记大于1的正整数表示我们想得到的前景。
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('water_coins.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh =cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
# 有一些细小的噪点和毛边
cv2.imshow('thresh', thresh)
# 通过开运算去掉噪点
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
cv2.imshow('opening', opening)
bg = cv2.dilate(opening, kernel, iterations=2) # sure background area
fg = cv2.erode(opening, kernel, iterations=2) # sure foreground area
# 剩下的区域(硬币的边界附近)还不能确定是前景还是背景。可通过膨胀图减去腐蚀图得到,下图中的白色部分为不确定区域
unknown = cv2.subtract(bg, fg) # 未知区域
cv2.imshow('gg', np.hstack((bg