运用GrabCut轻松玩转抠图(python实现)

冒泡~好像是很久没有写...在实验室一周多了...在不断地安装环境和库,其他没有太大的进展,今天在做显著性图片的提取中,发现了grabcut的函数可以用来抠图,做个小笔记。

GrabCut

简介

GrabCut该算法利用了图像中的纹理(颜色)信息和边界(反差)信息,只要小量的用户交互操作即可得到比较好的分割效果

算法原理

运用GrabCut轻松玩转抠图(python实现)_第1张图片

运用GrabCut轻松玩转抠图(python实现)_第2张图片

补充说明:
【a.矩形外的所有区域肯定是背景。矩形框内的东西是未知的。同样用户确定前景和背景的任何操作都不会被程序改变。
b.根据我们的输入,GMM会学习并创建新的像素分布。对那些分类未知的像素(可能是前景也可能是背景),可以根据他们与已知分类(如背景)的像素关系来进行分类(就想在做聚类操作)。
c.图中的节点就是像素点。除了像素点做节点之外还有两个节点:Source_node和Sink_node。所有的前景像素都和Source_node相连。所有的背景像素都和sink_node相连。
d.两个像素之间的权重由边的信息或者两个像素的相似性来决定。如果两个像素的颜色有很大的不同,那么它们之间的边的权重就会很小。】

具体的算法原理可参考(https://www.cnblogs.com/mikewolf2002/p/3341418.html)

函数原型

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

解释

img:待分割的源图像,必须是8位3通道(CV_8UC3)图像,在处理的过程中不会被修改;
mask:掩码图像,如果使用掩码进行初始化,那么mask保存初始化掩码信息;在执行分割的时候,也可以将用户交互所设定的前景与背景保存到mask中,然后再传入grabCut函数;在处理结束之后,mask中会保存结果。
mask只能取以下四种值:
GCD_BGD(=0),背景;
GCD_FGD(=1),前景;
GCD_PR_BGD(=2),可能的背景;
GCD_PR_FGD(=3),可能的前景。
如果没有手工标记GCD_BGD或者GCD_FGD,那么结果只会有GCD_PR_BGD或GCD_PR_FGD;
rect:用于限定需要进行分割的图像范围,只有该矩形窗口内的图像部分才被处理;
bgdModel:背景模型,如果为null,函数内部会自动创建一个bgdModel;bgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5;
fgdModel:前景模型,如果为null,函数内部会自动创建一个fgdModel;fgdModel必须是单通道浮点型(CV_32FC1)图像,且行数只能为1,列数只能为13x5;
iterCount:迭代次数,必须大于0;
mode:用于指示grabCut函数进行什么操作,可选的值有:
GC_INIT_WITH_RECT(=0),用矩形窗初始化GrabCut;
GC_INIT_WITH_MASK(=1),用掩码图像初始化GrabCut;
GC_EVAL(=2),执行分割。

代码实现

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

img = cv2.imread('F:/8.jpg')
OLD_IMG = img.copy()
mask = np.zeros(img.shape[:2], np.uint8)
SIZE = (1, 65)
bgdModle = np.zeros(SIZE, np.float64)
fgdModle = np.zeros(SIZE, np.float64)
rect = (1, 1, img.shape[1], img.shape[0])
cv2.grabCut(img, mask, rect, bgdModle, fgdModle, 10, cv2.GC_INIT_WITH_RECT)

mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
img *= mask2[:, :, np.newaxis]

plt.subplot(121), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title("grabcut"), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(cv2.cvtColor(OLD_IMG, cv2.COLOR_BGR2RGB))
plt.title("original"), plt.xticks([]), plt.yticks([])

plt.show()

效果图

运用GrabCut轻松玩转抠图(python实现)_第3张图片
运用GrabCut轻松玩转抠图(python实现)_第4张图片
运用GrabCut轻松玩转抠图(python实现)_第5张图片

改变iterCount(迭代)的次数可以改变抠图的精准度
(不足,迭代次数越多 运行所耗的时间更长)
迭代10次

运用GrabCut轻松玩转抠图(python实现)_第6张图片

迭代100次
运用GrabCut轻松玩转抠图(python实现)_第7张图片

N次之后
运用GrabCut轻松玩转抠图(python实现)_第8张图片

参考资料(https://blog.csdn.net/HuangZhang_123/article/details/80535269)
(https://blog.csdn.net/sunshine_in_moon/article/details/45200793)

Ending~
感觉实验是要做不出来了,只能祈祷毕设顺利了。

你可能感兴趣的:(运用GrabCut轻松玩转抠图(python实现))