首页 > 解决方案 > K-means 算法 C#

问题描述

我尝试在 C# 中实现 K-means 算法,但不知何故,它的输出是黑色(小)图像。我写了以下代码:

public static Color[,] Kmeans(int number_clusters, Vector[,] input, int iterations)
        {
            int length = input.GetLength(0);
            int height = input.GetLength(1);

            Random randomizer = new Random();

            //Inits centroides
            List<Vector> centroides = new List<Vector>(number_clusters);
            List<List<Vector>> clusters = new List<List<Vector>>(number_clusters); 

            for(int i = 0; i < number_clusters; i++)
            {
                Vector centroid = input[randomizer.Next(0, length), randomizer.Next(0, height)];

                List<Vector> cluster = new List<Vector>();

                cluster.Add(centroid); 
                clusters.Add(cluster);

                centroides.Add(centroid); 
            }

            int count = 0;

            while (count < iterations) {
                for (int x = 0; x < input.GetLength(0); x++)
                {
                    for (int y = 0; y < input.GetLength(1); y++)
                    {
                        Vector currentVector = input[x, y];
                        double min_distance = Double.PositiveInfinity;
                        Vector closest_centroid = centroides[0];

                        //Finds closest centroid
                        foreach (Vector centroid in centroides)
                        {
                            double distance = currentVector.Distance(centroid);
                            if (Math.Pow(distance, 2) < min_distance)
                            {
                                min_distance = Math.Pow(distance, 2);
                                closest_centroid = centroid;
                            }
                        }

                        //Find cluster with that centroid in it
                        List<Vector> to_assign = clusters[0];
                        foreach (List<Vector> cluster_list in clusters)
                        {
                            if (cluster_list[0].r == closest_centroid.r && cluster_list[0].g == closest_centroid.g && cluster_list[0].b == closest_centroid.b)
                            {
                                to_assign = cluster_list;
                                break;
                            }
                        }

                        to_assign.Add(currentVector);
                        int current_length = to_assign.Count();
                        Vector current_centroid = to_assign[0];

                        Vector new_centroid = new Vector(0, 0, 0);

                        foreach (Vector vector in to_assign)
                        {
                            new_centroid.Sum(vector);
                        }

                        new_centroid = new Vector(new_centroid.r / current_length, new_centroid.g / current_length, new_centroid.b / current_length);
                        to_assign.RemoveAt(0);
                        to_assign.Insert(0, new_centroid);

                        for (int i = 0; i < centroides.Count(); i++)
                        {
                            if (centroides[i].r == current_centroid.r && centroides[i].g == current_centroid.g && current_centroid.b == centroides[i].b)
                            {
                                centroides[i] = new_centroid;
                                break;
                            }
                        }
                    }
                }
                count++; 
            }

            foreach(List<Vector> cluster_list in clusters)
            {
                Vector current_centroid = cluster_list[0]; 
                for(int i = 1; i < cluster_list.Count(); i++)
                {
                    cluster_list[i].r = current_centroid.r;
                    cluster_list[i].g = current_centroid.g;
                    cluster_list[i].b = current_centroid.b;
                }
            }

            Color[,] output = new Color[length, height]; 
            foreach (List<Vector> cluster_list in clusters)
            {
                for (int i = 0; i < cluster_list.Count(); i++)
                {
                    Vector current_vector = cluster_list[i];
                    output[current_vector.x, current_vector.y] = Color.FromArgb((int) current_vector.r, (int) current_vector.g, (int) current_vector.b); 
                }
            }

            return output; 
        }

Vector 是以下类:

public class Vector
    {
        public double r, g, b;
        public int x, y;
        public Vector(double r, double g, double b)
        {
            this.r = r;
            this.g = g;
            this.b = b;
        }

        public void SetCoordinates(int x, int y)
        {
            this.x = x;
            this.y = y; 
        }

        public double Distance(Vector v2)
        {
            double r_power = Math.Pow((r - v2.r), 2);
            double g_power = Math.Pow((g - v2.g), 2);
            double b_power = Math.Pow((b - v2.b), 2);

            double distance = Math.Sqrt((r_power + g_power + b_power));

            return distance; 
        }

        public Vector Product(int scalar)
        {
            return new Vector(r * scalar, g * scalar, b * scalar); 
        }

        public double Length()
        {
            return Math.Sqrt((Math.Pow(r, 2) + Math.Pow(g, 2) + Math.Pow(b, 2))); 
        }

        public Vector Sum(Vector v2)
        {
            double new_r = r + v2.r; 
            double new_g = g + v2.g;
            double new_b = b + v2.b;

            return new Vector(new_r, new_g, new_b); 
        }
    }

我尝试通过以下算法描述来实现代码:

将对象分配给集群:对于测试集中的每个对象 v,执行以下步骤: 1 计算 v 与每个集群的每个质心 k 之间的平方距离(d 2 ( v , k ))。2 将对象 v 分配给具有最近质心的集群。更新质心:对于每个集群 k 计算它们的平均向量。平均向量的计算类似于一个数字的平均值:我们对集群中的所有向量求和(向量和),然后除以集群中向量的数量(标量积与倒数)。重复以上两个步骤

谁能帮我解决这个算法

标签: c#algorithmimage-processing

解决方案


我找到了解决方案:

    foreach (Vector vector in to_assign)
    {
        new_centroid.Sum(vector);
    }

应改为:

foreach (Vector vector in to_assign)
        {
            new_centroid = new_centroid.Sum(vector);
        }

这是因为 Sum 方法返回了一个新的向量,该向量现在没有被存储


推荐阅读