图像分割:从基础到实践
学习目标
通过本课程,学员们将了解图像分割的基本概念,掌握使用OpenCV实现图像分割的方法,包括基于阈值的分割和基于区域的分割技术。同时,学员将能够独立完成简单的图像分割任务,并理解其背后的原理。
相关知识点
- Python OpenCV图像分割
学习内容
1 Python OpenCV图像分割
1.1 图像分割基础
图像分割是计算机视觉中的一个基本问题,它涉及将图像划分为多个部分或区域,每个部分或区域具有相似的属性,如颜色、纹理或亮度。图像分割是许多高级图像处理任务的基础,如对象识别、图像分析和医学图像处理等。在图像分割中,目标是将图像中的像素分组为多个区域,每个区域对应于图像中的一个特定对象或部分。
图像分割的重要性在于它能够帮助计算机理解图像的内容,从而为后续的图像分析和处理提供基础。例如,在医学图像处理中,通过分割可以准确地识别出肿瘤的位置和大小;在自动驾驶技术中,图像分割可以帮助车辆识别道路、行人和其他障碍物。
在本课程中,学员将首先了解图像分割的基本概念,包括分割的目的、常见的分割方法以及分割结果的评估标准。接下来,探讨图像分割在实际应用中的重要性,以及如何选择合适的分割方法来解决特定的问题。
1.2 基于阈值的图像分割
基于阈值的图像分割是最简单也是最常用的图像分割方法之一。这种方法的基本思想是根据图像的灰度值或颜色值将图像中的像素分为不同的类别。阈值的选择是基于阈值分割的关键,不同的阈值选择方法适用于不同的图像和应用场景。
1.2.1 简单阈值分割
执行以下指令获取测试图片。
!wget https://model-community-picture.obs.cn-north-4.myhuaweicloud.com/ascend-zone/notebook_datasets/3c363b682faa11f09680fa163edcddae/example.jpg
简单阈值分割是最基本的阈值分割方法,它通过设定一个固定的阈值来将图像中的像素分为前景和背景。如果像素的灰度值大于阈值,则该像素被标记为前景;否则,被标记为背景。这种方法适用于背景和前景之间灰度值差异明显的图像。
import cv2
import numpy as np
from matplotlib import pyplot as plt# 读取图像
img = cv2.imread('example.jpg', 0)# 应用简单阈值分割
ret, thresh1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)# 显示结果
plt.subplot(1, 2, 1), plt.imshow(img, 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 2, 2), plt.imshow(thresh1, 'gray')
plt.title('Thresholded Image'), plt.xticks([]), plt.yticks([])
plt.show()
1.2.2 自适应阈值分割
自适应阈值分割是一种更高级的阈值分割方法,它根据图像的局部特性动态地选择阈值。这种方法适用于图像中背景和前景灰度值变化较大的情况。自适应阈值分割通过计算每个像素周围的局部平均灰度值来确定阈值,从而更好地适应图像的局部特性。
# 应用自适应阈值分割
thresh2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)# 显示结果
plt.subplot(1, 2, 1), plt.imshow(img, 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 2, 2), plt.imshow(thresh2, 'gray')
plt.title('Adaptive Thresholded Image'), plt.xticks([]), plt.yticks([])
plt.show()
1.3 基于区域的图像分割
基于区域的图像分割方法通过分析图像中的区域特性来实现分割。这些方法通常基于图像的连通性、颜色或纹理等特征,将图像中的像素分组为不同的区域。基于区域的分割方法适用于图像中对象边界不明显或背景复杂的情况。
1.3.1 连通区域标记
连通区域标记是一种基于区域的分割方法,它通过标记图像中的连通区域来实现分割。连通区域是指图像中具有相同或相似属性的像素集合。通过连通区域标记,可以将图像中的不同对象或部分区分开来。
# 读取图像
img = cv2.imread('example.jpg', 0)# 二值化图像
ret, binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)# 连通区域标记
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(binary, connectivity=8)# 显示结果
plt.imshow(labels, cmap='jet')
plt.title('Connected Components'), plt.xticks([]), plt.yticks([])
plt.show()
1.3.2 分水岭算法
分水岭算法是一种基于区域的分割方法,它通过模拟地形中的分水岭来实现图像分割。分水岭算法将图像中的每个像素视为地形中的一个点,通过模拟水从高处流向低处的过程,将图像中的不同区域分隔开来。分水岭算法适用于图像中对象边界不明显或背景复杂的情况。
# 读取图像
img = cv2.imread('example.jpg')# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 二值化图像
ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)# 距离变换
dist_transform = cv2.distanceTransform(binary, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)# 找到未知区域
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(binary, sure_fg)# 标记连通区域
ret, markers = cv2.connectedComponents(sure_fg)# 将所有标记加1,确保背景为1
markers = markers + 1# 将未知区域标记为0
markers[unknown == 255] = 0# 应用分水岭算法
markers = cv2.watershed(img, markers)
img[markers == -1] = [255, 0, 0]# 显示结果
plt.subplot(1, 2, 1), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('Watershed Segmentation'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 2, 2), plt.imshow(markers, cmap='jet')
plt.title('Markers'), plt.xticks([]), plt.yticks([])
plt.show()