65.9K
CodeProject 正在变化。 阅读更多。
Home

C# 的计算机视觉应用 - 模糊 C 均值聚类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (23投票s)

2010 年 7 月 5 日

GPL3

4分钟阅读

viewsIcon

131919

downloadIcon

9348

此代码执行彩色图像的模糊 C-means 聚类和分割,并可用于特征提取。

printscreen.png

引言

图像分割,即根据一组特征将图像划分为同质区域,是图像分析和计算机视觉的关键要素。聚类是可用于此目的的方法之一。聚类是一个过程,可用于根据像素的颜色或灰度强度相似性来对像素进行分类。

K-means 算法已被用于快速而明确的“硬”分割。模糊集理论通过允许部分隶属度的概念,改进了这一过程,其中图像像素可以属于多个簇。这种“软”聚类允许更精确地计算簇成员资格,并已成功用于图像聚类以及医学、地质和卫星图像的无监督分割。

算法

模糊 C-means (FCM) 算法遵循与 K-means 算法相同的原理,即它将每个像素的 RGB 值与簇中心的进行比较。主要区别在于,它不是对像素应该属于哪个簇做出硬性决定,而是为每个簇分配一个介于 0 和 1 之间的值,描述“该像素在多大程度上属于该簇”。模糊规则指出,像素对所有簇的隶属值之和必须为 1。隶属值越高,该像素属于该簇的可能性越大。FCM 聚类是通过最小化方程 (1) 中所示的目标函数获得的。

1.png (1)

其中

  • J 是目标函数
  • n 是图像 E 中的像素数
  • c 是簇的数量
  • µ 是来自表格的模糊隶属值
  • m 是模糊因子(大于 1 的值)
  • pi 是 E 中的第 i 个像素
  • vk 是第 k 个簇的质心
  • |pi – vk| 是 pi 和 vk 之间的欧几里得距离,由方程 (2) 定义

2.png (2)

第 k 个簇的质心计算使用方程 (3) 完成

3.png (3)

模糊隶属表使用原始方程 (4) 计算

4.png (4)

该算法已扩展用于 RGB 颜色空间中彩色图像的聚类。因此,方程 (2) 中计算 pi 和 vk 值之间欧几里得距离的计算被修改为包含 RGB 颜色,并显示在方程 (5) 中。

1.png (5)

Picture1.png

伪代码

如前所述,这是一个迭代过程。伪代码如下:

  • 步骤 1:设置簇的数量、模糊参数(大于 1 的常数)和停止条件
  • 步骤 2:初始化模糊分区矩阵
  • 步骤 3:设置循环计数器 k = 0
  • 步骤 4:计算簇质心,计算目标值 J
  • 步骤 5:对于每个像素,对于每个簇,计算矩阵中的隶属值
  • 步骤 6:如果连续迭代之间 J 的值小于停止条件,则停止;否则,设置 k=k+1 并转到步骤 4
  • 步骤 7:去模糊化和分割

Using the Code

GUI 非常直观,但计算量可能非常大。因此,处理是在工作线程中完成的,这使得与 GUI 的交互复杂化。

首先,使用“文件”菜单加载图像。请注意,大图像将花费很长时间!

可以从 GUI 更改的选项是簇的数量、最大迭代次数(这样程序就不会一直运行下去)和精度。如果达到精度,算法将在最大迭代次数之前停止。

options.png

单击“Fuzzy C-means Clustering”按钮将启动计算。程序将首先为图像中的每个像素创建一个ClusterPoint对象。

List<ClusterPoint> points = new List<ClusterPoint>();
for (int row = 0; row < originalImage.Width; ++row)
{
    for (int col = 0; col < originalImage.Height; ++col)
    {
        Color c2 = originalImage.GetPixel(row, col);
        points.Add(new ClusterPoint(row, col, c2));
    }
}

然后,创建所请求数量的ClusterCentroid簇对象。

List<ClusterCentroid> centroids = new List<ClusterCentroid>();

//Create random points to use a the cluster centroids
Random random = new Random();
for (int i = 0; i < numClusters; i++)
{
    int randomNumber1 = random.Next(sourceImage.Width);
    int randomNumber2 = random.Next(sourceImage.Height);
    centroids.Add(new ClusterCentroid(randomNumber1, randomNumber2, 
                  filteredImage.GetPixel(randomNumber1, randomNumber2))); 
}

簇中心(或质心)在第一次传递时是随机选择的,并且将由算法进行调整。

最后,创建FCM对象并开始迭代。

FCM alg = new FCM(points, centroids, 2, filteredImage, (int)numericUpDown2.Value);
k++;
alg.J = alg.CalculateObjectiveFunction();
alg.CalculateClusterCentroids();
alg.Step();
double Jnew = alg.CalculateObjectiveFunction();
Console.WriteLine("Run method i={0} accuracy = {1} delta={2}", 
                  k, alg.J, Math.Abs(alg.J - Jnew));
backgroundWorker.ReportProgress((100 * k) / maxIterations, "Iteration " + k);
if (Math.Abs(alg.J - Jnew) < accuracy) break;

进度显示在状态栏上。

progress.png

迭代完成后,算法将执行去模糊化过程,将像素分配给它具有最高隶属值的簇。对于每个簇,程序将保存一个包含原始图像中属于该簇的像素的分割图像。

例如,对以下测试图像进行 2 个簇的聚类

printscreen.png

将产生以下聚类图像

printscreen.png

通过使用簇信息和原始图像中的像素,可以提取以下区域

printscreen.png printscreen.png

由于此算法计算量非常大,它有“锁定”GUI 并且不刷新状态和工作图像的倾向。因此,我必须使用工作线程。

关注点

这是我的第一篇帖子,也是我的第一个 C# 程序,所以 I'm sure 还有很多改进的空间。但总的来说,I hope you will find this project fun and interesting!

参考文献

© . All rights reserved.