目录
一、分水岭算法
二、GrabCut
一、分水岭算法
res = cv.watershed(image,markers)
参数:
- image: 输入图像,必须是8位的3通道彩色图像
- marker: 标记图像,32位单通道图像,它包括种子点信息,使用轮廓信息作为种子点。在进行分水岭算法之前,必须设置好marker信息,它包含不同区域的轮廓,每个轮廓有唯一的编号,使用findCountours方法确定轮廓位置,不同区域的交界位置为-1
返回:
- res: 图像分割之后的结果
自动分割的步骤:
- 对原图像进行灰度化处理,并进行边缘检测或二值化
- 查找轮廓,并且把轮廓信息按不同的编号绘制在标记图像上,即标记种子点,将其传给marker参数
- 进行分水岭算法检测
- 绘制分割出来的区域,使用随机颜色进行填充
代码:
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
GrabCut算法的优势是:
1、只需要在目标外面画一个框,把目标框住,它就可以完成良好的分割:
2、如果增加额外的用户交互(由用户指定一些像素属于目标),那么效果会更好
3、它的边界处理技术会使目标分割边界更加自然和柔和:
该算法也有不完美的地方,如果背景比较复杂或者背景和目标的相似度很大,那分割效果就不好,而且该算法的速度较慢。
在openCV中实现GrabCut算法,使用的API:
grabCut(img,mask,rect,bgdModel,fgdModel,iterCount,mode )
参数:
- img:输入图像,必须是8位的3通道彩色图像
- mask: 掩码图像,如果使用掩码进行初始化,那么mask保存初始化掩码信息;也可以将用户交互所设定的前景与背景保存到mask中,然后再传入grabCut函数;在处理结束之后,mask中会保存结果。mask只能取以下四种值:
- rect:用于限定需要进行分割的图像范围,只有该矩形窗口内的图像部分才被处理
- bgdModel:背景模型,如果为None,函数内部会自动创建一个bgdModel;bgdModel必须是单通道浮点型图像,且行数只能为1,列数只能为13x5
- fgdModel:前景模型,如果为None,函数内部会自动创建一个fgdModel;fgdModel必须是单通道浮点型图像,且行数只能为1,列数只能为13x5
- iterCount:迭代次数,必须大于0
- mode:指明grabcut函数进行哪种操作,如下所示:
代码演示:
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()
文章来源:https://www.toymoban.com/news/detail-818778.html
参考:图像分割文章来源地址https://www.toymoban.com/news/detail-818778.html
到了这里,关于基于OpenCV的图像分割(分水岭算法和GrabCut)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!