public static int EucliceanDistance(NewColor c1, NewColor c2) { int redDifference = c1.R - c2.R; int greenDifference = c1.G - c2.G; int blueDifference = c1.B - c2.B; return(redDifference * redDifference + greenDifference * greenDifference + blueDifference * blueDifference); }
public Cluster(NewColor centroid, int index) { this.centroid = centroid; this.id = index; }
public byte[] KMeans(byte[] buffer, byte[] result, int k) { Random rand = new Random(); var colors = new HashSet <NewColor>(); //uniqe colors in an image for (int i = 0; i < buffer.Length; i = i + 4) { NewColor color = new NewColor(buffer[i + 2], buffer[i + 1], buffer[i]); colors.Add(color); } List <NewColor> allColors = colors.ToList(); // limit k to existing number of colors if (k > colors.Count) { k = colors.Count; } NewColor[] centroids = new NewColor[k]; NewColor[] avgCentroids = new NewColor[k]; // random initial centroids for (int i = 0; i < k; i++) { centroids[i] = allColors[rand.Next(allColors.Count)]; } bool changed = true; int iteration = 0; //till centroids are changing and maximum no of iteratioins is not achieved while (changed && iteration < 100) { iteration++; List <Cluster> clusters = new List <Cluster>(); //assign centroid to a cluster for (int i = 0; i < k; i++) { clusters.Add(new Cluster(centroids[i], i)); clusters[i].sumR = centroids[i].R; clusters[i].sumG = centroids[i].G; clusters[i].sumB = centroids[i].B; clusters[i].noOfcolors = 1; } // for all available colors assign clusters and calculate the resulting sums of RGB values for (int col = 0; col < allColors.Count; col++) { double minDistance = double.MaxValue; int clusterIndex = -1; NewColor color = allColors[col]; for (int c = 0; c < centroids.Length; c++) { double distance = NewColor.EucliceanDistance(color, centroids[c]); if (distance < minDistance) { minDistance = distance; clusterIndex = c; } } for (int cl = 0; cl < clusters.Count; cl++) { if (clusters[cl].id == clusterIndex) { clusters[clusterIndex].distances.Add(minDistance); clusters[clusterIndex].sumR += color.R; clusters[clusterIndex].sumG += color.G; clusters[clusterIndex].sumB += color.B; clusters[clusterIndex].noOfcolors += 1; } } } //for all centroids calculate the avg color in their cluster: if it equals centroid exit the loop, //otherwise assign the calculated avg and continue loop for (int j = 0; j < centroids.Length; j++) { int numOfColors = clusters[j].noOfcolors; avgCentroids[j] = new NewColor((clusters[j].sumR / numOfColors), (clusters[j].sumG / numOfColors), (clusters[j].sumB / numOfColors)); if (centroids[j].R == avgCentroids[j].R && centroids[j].G == avgCentroids[j].G && centroids[j].B == avgCentroids[j].B) { changed = false; } else { centroids[j].R = avgCentroids[j].R; centroids[j].G = avgCentroids[j].G; centroids[j].B = avgCentroids[j].B; } } } //for all pixels for (int i = 0; i < buffer.Length; i = i + 4) { NewColor color = new NewColor(buffer[i + 2], buffer[i + 1], buffer[i]); double minDistance = double.MaxValue; int clusterIndex = -1; for (int m = 0; m < k; m++) { double distance = NewColor.EucliceanDistance(color, centroids[m]); if (distance < minDistance) { minDistance = distance; clusterIndex = m; } } result[i + 3] = 255; result[i + 2] = (byte)centroids[clusterIndex].R; result[i + 1] = (byte)centroids[clusterIndex].G; result[i] = (byte)centroids[clusterIndex].B; } return(result); }