从零开始学cv-15:图像分割


前言

在当代计算机视觉领域,图像分割技术扮演着至关重要的角色,它为图像理解、目标识别和场景解析等高级视觉任务提供了基础。OpenCV,作为一款广泛应用于工业和学术界的开源计算机视觉库,提供了丰富的算法和工具,使得图像分割技术的实现变得更为便捷和高效,本文旨在深入探讨OpenCV在图像分割方面的应用,从理论到实践,全面剖析各种分割算法的实现原理和操作步骤。

一、全局阈值分割:

全局阈值分割是一种基本的图像分割方法,它将图像中的像素分为两类:前景和背景。这种分割方法基于一个全局阈值,该阈值适用于图像中的所有像素。
步骤:

  1. 选择阈值:选择一个灰度值作为阈值。这个值可以是固定的,也可以通过某种算法自动确定,例如Otsu方法。
  2. 应用阈值:对于图像中的每个像素,如果像素的灰度值大于或等于阈值,则将其分类为前景;如果小于阈值,则分类为背景。

在opencv中提供了其api:ret, thresh = cv2.threshold(img, threshold_value, 255, cv2.THRESH_BINARY):
参数说明:
src: 输入图像,通常是 8 位单通道图像(灰度图像)。
thresh: 阈值,用于决定像素是否被设置为 maxval 或 0。
maxval: 当像素值超过阈值时,要赋予的像素值。通常对于二值图像,这个值是 255。
type: 阈值类型,决定了如何处理阈值操作。以下是几种常见的阈值类型:

  1. cv2.THRESH_BINARY: 如果像素值大于阈值,则将其设置为 maxval;否则设置为 0。
  2. cv2.THRESH_BINARY_INV: 如果像素值大于阈值,则将其设置为 0;否则设置为 maxval。
  3. cv2.THRESH_TRUNC: 如果像素值大于阈值,则将其设置为阈值;否则不改变。
  4. cv2.THRESH_TOZERO: 如果像素值大于阈值,则不改变;否则设置为 0。
  5. cv2.THRESH_TOZERO_INV: 如果像素值大于阈值,则设置为 0;否则不改变。
  6. cv2.THRESH_OTSU: 使用 Otsu 方法自动计算最佳阈值,并将其设置为阈值。
  7. cv2.THRESH_TRIANGLE: 使用 Triangle 方法自动计算最佳阈值,并将其设置为阈值。

返回值:
retval: 函数返回的阈值,这在应用 Otsu 或 Triangle 自动阈值方法时非常有用。
dst: 阈值处理后的输出图像。
注:
其中Otsu和Triangle算法不需要设置阈值,它们会根据图像的特征自动选择一个合适的阈值,Otsu算法通过遍历所有可能的灰度阈值,计算每个阈值下的前景和背景的类间方差,并选择使得类间方差最大的阈值作为最佳分割阈值,从而实现图像的二值化。
Triangle分割算法是一种基于图像直方图形状的阈值确定方法,通过寻找直方图与背景和对象之间的“三角形”区域的重心来确定最佳阈值,适用于直方图不呈现明显双峰分布的图像,对噪声和不均匀分布具有较好的鲁棒性。

  • 如果图像的直方图具有明显的双峰特性,Otsu方法通常能提供更好的分割效果。如果直方图没有明显的双峰或者图像的对比度较低,Triangle方法可能更合适。
  • Otsu方法对噪声较为敏感,因为噪声可能会导致直方图的双峰特性不明显。Triangle方法在这种情况下可能更为鲁棒。

使用:

import cv2

# 读取灰度图像
img = cv2.imread(r'D:\AI_tool\GFPGAN-master\1.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img_show = cv2.resize(img,(0,0),fx=0.3,fy=0.3)
img_re = cv2.resize(img_gray,(0,0),fx=0.3,fy=0.3)
# 应用阈值处理
ret, thresh = cv2.threshold(img_re, 127, 255, cv2.THRESH_BINARY)
ret2, thresh2 = cv2.threshold(img_re, 0, 255, cv2.THRESH_OTSU)
ret3, thresh3 = cv2.threshold(img_re, 0, 255, cv2.THRESH_TRIANGLE)
# 显示结果
cv2.imshow('Image', img_show)
cv2.imshow('Thresholded Image', thresh)
cv2.imshow('OTSU Image', thresh2)
cv2.imshow('TRIANGLE Image', thresh3)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果:
在这里插入图片描述

二、自适应阈值分割:

自适应阈值分割是一种图像处理技术,它根据图像的不同区域特性自动调整阈值,以实现更准确的图像分割。这种方法不同于全局阈值分割,后者在整个图像上使用一个固定的阈值。自适应阈值分割的目的是解决图像中光照不均或对比度变化的问题,其基本思想是局部区域内的像素值应该足够相似,以便可以被正确地分为前景或背景。
自适应阈值分割的步骤通常包括:

  1. 选择一个合适大小的窗口(如奇数大小的正方形或圆形窗口)。
  2. 在每个窗口内计算阈值,通常是基于窗口内像素的均值或中值,并减去一个常数(如C),即阈值 = 局部均值 - C。
  3. 将每个像素与其对应窗口的阈值进行比较,以确定该像素是前景还是背景。
  4. 移动窗口遍历整个图像,重复上述过程。

在opencv中存在其对应的api:cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)
参数说明:
src: 输入图像,通常是一个灰度图像。
maxValue: 阈值最大值,通常设置为255。
adaptiveMethod: 自适应方法,有以下两种选择:
cv2.ADAPTIVE_THRESH_MEAN_C: 阈值是邻域区域的平均值减去常数C。
cv2.ADAPTIVE_THRESH_GAUSSIAN_C: 阈值是邻域区域的高斯加权和减去常数C。
thresholdType: 阈值类型,有以下两种选择:
cv2.THRESH_BINARY: 如果像素值大于阈值,则设为最大值,否则设为0。
cv2.THRESH_BINARY_INV: 如果像素值大于阈值,则设为0,否则设为最大值。
blockSize: 邻域大小,必须是奇数,如3、5、7等。
C: 从平均值或加权平均值中减去的常数,通常是一个正数。
使用代码:

import cv2

# 读取灰度图像
img = cv2.imread(r'D:\AI_tool\GFPGAN-master\1.jpg')
img = cv2.resize(img,(0,0),fx=0.3,fy=0.3)


# 2. 灰度转换
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 3. 高斯模糊
blurred_image = cv2.GaussianBlur(gray_image, (5, 5), 0)

# 4. 自适应阈值分割
# 使用ADAPTIVE_THRESH_MEAN_C,blockSize为11,常数C为2
adaptive_thresh = cv2.adaptiveThreshold(blurred_image, 255,
                                        cv2.ADAPTIVE_THRESH_MEAN_C,
                                        cv2.THRESH_BINARY, 31,3)

# 5. 结果展示
cv2.imshow('Original Image', img)
cv2.imshow('Adaptive Thresholding', adaptive_thresh)

# 等待按键后关闭窗口
cv2.waitKey(0)
cv2.destroyAllWindows()


效果:
在这里插入图片描述

三、分水岭算法:

分水岭算法是一种基于拓扑理论的图像分割方法,它将图像看作一个地形图,其中亮度较高的区域被视为山峰,亮度较低的区域被视为山谷。算法的基本思想是模拟水在山谷中流动并最终汇集到一起的过程,直到水从山顶溢出,从而在各个山峰之间形成分水岭。
其实现流程为:

  1. 初始化:将图像看作一个三维地形图,其中灰度值表示高度。
  2. 淹没:从最低点开始,模拟水逐渐淹没整个地形。随着水位的上升,不同的盆地被水填满。
  3. 构建分水岭:当水位继续上升并接触到不同盆地的边缘时,在这些边缘处构建堤坝(分水岭)。堤坝防止不同盆地中的水相互混合。
  4. 标记:当所有的盆地都被堤坝分隔开后,每个盆地都会被赋予一个独特的标记。
  5. 合并:在实际应用中,会合并非常接近的盆地,以减少过分割的问题。

分水岭算法的关键步骤包括:

  1. 预处理:通常需要对图像进行预处理,如滤波、二值化、形态学操作等,以减少噪声和突出图像特征。
  2. 标记:在图像中标记出已知的前景和背景区域。这些标记将作为分水岭算法的种子点。
  3. 实施分水岭:使用标记过的图像作为输入,实施分水岭算法,从而得到分割后的图像。

分水岭算法的优点是能够提供连续、闭合、单调的分割边界,并且能够处理具有复杂形状的物体。然而,它也有缺点,比如对噪声敏感,容易产生过分割现象,即图像被分割成过多的区域。
在opencv中有实现分水岭算法的api:retval, markers = cv2.watershed(image, markers),
参数说明:

输入:
image:
类型:8位3通道图像。
说明:这是输入图像,通常是经过预处理后的图像,比如已经进行了灰度转换、滤波、边缘检测等操作。
markers:
类型:32位单通道图像,与image具有相同的大小。
说明:这是标记图像,其中每个区域的标记是通过不同的正整数来表示的。通常,前景对象用正值标记,背景用0标记,未知区域用-1标记。标记图像可以通过用户交互或者使用其他图像分割技术(如阈值分割、边缘检测、区域生长等)来生成。

返回值:
retval:
类型:与markers相同的图像。
说明:这是分割后的图像,其中边界区域被标记为-1。
markers:
类型:与输入的markers相同,但是经过函数处理后,标记图像中的每个区域都会被赋予一个唯一的标签。

使用 cv2.watershed 函数的步骤通常如下:

  1. 读取或创建原始图像。
  2. 对图像进行预处理,比如转换为灰度图像、应用滤波器、边缘检测等。
  3. 创建标记图像,初始化前景、背景和未知区域。
  4. 应用 cv2.watershed 函数。
  5. 根据返回的 markers 图像进行后处理,例如用颜色标记不同区域,或者提取分割后的区域。

代码案例:

import cv2
import numpy as np

# 读取图像
image = cv2.imread(r'D:\AI_tool\GFPGAN-master\1.jpg')
if image is None:
    print("Error: Image cannot be loaded. Please check the path.")
    exit()

image = cv2.resize(image,(0,0),fx=0.3,fy=0.3)

# 转换为灰度图像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 应用高斯模糊,减少图像噪声
blurred = cv2.GaussianBlur(gray, (5, 5), 0)

# 使用二值化方法初始化前景
_, thresh = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY)

# 定义一个kernel,用于形态学操作
kernel = np.ones((3,3), np.uint8)

# 形态学开操作,去除小的白色噪点
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)

# 确定背景区域
sure_bg = cv2.dilate(opening, kernel, iterations=2)

# 寻找前景区域,通过距离变换和阈值处理
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
_, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0)

# 找到未知区域
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)

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

# 为背景添加一个标记,标记为1而不是0,因为0是未知区域
markers = markers + 1

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

# 应用分水岭算法
markers = cv2.watershed(image, markers)

# 将边界标记为红色
image[markers == -1] = [0, 0, 255]

# 显示结果
cv2.imshow('Watershed Segmented Image', sure_bg)
cv2.waitKey(0)
cv2.destroyAllWindows()

效果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值