Python 使用Opencv的GrabCut 算法实现前景检测以及分水岭算法实现图像分割

本人新书《玩转Python网络爬虫》,可在天猫、京东等商城搜索查阅,项目深入浅出,适合爬虫初学者或者是已经有一些网络爬虫编写经验,但希望更加全面、深入理解Python爬虫的开发人员。
这里写图片描述

———-欢迎加入学习交流QQ群:657341423


OpenCV的前景检测是由grabCut函数实现。grabCut是一种算法,算法原理说明如下:
这里写图片描述这里写图片描述


函数原型:

grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode=None)

img - 输入图像
mask-掩模图像,用来确定那些区域是背景,前景,可能是前景/背景等。可以设置为:cv2.GC_BGD,cv2.GC_FGD,cv2.GC_PR_BGD,cv2.GC_PR_FGD,或者直接输入 0,1,2,3 也行。
rect - 包含前景的矩形,格式为 (x,y,w,h)
bdgModel, fgdModel - 算法内部使用的数组. 你只需要创建两个大小为 (1,65),数据类型为 np.float64 的数组。
iterCount - 算法的迭代次数
mode - cv2.GC_INIT_WITH_RECT 或 cv2.GC_INIT_WITH_MASK,使用矩阵模式还是蒙板模式。


示例一

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('varese.jpg')
mask = np.zeros(img.shape[:2], np.uint8)

# zeros(shape, dtype=float, order='C'),参数shape代表形状,(1,65)代表1行65列的数组,dtype:数据类型,可选参数,默认numpy.float64
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)

rect = (1, 1, img.shape[1], img.shape[0])
# 函数原型:grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode=None)
# img - 输入图像
# mask-掩模图像,用来确定那些区域是背景,前景,可能是前景/背景等。可以设置为:cv2.GC_BGD,cv2.GC_FGD,cv2.GC_PR_BGD,cv2.GC_PR_FGD,或者直接输入 0,1,2,3 也行。
# rect - 包含前景的矩形,格式为 (x,y,w,h)
# bdgModel, fgdModel - 算法内部使用的数组. 你只需要创建两个大小为 (1,65),数据类型为 np.float64 的数组。
# iterCount - 算法的迭代次数
# mode cv2.GC_INIT_WITH_RECT 或 cv2.GC_INIT_WITH_MASK,使用矩阵模式还是蒙板模式。
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 10, cv2.GC_INIT_WITH_RECT)

# np.where 函数是三元表达式 x if condition else y的矢量化版本
# result = np.where(cond,xarr,yarr)
# 当符合条件时是x,不符合是y,常用于根据一个数组产生另一个新的数组。
# | 是逻辑运算符or的另一种表现形式
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
# mask2[:, :, np.newaxis] 增加维度
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('varese.jpg'), cv2.COLOR_BGR2RGB))
plt.title("original"), plt.xticks([]), plt.yticks([])
plt.show()

这里写图片描述
参数mask的x、y坐标设置和参数iterCount 的设置都对前景检测有一定的影响。

在上述例子中,还可以将函数参数mode 改为GC_INIT_WITH_MASK模式实现,可参考:链接地址


分水岭算法实现图像分割
分水岭算法原理解释:请点击
示例二

import numpy as np
import cv2
from matplotlib import pyplot as plt

# 参考教程:https://blog.csdn.net/u010682375/article/details/72765064
img = cv2.imread('basil.jpg')
# 图片灰度处理
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# threshold函数是二化值处理
# ret, dst = cv2.threshold(src, thresh, maxval, type)
# 参数说明:
# src:输入图,只能输入单通道图像,通常来说为灰度图
# dst:输出图
# thresh:阈值
# maxval:当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
# type:二值化操作的类型,包含以下5 种类型:cv2.THRESH_BINARY;cv2.THRESH_BINARY_INV;cv2.THRESH_TRUNC;cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
# 生成3x3的核
kernel = np.ones((3, 3), np.uint8)
# morphologyEx函数是图像进行膨胀后再腐蚀的操作,去除噪声数据,参考https://blog.csdn.net/u010682375/article/details/70026569
# 参数src:二值化后的图像
# 参数op:形态运算的类型
# 参数iterations:腐蚀次数和膨胀次数
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)

# dilate函数是膨胀,与morphologyEx的作用相似
sure_bg = cv2.dilate(opening,kernel,iterations=3)

# 确认背景区域位置,distanceTransform函数是距离变换,参考https://blog.csdn.net/liubing8609/article/details/78483667
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
# threshold函数是二化值处理
ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)

# Finding unknown region
sure_fg = np.uint8(sure_fg)
# subtract计算两个数组或数组和标量之间的元素差异,这里计算背景和前景的差异值
unknown = cv2.subtract(sure_bg, sure_fg)

# 标记
ret, markers = cv2.connectedComponents(sure_fg)

# Add one to all labels so that sure background is not 0, but 1
markers = markers + 1

# Now, mark the region of unknown with zero
markers[unknown==255] = 0
# watershed实现分水岭算法
markers = cv2.watershed(img, markers)
img[markers == -1] = [255,0,0]
# 显示图像
plt.imshow(img)
plt.show()

运行结果:
这里写图片描述
从结果看到,有些叶子能分割很好,有些叶子是无法分割。

猜你喜欢

转载自blog.csdn.net/huangzhang_123/article/details/80535269