当前位置:首页 » 《资源分享》 » 正文

OpenCV图像处理之——分水岭算法的图像分割_程序媛一枚~的博客

20 人参与  2021年09月26日 12:43  分类 : 《资源分享》  评论

点击全文阅读


OpenCV图像处理之——分水岭算法的图像分割

    • 1. 效果图
    • 2. 原理
    • 3. 源码
    • 参考

这篇博客将介绍如何使用分水岭算法进行基于标记的图像分割,OpenCV通过cv2.watershed()实现;

1. 效果图

官方示例——水果分割 效果图如下:

共分了8块,可交互式的进行分割;
在这里插入图片描述
在这里插入图片描述

原图 VS 硬币分割效果图如下:

可以看到有的硬币及边界被正确检测,有的并没有;(检测圆并不推荐用霍夫圆方法检测,而推荐用Canny边缘检测,这是在阈值化等处理后,有的边缘并不是特别规则的圆)

在这里插入图片描述
硬币检测过程图如下:
分别为:原始图 VS 灰度图 VS 阈值化图 VS 形态学Opening图
确定背景图 VS 距离阈值图 VS 确定前景图 VS 未知区域
标记图 VS 标记边界图 VS 分水岭结果图

  • 1 origin:原始的RGB图
  • 2 gray:灰度图
  • 3 thresh:简单轮廓检测前置步骤:背景与前景分离
  • 4 opening 形态学开操作,去除对象中的任何小孔
  • 5 sure_bg 膨胀将对象边界增加到背景,得到确定的背景
  • 6 distance transform 距离变换图,可以找到确定的前景,也可以找到互相有关联的前景;
  • 7 sure_fg 找到距离变换并应用适当的阈值或者腐蚀,以找到确定的前景
  • 8 unknown 确定背景-确定前景,得到未知区域图
  • 9 markers 对未知区域进行标记(背景深蓝色,前景浅蓝色)
  • 10 marker boundaries 深蓝色区域表示未知区域。确定背景的剩余区域以浅蓝色显示。
  • 11 res 应用分水岭算法得到结果,边界区域被标记为-1;

在这里插入图片描述

2. 原理

在某些情况下,可能只对前景分割感兴趣,而不是对相互接触的对象进行分离。在这种情况下,不需要使用距离变换,只需要腐蚀就足够了。腐蚀只是另一种提取全部确定前景区域的方法。

可以看到左图距离变换能找到相互接触的对象(硬币是有互相粘连的地方);
在这里插入图片描述

3. 源码

# 分水岭算法

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

dict = {}
img = cv2.imread('coins.jpg')
cv2.imshow("origin", img)
dict['origin'] = img
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
dict['gray'] = gray
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
dict['thresh'] = thresh

# 去掉噪音
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
dict['opening'] = opening

# 寻找确定的背景
sure_bg = cv2.dilate(opening, kernel, iterations=3)
dict['sure_bg'] = sure_bg

# 寻找确定的前景区域
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)
dict['dist_transform'] = dist_transform
dict['sure_fg'] = sure_fg

# 用背景减前景,得到不确定的区域
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)
dict['unknown'] = unknown

# 创建标记(它是一个与原始图像大小相同的数组,但数据类型为 int32)并标记其中的区域。
# 标记背景、不确定对象(默认背景为0,其他为1)
ret, markers = cv2.connectedComponents(sure_fg)
dict['markers'] = markers

# 对所有标签加1,将得到背景为1
markers = markers + 1

# 标记未知区域为0
markers[unknown == 255] = 0

# 应用分水岭算法,然后标记图像,边界区域将被标记为-1
markers = cv2.watershed(img, markers)
img[markers == -1] = [255, 0, 0]
cv2.imshow("watershed res", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
dict['marker boundaries'] = markers
dict['res'] = img

size = len(dict)
print(size, '\n')
for i, key in enumerate(dict):
    print(i + 1, key, len(list(dict[key].shape)))
    plt.subplot(3, 4, i + 1)
    if (len(list(dict[key].shape)) > 2):  # 由于matplot需要RGB以显示彩色图,而OpenCV是用BGR来表示彩色图的
        plt.imshow(cv2.cvtColor(dict[key], cv2.COLOR_BGR2RGB))  # 为确保正确显示RGB图,进行颜色空间转换
    else:
        plt.imshow(dict[key])
    plt.title(key)  # 图片的标题
    plt.xticks([])  # 去掉x轴的刻度
    plt.yticks([])  # 去掉y轴的刻度
plt.show()

参考

  • https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_imgproc/py_watershed/py_watershed.html#watershed
  • https://github.com/seminar2012/opencv/blob/master/samples/python/watershed.py

点击全文阅读


本文链接:http://zhangshiyu.com/post/28711.html

区域  标记  前景  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1