当前位置: 代码网 > it编程>前端脚本>Python > python-opencv 一种基于聚类的图像过分割解决办法

python-opencv 一种基于聚类的图像过分割解决办法

2024年07月31日 Python 我要评论
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言1. 过分割分析2. 聚类算法前言本文过分割解决办法,主要针对一些目标物在图像中较为分散或比较单一的情况有效。例如血管的过分割,一些杂质颗粒的过分割,较为分散矿石的过分割。如果目标物较为密集也可参考本文,自行改进聚类算法实现过分割的修复。以下例子为杂质颗粒的过分割修复1. 过分割分析 原图 对原图二值化后提取轮廓 开运算膨胀后提取轮廓


前言

本文过分割解决办法,主要针对一些目标物在图像中较为分散或比较单一的情况有效。例如血管的过分割,一些杂质颗粒的过分割,较为分散矿石的过分割。如果目标物较为密集也可参考本文,自行改进聚类算法实现过分割的修复。


以下例子为杂质颗粒的过分割修复

1. 过分割分析

原图
对原图二值化后提取轮廓
开运算膨胀后提取轮廓
原图
对原图二值化后提取轮廓
开运算膨胀后提取轮廓

图中可以看出通过开运算、膨胀后内部一些杂点被消除,但是一些灰度值较低的连接处仍然无法连接在一起,图3中开运算及膨胀采用kernel大小,如下所示:

# 开运算
kernel1 = cv2.getstructuringelement(cv2.morph_ellipse, (3, 3))
# 膨胀
kernel2 = cv2.getstructuringelement(cv2.morph_ellipse, (5, 5))

如果膨胀采用15 x 15的核,效果如下:

膨胀采用15 x 15的核,根据绿色画出的轮廓可以看出,轮廓外扩较多,如果涉及计算该目标物的面积、灰度占比、周长、直径等一些数据,会造成非常大的误差,如果不需要精确计算目标物详细信息,对于圆型目标物可以采用膨胀方式解决过分割。

2. 聚类算法

思想:遍历所有轮廓,根据每个轮廓重心点的距离减两个轮廓最小外接圆的半径,小于阈值的归为一类
聚类算法过程示意图:
在这里插入图片描述

核心代码

# 开运算膨胀,消除二值化图像中小亮点
kernel1 = cv.getstructuringelement(cv.morph_ellipse, (5, 5))
kernel2 = cv.getstructuringelement(cv.morph_ellipse, (3, 3))
image_open = cv.morphologyex(image_thre, cv.morph_open, kernel2, iterations=1)
image_dil = cv.dilate(image_open,kernel1)
_ , contours, hierarchy = cv.findcontours(image_dil, cv.retr_external, cv.chain_approx_simple)
if len(contours) != 0 :
    # 距离相近的轮廓聚类,输出轮廓index
    cnt_idxs = [[idx] for idx in range(len(contours))]  # 轮廓index
    pre_len = len(cnt_idxs)
    while len(cnt_idxs) > 1:
        tmp_cnt_idxs = []
        flags = [false] * len(cnt_idxs)
        for first in range(len(cnt_idxs)):
            for second in range(len(cnt_idxs)):
                if first == second or flags[first] or flags[second]:
                    continue
                is_find = false
                for fidx in cnt_idxs[first]:
                    cnt = contours[fidx]
                    _, radius1 = cv.minenclosingcircle(cnt)
                    # 获取轮空间矩、中心矩、归一化矩
                    m = cv.moments(cnt)
                    # 获取目标重心坐标
                    cx = int(m["m10"] / m["m00"])
                    cy = int(m["m01"] / m["m00"])
                    for sidx in cnt_idxs[second]:
                        new_cnt = contours[sidx]
                        m2 = cv.moments(new_cnt)
                        # 获取目标重心坐标
                        cx2 = int(m2["m10"] / m2["m00"])
                        cy2 = int(m2["m01"] / m2["m00"])
                        _, radius2 = cv.minenclosingcircle(new_cnt)
                        sq1 = (cx2 - cx) * (cx2 - cx)
                        sq2 = (cy2 - cy) * (cy2 - cy)
                        # 两轮廓中心点距离
                        dist = math.sqrt(sq1 + sq2)
                        # print("dist:{0:.2f}".format(dist))
                        if dist - radius2 - radius1 < 30:
                            is_find = true
                            tmp_cnt_idxs.append(cnt_idxs[first] + cnt_idxs[second])
                            flags[first] = flags[second] = true
                            break
                    if is_find:
                        break
        for idx, flag in enumerate(flags):
            if not flag:
                tmp_cnt_idxs.append(cnt_idxs[idx])
        cnt_idxs = tmp_cnt_idxs
        if pre_len == len(cnt_idxs):
            break
        else:
            pre_len = len(cnt_idxs)

膨胀和本文聚类算法对比

采用膨胀的方法造成轮廓选取偏差较大,影响精准计算


(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com