python+opencv实现高斯混合(GMM)图像分割

前言

最近想学习一点图像分割方面的知识。网上看了一圈,发现GMM实现图像分割的算法在C++/opencv上实现的案例很多,暂时没有发现python实现的。结合C++版本的语法和对算法的理解,花了半个下午时间,使用python实现了一下,在此记录一下。我们的目的是给下图这位漂亮小姐姐的证件照换一个绿色的背景
请添加图片描述

原理

原理部分这里就不细讲了。小破站up主shuhuai008在这方面有非常详细的讲解,有兴趣的同学可以去看看。主要思想就是对当前图片各像素RGB分布按照最大似然拟合出一个最可能的混合高斯分布,然后在反推这些像素分别来自于哪个高斯分布,进行分类。

https://www.bilibili.com/video/BV13b411w7Xj/?spm_id_from=333.337.search-card.all.click&vd_source=d8ac0ff430c94b044512c4edabc63f35

第一步代码实现

在得到像素分类标签best后,找到像素数量最大(即面积最大)的类别,视为背景

import cv2
import numpy as np
import matplotlib.pyplot as plt
def GMM(img):
    print(img.shape)
    # 将一个像素点的rgb值作为一个单元处理
    data = img.reshape((-1, 3))
    print(data.shape)
    # 转换数据类型
    data = np.float32(data)
    # 生成模型
    em = cv2.ml.EM_create()
    # 设置参数,将像素分成num个类别
    num = 3
    em.setClustersNumber(num)
    em.setCovarianceMatrixType(cv2.ml.EM_COV_MAT_GENERIC)  # 默认
    # 训练返回的第三个元素包含了预测分类标签
    best = em.trainEM(data)[2]
    # 筛选出面积最大的一个分类(即认为背景是面积最大的)
    index = 0
    length = len(data[best.ravel() == 0])
    for i in range(0, num):
        if len(data[best.ravel() == i]) > length:
            length = len(data[best.ravel() == i])
            index = i
    # 设置为绿色
    data[best.ravel() == index] = (0, 255, 0)
    # 将结果转换为图片需要的格式
    data = np.uint8(data)
    oi = data.reshape(img.shape)
    # show('img',img)
    # show('res',oi)
    cv2.imshow('img', img)
    cv2.imshow('res', oi)
    cv2.waitKey()
    
if __name__ == '__main__':
    img = cv2.imread("../img/certificate_photo2.jpg")
    GMM(img)

在这里插入图片描述
已经有点意思了!但是周边还是毛糙了一点。

第二步代码实现,周边去毛糙

仔细想一下,其实对于这个问题完全可以直接像素二分类,也就是背景和人物两类像素,这样分类更简单,边界也应该更清晰。于是,修改上述代码参数num为2

num = 2

再试试看,结果会是啥样子呢?
请添加图片描述我去,小姐姐直接绿了。不过聪明的各位应该也知道为什么了吧?
原因就是,刚才的算法认为面积最大的是背景。这里小姐姐所占据的像素面积大于背景了,所以算法误认为人像是背景了,那就在改下吧!

第三步代码实现,重新筛选背景

实现起来比较笨,不过也很简单,就是吧面积小的作为背景呗~

    for i in range(0, num):
        if len(data[best.ravel() == i]) < length:
            length = len(data[best.ravel() == i])
            index = i

这次应该没毛病了
请添加图片描述嗯!效果还可以。

总结

对于背景和前景的选择,我目前只是实现了非常简单的判断方法,更多精妙的idea欢迎各位大佬在评论区交流。
另外个人觉得GMM分割可能并不是非常擅长与背景分割的工作(至少存在很多bug)。比如背景色不够重,和肤色接近,那么分割必然会出现很多问题。实际上我找了网上其他一些证件照尝试,确实效果不尽如人意。这可能也是网上大量教程案例都选择这张图片的原因吧!将来发现更好的方法我会持续更新的!

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值