【OpenCV-Python】17 使用分水岭和CrabCut算法进行物体分割

GrabCut算法的实现步骤

  1. 在图片中定义含有(一个或多个)物体的矩形;
  2. 矩形外的区域被自动认为是背景;
  3. 对于用户定义的矩形区域,可用背景中的数据来区别它里面的前景和背景区域;
  4. 用高斯混合模型(Guassians Mixture Model, GMM)来对背景和前景建模,并将未定义的像素标记为可能的前景或背景的概率;
  5. 图像中的每一个像素都被看作通过虚拟边与周围像素相连接,而每条边都有一个属于前景或背景的概率,这基于它与周边像素颜色的相似性;
  6. 每一个像素(即算法中的节点)会与一个前景或背景节点连接;
  7. 在节点完成连接后(可能与背景或前景连接),在节点之间的边属于不同终端(一个节点属于前景,一个节点属于背景),则会切断它们之间的边(切割),这就能将图像各部分分割出来。在这里插入图片描述

使用GrabCut进行前景检测

提取图中的雕像图并消除背景。实例化GrabCut,进行分割,然后把结果和原图像一起展示。

代码

# -*- coding: utf-8 -*-
"""
Created on Thu Dec 31 10:01:14 2020

@author: gkm0120
"""
import numpy as np
import cv2
from matplotlib import pyplot as plt

# 加载图像。创建与加载图像同形状的掩模,并用0填充
img = cv2.imread('D:/Python/Test_code/pycv/images/statue.jpg')
mask = np.zeros(img.shape[:2],np.uint8)
# 创建以0填充的前景和背景模型
bgdModel = np.zeros((1,65),np.float64)
fgdModel = np.zeros((1,65),np.float64)
# 用一个标识出想要隔离的对象的矩形来初始化GrabCut算法
rect = (100,50,421,378)
# 使用指定的空模型和掩模来运行GrabCut算法,并且实际上使用矩形初始化这个操作
# cv2.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode=None)
# model 可以是cv2.GC_INIT_WITH_RECT或cv2.GC_INIT_WITH_MASK,即使用矩形形式或掩码形式
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)

#此时掩模已经变成包含0~3之间的数。值为0和2的将转为0,值为1和3的将转为1,然后保存在mask中,然后可用mask2过滤出所有的0像素
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask2[:,:,np.newaxis]
# 并排显示两张图片
plt.subplot(121), plt.imshow(img)
plt.title("grabcut"), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(cv2.cvtColor(cv2.imread("D:/Python/Test_code/pycv/images/statue.jpg"), cv2.COLOR_BGR2RGB))
plt.title("original"), plt.xticks([]), plt.yticks([])
plt.show()

图例

在这里插入图片描述

使用分水岭算法进行图像分割

分水岭算法:把图像中低密度的区域(变化很少)想象成山谷,把图像中高密度的区域(变化很多)想象成山峰。开始向山谷注入水直到不同的山谷水开始汇聚。为阻止不同山谷的水汇聚,可以设置一些栅栏,最后得到的栅栏就是图像分割。

利用图像分割将这些叶子从白色背景里分离出来。

代码

"""
Created on Thu Dec 31 12:41:19 2020

@author: gkm0120
"""
import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread("D:/Python/Test_code/pycv/images/basil.jpg")
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 将图像转为灰度后,设置一个阈值,将图像分为两部分:黑色部分、白色部分
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# 利用morphologyEx变换去除噪声(一种对图像膨胀之后再进行腐蚀的操作,可以提取图像特征)
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)

# 确定背景区域
sure_bg = cv2.dilate(opening,kernel,iterations=3)

# 确定前景区域
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)

# 确定未知区域(前景与背景重合部分)
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg,sure_fg)

# 标记标签(给出一些确定的前景区域,其中一部分节点会连接在一起,另一些节点没有连接在一起,意味着它们属于不同的山谷)
ret, markers = cv2.connectedComponents(sure_fg)

# 在背景区域加1
markers = markers+1

# 用零标记未知区域,让水漫起来并把栅栏绘成红色
markers[unknown==255] = 0
markers = cv2.watershed(img,markers)
img[markers == -1] = [255,0,0]

plt.imshow(img)
plt.show()

图例

原图
分割图
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值