目录
一、分水岭算法
二、GrabCut
res = cv.watershed(image,markers)
参数:
返回:
自动分割的步骤:
代码:
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
# 1.读入图片
img = cv.imread(r"D:\Desktop\00aa\1.png")
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 2.canny边缘检测
canny = cv.Canny(gray_img, 80, 150)
# 3.轮廓检测并设置标记图像
# 寻找图像轮廓 返回修改后的图像 图像的轮廓 以及它们的层次
contours, hierarchy = cv.findContours(canny, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
# 32位有符号整数类型,
marks = np.zeros(img.shape[:2], np.int32)
# findContours检测到的轮廓
imageContours = np.zeros(img.shape[:2], np.uint8)
# 轮廓颜色
compCount = 0
index = 0
# 绘制每一个轮廓
for index in range(len(contours)):
# 对marks进行标记,对不同区域的轮廓使用不同的亮度绘制,相当于设置注水点,有多少个轮廓,就有多少个轮廓
# 图像上不同线条的灰度值是不同的,底部略暗,越往上灰度越高
marks = cv.drawContours(marks, contours, index, (index, index, index), 1, 8, hierarchy)
# 绘制轮廓,亮度一样
imageContours = cv.drawContours(imageContours, contours, index, (255, 255, 255), 1, 8, hierarchy)
# 4 使用分水岭算法,并给不同的区域随机填色
# cv.watershed(输入图像,标记图像)
marks = cv.watershed(img, marks)
# 实现图像增强等相关操作的快速运算 图像sobely转换回灰度
afterWatershed = cv.convertScaleAbs(marks)
# 生成随机颜色
colorTab = np.zeros((np.max(marks) + 1, 3))
# 生成0~255之间的随机数
for i in range(len(colorTab)):
aa = np.random.uniform(0, 255)
bb = np.random.uniform(0, 255)
cc = np.random.uniform(0, 255)
colorTab[i] = np.array([aa, bb, cc], np.uint8)
bgrImage = np.zeros(img.shape, np.uint8)
# 遍历marks每一个元素值,对每一个区域进行颜色填充
for i in range(marks.shape[0]):
for j in range(marks.shape[1]):
# index值一样的像素表示在一个区域
index = marks[i][j]
# 判断是不是区域与区域之间的分界,如果是边界(-1),则使用白色显示
if index == -1:
bgrImage[i][j] = np.array([255, 255, 255])
else:
bgrImage[i][j] = colorTab[index]
# 5 图像显示
plt.imshow(bgrImage[:, :, ::-1])
plt.title('result')
plt.xticks([]), plt.yticks([])
plt.show()
分割结果如下所示:
GrabCut算法的优势是:
1、只需要在目标外面画一个框,把目标框住,它就可以完成良好的分割:
2、如果增加额外的用户交互(由用户指定一些像素属于目标),那么效果会更好
3、它的边界处理技术会使目标分割边界更加自然和柔和:
该算法也有不完美的地方,如果背景比较复杂或者背景和目标的相似度很大,那分割效果就不好,而且该算法的速度较慢。
在openCV中实现GrabCut算法,使用的API:
grabCut(img,mask,rect,bgdModel,fgdModel,iterCount,mode )
参数:
代码演示:
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
# 1. 读取图片
img = cv.imread(r"D:\Desktop\00aa\1.png")
# 2. 掩码图像
mask = np.zeros(img.shape[:2], np.uint8)
print(img.shape[:2])
# 3.矩形窗口(x,y,w,h);
rect = [0, 0, 389, 582] # 全图显示,但是要注意,利用img.shape[:2]获取图像大小后,维度都需要减1才能填入w,h。利用shape获取的维度是h,w
# 4.物体分割
cv.grabCut(img, mask, tuple(rect), None, None, 5, cv.GC_INIT_WITH_RECT)
# 5.抠取图像
mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
img_show = img * mask2[:, :, np.newaxis]
# 将矩形框绘制在图像上
cv.rectangle(img, (0, 0), (389, 582), (0, 255, 0), 3)
# # 6.图像显示
plt.figure(figsize=(10, 8), dpi=100)
plt.subplot(121), plt.imshow(img[:, :, ::-1]), plt.title('矩形框选位置')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(img_show[:, :, ::-1]), plt.title('抠取结果')
plt.xticks([]), plt.yticks([])
plt.show()
参考:图像分割