Advertisement

OpenCV与AI深度学习 | 实战 | 基于OpenCV和K-Means聚类实现颜色分割(步骤 + 代码)

阅读量:

本文来源公众号**“OpenCV与AI深度学习”** ,仅用于学术分享,侵权删,干货满满。

实战 | 基于OpenCV和K-Means聚类实现颜色分割(步骤 + 代码)

实践环节 | 以OpenCV框架为基础并结合K-means算法基础实现图像色彩分割(具体操作与代码实现)

介 绍

一种基于颜色的分割方法被广泛应用于计算机视觉领域。聚类算法能够将具有相似色调的像素自动归类到同一组中。该方法无需预先设定特定的颜色阈值即可实现目标识别任务。当图像呈现较大色彩跨度或在缺乏明确阈值设定的情况下, 该方法表现出较高的实用性。

在本文中, 我们将深入研究如何利用K-Means聚类算法实现图像的颜色分割, 并统计不同颜色区域的数量

复制代码
 from matplotlib import pyplot as plt

    
 import cv2
    
 import pandas as pd
    
 import numpy as np
    
 from sklearn.cluster import KMeans
    
 %matplotlib inlin
    
    
    
    
    python
复制代码
 image = cv2.imread(r'bubbles.jpeg', cv2.IMREAD_UNCHANGED)

    
 plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
    
 plt.axis('off')
    
    
    
    
    python

使用阈值提取二进制掩码

第一步是从背景中提取所有气泡。为此,我们首先使用cv2.cvtColor()函数将原始图像转换为灰度图象;接着利用cv2.threshold()将其转换为二进制图象,在该图象中每个像素要么取值0(黑色)要么取值255(白色)。具体阈值设定为60,则所有小于60的像素会被设为0(黑色),其他则设为255(白色)。由于在二进制图象中存在少量重叠现象导致气泡分离困难的问题,因此我们采用了形态学中的腐蚀运算(利用cv2.erode()函数),该运算能够有效地减少图像中对象尺寸的同时还能够去除微小的白色噪声以及分离连接的对象。

复制代码
 image = cv2.imread(r'bubbles.jpeg', cv2.IMREAD_UNCHANGED)

    
 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
 _ , mask = cv2.threshold(gray, 60, 255, cv2.THRESH_BINARY)
    
 mask = cv2.erode(mask, np.ones((7, 7), np.uint8))
    
    
    
    
    python

使用轮廓提取对象边界

下一步是在二值图像中进行对象定位。该函数cv2.findContours()在处理二值图像时用于识别物体的边界。轮廓被定义为构成图像中对象边界的连续曲线。通过使用cv2.RETR_EXTERNAL标志参数可以提取最外围的轮廓。该算法最终输出一个包含多个轮廓的对象边界列表。

复制代码
    contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    python

过滤轮廓并提取平均颜色

为了消除不对应气泡边缘特征的影响,在迭代生成的所有边缘特征中筛选出面积较大的边缘特征(大于3000像素)。这一操作能够有效识别气泡的主要边界,并排除所有小尺寸干扰物如字母或其他背景残留片段。

复制代码
 filtered_contours = []

    
 df_mean_color = pd.DataFrame()
    
 for idx, contour in enumerate(contours):
    
     area = int(cv2.contourArea(contour))
    
  
    
     # if area is higher than 3000:
    
     if area > 3000:
    
     filtered_contours.append(contour)
    
     # get mean color of contour:
    
     masked = np.zeros_like(image[:, :, 0])  # This mask is used to get the mean color of the specific bead (contour), for kmeans
    
     cv2.drawContours(masked, [contour], 0, 255, -1)
    
  
    
     B_mean, G_mean, R_mean, _ = cv2.mean(image, mask=masked)
    
     df = pd.DataFrame({'B_mean': B_mean, 'G_mean': G_mean, 'R_mean': R_mean}, index=[idx])
    
     df_mean_color = pd.concat([df_mean_color, df])
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-16/sOlIGx1uLtNqacfEH5J6Wrz2onpg.png)

为了获取每个气泡的平均色调,我们采用了以下方法:首先,在纯黑色背景图像中绘制白色轮廓的方式为每个气泡创建了一个遮罩。接着,在应用 OpenCV 的 cv2.mean() 函数时结合遮罩与原图计算出各个通道(BGR)的颜色均值数据,并将这些均值数据存入到 pandas 数据框架中进行后续处理。

使用 K-means 算法对相似颜色进行聚类

最后, 我们将采用 K 均值聚类算法来进行气泡的颜色相似性归集. 选择轮廓区域的平均色调作为输入数据, 这些数据会被传递给库中的 KMeans 算法 (sklearn). n_clusters 超参数用于指定需要创建的聚类数量. 在本例中, 由于气泡具有六种不同的颜色, 我们将其设置为 6

K均值算法是一种广泛应用于数据分析与挖掘的强大工具,在机器学习领域具有重要地位。其基本原理是接受一组待分类样本并将其划分为预先指定数量的类别群,在这一过程中每一类别群都有一个代表性的典型特征向量即中心点(centroid)。初始时将中心点随机放置于数据空间中的某个位置然后通过迭代过程使每个样本被分配到与之最近的中心点对应的类别群中当所有样本完成分类后新的中心点坐标则根据各类别成员的位置计算得出这个过程会不断重复直到各类别中心收敛稳定不再发生变动从而实现了最优分类效果这种方法特别适用于需要快速处理大量离散型或连续型属性的数据集并且能够有效发现潜在的空间分布模式通过K均值算法我们可以轻松地对具有相似特性的气泡进行特征提取进而实现高效的空间聚类

当KMeans类初始化完成时, 程序将调用fit_predict方法来执行聚类过程. 此fit_predict方法将每个样本分配至相应的类别中, 然后将这些标签赋值为新列中的数据. 从而让我们能够明确区分各个数据群组所属的不同类别.

复制代码
 km = KMeans( n_clusters=6)

    
 df_mean_color['label'] = km.fit_predict(df_mean_color)
    
    
    
    
    python

调用draw_segmented_objects函数后定义函数来创建一个新的蒙版图像,并将其应用于提取特定区域的颜色特征。该过程分为两步:首先创建一个二进制蒙版的方法如下:使用白色笔触在黑色背景上勾勒出所有具有相同标签号气泡的轮廓;接着使用cv2.bitwise_and()函数对原始图像和掩膜图进行操作以实现目标区域的选择性显示效果。最后,在目标图上使用cv2.putText()绘制每种颜色对应的数量信息以供后续分析参考。

复制代码
 def draw_segmented_objects(image, contours, label_cnt_idx, bubbles_count):

    
     mask = np.zeros_like(image[:, :, 0])
    
     cv2.drawContours(mask, [contours[i] for i in label_cnt_idx], -1, (255), -1)
    
     masked_image = cv2.bitwise_and(image, image, mask=mask)
    
     masked_image = cv2.putText(masked_image, f'{bubbles_count} bubbles', (200, 1200), cv2.FONT_HERSHEY_SIMPLEX,
    
                     fontScale = 3, color = (255, 255, 255), thickness = 10, lineType = cv2.LINE_AA)
    
     return masked_image
    
    
    
    
    python

对于每个带有相同标签的气泡集合而言,在执行draw_segmented_objects函数时会输出相应的颜色蒙版图像。统计按颜色分类后的DataFrame中的记录条数能够帮助确定每一颜色对应的珠子数量。

复制代码
 img = image.copy()

    
 for label, df_grouped in df_mean_color.groupby('label'):
    
     bubbles_amount = len(df_grouped)
    
     masked_image = draw_segmented_objects(image, contours, df_grouped.index, bubbles_amount)
    
     img = cv2.hconcat([img, masked_image])
    
  
    
 plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB) )
    
    
    
    
    python

结果图:

总 结

使用 K-means 聚类进行色彩分割是一种强有力的工具,并且能够依据对图像中物体的颜色特征识别以及数量的量化来实现这一过程。在本教程中,我们将展示如何应用 K-means 算法结合 OpenCV 和 scikit-learn 来完成色彩分割,并统计每种颜色物体的数量。这一技术适用于多种基于对图像内容进行色彩分析与分类的应用场景

THE END !

文章结束之际,请允许我用文字与您分享一些有趣的知识和见解。您的点赞、收藏和评论是我继续更新的动力!如果您觉得有用,请您在评论区留言并与我们共同进步!

全部评论 (0)

还没有任何评论哟~