首页 > 后端开发 > Python教程 > [Python-CV图像分割:Canny边缘、分水岭和K-Means方法

[Python-CV图像分割:Canny边缘、分水岭和K-Means方法

Patricia Arquette
发布: 2024-12-11 05:33:09
原创
891 人浏览过

分割是图像分析中的一项基本技术,它允许我们根据对象、形状或颜色将图像划分为有意义的部分。它在物体检测、计算机视觉甚至艺术图像处理等应用中发挥着关键作用。但如何才能有效实现细分呢?幸运的是,OpenCV (cv2) 提供了几种用户友好且强大的分割方法。

在本教程中,我们将探讨三种流行的分割技术:

  • Canny 边缘检测 – 非常适合勾画物体轮廓。
  • 分水岭算法 – 非常适合分离重叠区域。
  • K-Means 颜色分割 – 非常适合对图像中的相似颜色进行聚类。

为了使本教程引人入胜且实用,我们将使用来自日本大阪的卫星和航空图像,重点关注古代古坟。您可以从教程的 GitHub 页面下载这些图像和相应的示例笔记本。

Canny 边缘检测到轮廓分割

Canny 边缘检测是一种简单而强大的方法来识别图像中的边缘。它的工作原理是检测强度快速变化的区域,这些区域通常是物体的边界。该技术通过应用强度阈值生成“薄边缘”轮廓。让我们深入了解它使用 OpenCV 的实现。

示例:检测卫星图像中的边缘
在这里,我们使用大阪的卫星图像,特别是古坟,作为测试用例。

import cv2 
import numpy as np
import matplotlib.pyplot as plt
files = sorted(glob("SAT*.png")) #Get png files 
print(len(files))
img=cv2.imread(files[0])
use_image= img[0:600,700:1300]
gray = cv2.cvtColor(use_image, cv2.COLOR_BGR2GRAY)

#Stadard values 
min_val = 100
max_val = 200
# Apply Canny Edge Detection
edges = cv2.Canny(gray, min_val, max_val)
#edges = cv2.Canny(gray, min_val, max_val,apertureSize=5,L2gradient = True )
False
# Show the result
plt.figure(figsize=(15, 5))
plt.subplot(131), plt.imshow(cv2.cvtColor(use_image, cv2.COLOR_BGR2RGB))
plt.title('Original Image'), plt.axis('off')
plt.subplot(132), plt.imshow(gray, cmap='gray')
plt.title('Grayscale Image'), plt.axis('off')
plt.subplot(133), plt.imshow(edges, cmap='gray')
plt.title('Canny Edges'), plt.axis('off')
plt.show()

登录后复制
登录后复制
登录后复制

[Python-CVImage Segmentation : Canny Edges, Watershed, and K-Means Methods

输出边缘清晰地勾勒出古坟和其他感兴趣区域的部分轮廓。然而,由于阈值过大,一些区域被遗漏了。结果在很大程度上取决于 min_val 和 max_val 的选择以及图像质量。

为了增强边缘检测,我们可以对图像进行预处理以分散像素强度并减少噪声。这可以使用直方图均衡 (cv2.equalizeHist()) 和高斯模糊 (cv2.GaussianBlur()) 来实现。

use_image= img[0:600,700:1300]
gray = cv2.cvtColor(use_image, cv2.COLOR_BGR2GRAY)
gray_og = gray.copy()
gray = cv2.equalizeHist(gray)
gray = cv2.GaussianBlur(gray, (9, 9),1)

plt.figure(figsize=(15, 5))
plt.subplot(121), plt.imshow(gray, cmap='gray')
plt.title('Grayscale Image')
plt.subplot(122)
_= plt.hist(gray.ravel(), 256, [0,256],label="Equalized") 
_ = plt.hist(gray_og.ravel(), 256, [0,256],label="Original",histtype='step')
plt.legend()
plt.title('Grayscale Histogram')

登录后复制
登录后复制
登录后复制

[Python-CVImage Segmentation : Canny Edges, Watershed, and K-Means Methods

这种预处理可以均匀强度分布并平滑图像,这有助于 Canny 边缘检测算法捕获更有意义的边缘。

边缘很有用,但它们仅表示边界。为了分割封闭区域,我们将边缘转换为轮廓并可视化它们。

# Edges to contours 
contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Calculate contour areas
areas = [cv2.contourArea(contour) for contour in contours]

# Normalize areas for the colormap
normalized_areas = np.array(areas)
if normalized_areas.max() > 0:
    normalized_areas = normalized_areas / normalized_areas.max()

# Create a colormap
cmap = plt.cm.jet

# Plot the contours with the color map
plt.figure(figsize=(10, 10))
plt.subplot(1,2,1)
plt.imshow(gray, cmap='gray', alpha=0.5)  # Display the grayscale image in the background
mask = np.zeros_like(use_image)
for contour, norm_area in zip(contours, normalized_areas):
    color = cmap(norm_area)  # Map the normalized area to a color
    color = [int(c*255) for c in color[:3]]
    cv2.drawContours(mask, [contour], -1, color,-1 )  # Draw contours on the image

plt.subplot(1,2,2)
登录后复制
登录后复制
登录后复制

[Python-CVImage Segmentation : Canny Edges, Watershed, and K-Means Methods

上述方法用代表其相对区域的颜色突出显示检测到的轮廓。这种可视化有助于验证轮廓是否形成封闭体或仅形成线条。然而,在此示例中,许多轮廓仍然是未闭合的多边形。进一步的预处理或参数调整可以解决这些限制。

通过结合预处理和轮廓分析,Canny 边缘检测成为识别图像中对象边界的强大工具。然而,当对象定义明确且噪声最小时,它的效果最佳。接下来,我们将探索 K 均值聚类以按颜色分割图像,从而为相同数据提供不同的视角。

K均值聚类

K-Means 聚类是数据科学中一种流行的方法,用于将相似的项目分组为聚类,并且它对于基于颜色相似性的图像分割特别有效。 OpenCV 的 cv2.kmeans 函数简化了此过程,使其可以执行对象分割、背景去除或视觉分析等任务。

在本节中,我们将使用 K 均值聚类将古坟墓图像分割为相似颜色的区域。

首先,我们对图像的 RGB 值应用 K 均值聚类,将每个像素视为一个数据点。

import cv2 
import numpy as np
import matplotlib.pyplot as plt
files = sorted(glob("SAT*.png")) #Get png files 
print(len(files))
img=cv2.imread(files[0])
use_image= img[0:600,700:1300]
gray = cv2.cvtColor(use_image, cv2.COLOR_BGR2GRAY)

#Stadard values 
min_val = 100
max_val = 200
# Apply Canny Edge Detection
edges = cv2.Canny(gray, min_val, max_val)
#edges = cv2.Canny(gray, min_val, max_val,apertureSize=5,L2gradient = True )
False
# Show the result
plt.figure(figsize=(15, 5))
plt.subplot(131), plt.imshow(cv2.cvtColor(use_image, cv2.COLOR_BGR2RGB))
plt.title('Original Image'), plt.axis('off')
plt.subplot(132), plt.imshow(gray, cmap='gray')
plt.title('Grayscale Image'), plt.axis('off')
plt.subplot(133), plt.imshow(edges, cmap='gray')
plt.title('Canny Edges'), plt.axis('off')
plt.show()

登录后复制
登录后复制
登录后复制

[Python-CVImage Segmentation : Canny Edges, Watershed, and K-Means Methods

在分割图像中,古坟和周围区域聚集成不同的颜色。然而,噪声和颜色的微小变化会导致簇分散,这会给解释带来挑战。

为了减少噪音并创建更平滑的聚类,我们可以在运行 K-Means 之前应用中值模糊。

use_image= img[0:600,700:1300]
gray = cv2.cvtColor(use_image, cv2.COLOR_BGR2GRAY)
gray_og = gray.copy()
gray = cv2.equalizeHist(gray)
gray = cv2.GaussianBlur(gray, (9, 9),1)

plt.figure(figsize=(15, 5))
plt.subplot(121), plt.imshow(gray, cmap='gray')
plt.title('Grayscale Image')
plt.subplot(122)
_= plt.hist(gray.ravel(), 256, [0,256],label="Equalized") 
_ = plt.hist(gray_og.ravel(), 256, [0,256],label="Original",histtype='step')
plt.legend()
plt.title('Grayscale Histogram')

登录后复制
登录后复制
登录后复制

[Python-CVImage Segmentation : Canny Edges, Watershed, and K-Means Methods

模糊的图像会产生更平滑的簇,减少噪音并使分割区域在视觉上更具凝聚力。

为了更好地理解分割结果,我们可以使用 matplotlib plt.fill_ Between;
创建独特簇颜色的颜色图

# Edges to contours 
contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Calculate contour areas
areas = [cv2.contourArea(contour) for contour in contours]

# Normalize areas for the colormap
normalized_areas = np.array(areas)
if normalized_areas.max() > 0:
    normalized_areas = normalized_areas / normalized_areas.max()

# Create a colormap
cmap = plt.cm.jet

# Plot the contours with the color map
plt.figure(figsize=(10, 10))
plt.subplot(1,2,1)
plt.imshow(gray, cmap='gray', alpha=0.5)  # Display the grayscale image in the background
mask = np.zeros_like(use_image)
for contour, norm_area in zip(contours, normalized_areas):
    color = cmap(norm_area)  # Map the normalized area to a color
    color = [int(c*255) for c in color[:3]]
    cv2.drawContours(mask, [contour], -1, color,-1 )  # Draw contours on the image

plt.subplot(1,2,2)
登录后复制
登录后复制
登录后复制

[Python-CVImage Segmentation : Canny Edges, Watershed, and K-Means Methods

这种可视化可以深入了解图像中的主色及其相应的 RGB 值,这对于进一步分析非常有用。因为我们现在可以屏蔽并选择我的颜色代码区域。

簇的数量 (K) 显着影响结果。增加 K 会创建更详细的细分,而较低的值会产生更广泛的分组。为了进行实验,我们可以迭代多个 K 值。

import cv2 
import numpy as np
import matplotlib.pyplot as plt
files = sorted(glob("SAT*.png")) #Get png files 
print(len(files))
img=cv2.imread(files[0])
use_image= img[0:600,700:1300]
gray = cv2.cvtColor(use_image, cv2.COLOR_BGR2GRAY)

#Stadard values 
min_val = 100
max_val = 200
# Apply Canny Edge Detection
edges = cv2.Canny(gray, min_val, max_val)
#edges = cv2.Canny(gray, min_val, max_val,apertureSize=5,L2gradient = True )
False
# Show the result
plt.figure(figsize=(15, 5))
plt.subplot(131), plt.imshow(cv2.cvtColor(use_image, cv2.COLOR_BGR2RGB))
plt.title('Original Image'), plt.axis('off')
plt.subplot(132), plt.imshow(gray, cmap='gray')
plt.title('Grayscale Image'), plt.axis('off')
plt.subplot(133), plt.imshow(edges, cmap='gray')
plt.title('Canny Edges'), plt.axis('off')
plt.show()

登录后复制
登录后复制
登录后复制

[Python-CVImage Segmentation : Canny Edges, Watershed, and K-Means Methods

不同 K 值的聚类结果揭示了细节和简单性之间的权衡:

・较低的 K 值(例如 2-3):聚类范围广泛,区分清晰,适合高级分割。
・更高的 K 值(例如 12-15):更详细的分割,但代价是增加复杂性和潜在的过度分割。

K-Means 聚类是一种基于颜色相似性分割图像的强大技术。通过正确的预处理步骤,它可以生成清晰且有意义的区域。然而,其性能取决于 K 的选择、输入图像的质量以及所应用的预处理。接下来,我们将探索分水岭算法,该算法利用地形特征来实现对象和区域的精确分割。

分水岭分割

分水岭算法的灵感来自地形图,其中分水岭划分流域。此方法将灰度强度值视为高程,有效地创建“峰”和“谷”。通过识别感兴趣区域,该算法可以分割具有精确边界的对象。它对于分离重叠对象特别有用,使其成为细胞分割、对象检测和区分密集特征等复杂场景的绝佳选择。

第一步是预处理图像以增强特征,然后应用分水岭算法。

use_image= img[0:600,700:1300]
gray = cv2.cvtColor(use_image, cv2.COLOR_BGR2GRAY)
gray_og = gray.copy()
gray = cv2.equalizeHist(gray)
gray = cv2.GaussianBlur(gray, (9, 9),1)

plt.figure(figsize=(15, 5))
plt.subplot(121), plt.imshow(gray, cmap='gray')
plt.title('Grayscale Image')
plt.subplot(122)
_= plt.hist(gray.ravel(), 256, [0,256],label="Equalized") 
_ = plt.hist(gray_og.ravel(), 256, [0,256],label="Original",histtype='step')
plt.legend()
plt.title('Grayscale Histogram')

登录后复制
登录后复制
登录后复制

分段区域和边界可以与中间处理步骤一起可视化。

[Python-CVImage Segmentation : Canny Edges, Watershed, and K-Means Methods

# Edges to contours 
contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# Calculate contour areas
areas = [cv2.contourArea(contour) for contour in contours]

# Normalize areas for the colormap
normalized_areas = np.array(areas)
if normalized_areas.max() > 0:
    normalized_areas = normalized_areas / normalized_areas.max()

# Create a colormap
cmap = plt.cm.jet

# Plot the contours with the color map
plt.figure(figsize=(10, 10))
plt.subplot(1,2,1)
plt.imshow(gray, cmap='gray', alpha=0.5)  # Display the grayscale image in the background
mask = np.zeros_like(use_image)
for contour, norm_area in zip(contours, normalized_areas):
    color = cmap(norm_area)  # Map the normalized area to a color
    color = [int(c*255) for c in color[:3]]
    cv2.drawContours(mask, [contour], -1, color,-1 )  # Draw contours on the image

plt.subplot(1,2,2)
登录后复制
登录后复制
登录后复制

该算法成功识别不同的区域并在对象周围绘制清晰的边界。在本例中,古坟被精确分割。然而,该算法的性能在很大程度上取决于阈值处理、噪声去除和形态学操作等预处理步骤。

添加高级预处理,例如直方图均衡或自适应模糊,可以进一步增强结果。例如:

# Kmean color segmentation
use_image= img[0:600,700:1300]
#use_image = cv2.medianBlur(use_image, 15)


 # Reshape image for k-means
pixel_values = use_image.reshape((-1, 3)) if len(use_image.shape) == 3 else use_image.reshape((-1, 1))
pixel_values = np.float32(pixel_values)

criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = 3
attempts=10
ret,label,center=cv2.kmeans(pixel_values,K,None,criteria,attempts,cv2.KMEANS_PP_CENTERS)

centers = np.uint8(center)
segmented_data = centers[label.flatten()]
segmented_image = segmented_data.reshape(use_image.shape)

plt.figure(figsize=(10, 6))
plt.subplot(1,2,1),plt.imshow(use_image[:,:,::-1])
plt.title("RGB View")
plt.subplot(1,2,2),plt.imshow(segmented_image[:,:,[2,1,0]])
plt.title(f"Kmean Segmented Image K={K}")

登录后复制

[Python-CVImage Segmentation : Canny Edges, Watershed, and K-Means Methods
通过这些调整,可以准确分割更多区域,并最大限度地减少噪声伪影。

分水岭算法在需要精确边界划分和重叠对象分离的场景中表现出色。通过利用预处理技术,它甚至可以有效地处理像古坟古坟区域这样的复杂图像。然而,它的成功取决于仔细的参数调整和预处理。

结论

分割是图像分析中的重要工具,提供了隔离和理解图像中不同元素的途径。本教程演示了三种强大的分割技术:Canny 边缘检测、K 均值聚类和分水岭算法,每种技术都是针对特定应用程序量身定制的。从勾勒出大阪古代古坟的轮廓,到聚类城市景观和划分不同区域,这些方法凸显了 OpenCV 在应对现实世界挑战方面的多功能性。

现在去将其中的一些方法应用到您选择的应用程序中,并发表评论并分享结果。另外,如果您知道任何其他简单的分割方法,也请分享

以上是[Python-CV图像分割:Canny边缘、分水岭和K-Means方法的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板