/// <summary> /// Calculates the centroids of the clusters /// </summary> public void CalculateClusterCentroids() { //Console.WriteLine("Cluster Centroid calculation:"); for (int j = 0; j < this.Clusters.Count; j++) { ClusterCentroid c = this.Clusters[j]; double l = 0.0; c.PixelCount = 1; c.RSum = 0; c.GSum = 0; c.BSum = 0; c.MembershipSum = 0; for (int i = 0; i < this.Points.Count; i++) { ClusterPoint p = this.Points[i]; l = Math.Pow(U[i, j], this.Fuzzyness); c.RSum += l * p.PixelColor.R; c.GSum += l * p.PixelColor.G; c.BSum += l * p.PixelColor.B; c.MembershipSum += l; if (U[i, j] == p.ClusterIndex) { c.PixelCount += 1; } } c.PixelColor = Color.FromArgb((byte)(c.RSum / c.MembershipSum), (byte)(c.GSum / c.MembershipSum), (byte)(c.BSum / c.MembershipSum)); } //update the original image Bitmap tempImage = new Bitmap(myImageWidth, myImageHeight, PixelFormat.Format32bppRgb); for (int j = 0; j < this.Points.Count; j++) { for (int i = 0; i < this.Clusters.Count; i++) { ClusterPoint p = this.Points[j]; if (U[j, i] == p.ClusterIndex) { tempImage.SetPixel((int)p.X, (int)p.Y, this.Clusters[i].PixelColor); } } } processedImage = tempImage; }
/// <summary> /// Initialize the algorithm with points and initial clusters /// </summary> /// <param name="points">The list of Points objects</param> /// <param name="clusters">The list of Clusters objects</param> /// <param name="fuzzy">The fuzzyness factor to be used, constant</param> /// <param name="myImage">A working image, so that the GUI working image can be updated</param> /// <param name="numCluster">The number of clusters requested by the user from the GUI</param> public KMeansAlgorithm(List <ClusterPoint> points, List <ClusterCentroid> clusters, float fuzzy, Bitmap myImage, int numCluster) { if (points == null) { throw new ArgumentNullException("points"); } if (clusters == null) { throw new ArgumentNullException("clusters"); } processedImage = (Bitmap)myImage.Clone(); this.Points = points; this.Clusters = clusters; this.myImageHeight = myImage.Height; this.myImageWidth = myImage.Width; this.myImage = new Bitmap(myImageWidth, myImageHeight, PixelFormat.Format32bppRgb); U = new double[this.Points.Count, this.Clusters.Count]; this.Fuzzyness = fuzzy; double diff; // Iterate through all points to create initial U matrix for (int i = 0; i < this.Points.Count; i++) { ClusterPoint p = this.Points[i]; double sum = 0.0; for (int j = 0; j < this.Clusters.Count; j++) { ClusterCentroid c = this.Clusters[j]; diff = Math.Sqrt(Math.Pow(CalculateEuclideanDistance(p, c), 2.0)); U[i, j] = (diff == 0) ? Eps : diff; sum += U[i, j]; } } this.RecalculateClusterMembershipValues(); }
/// <summary> /// Calculates Euclidean Distance distance between a point and a cluster centroid /// </summary> /// <param name="p">Point</param> /// <param name="c">Centroid</param> /// <returns>Calculated distance</returns> private double CalculateEuclideanDistance(ClusterPoint p, ClusterCentroid c) { return Math.Sqrt(Math.Pow(p.PixelColor.R - c.PixelColor.R, 2.0) + Math.Pow(p.PixelColor.G - c.PixelColor.G, 2.0) + Math.Pow(p.PixelColor.B - c.PixelColor.B, 2.0)); }
/// <summary> /// Calculates Euclidean Distance distance between a point and a cluster centroid /// </summary> /// <param name="p">Point</param> /// <param name="c">Centroid</param> /// <returns>Calculated distance</returns> private double CalculateEuclideanDistance(ClusterPoint p, ClusterCentroid c) { return(Math.Sqrt(Math.Pow(p.PixelColor.R - c.PixelColor.R, 2.0) + Math.Pow(p.PixelColor.G - c.PixelColor.G, 2.0) + Math.Pow(p.PixelColor.B - c.PixelColor.B, 2.0))); }
// This method will run on a thread other than the UI thread. // Be sure not to manipulate any Windows Forms controls created // on the UI thread from this method. private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { Database dataBase = new Database(); backgroundWorker.ReportProgress(0, "Working..."); filteredImage = (Bitmap)picPreview.Image.Clone(); int numClusters = (int)txtNumClusters.Value; int maxIterations = (int)txtIterations.Value; double accuracy = 0.00001; 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)); } } 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))); } /*foreach (ClusterPoint p in points) * { * List<SqlParameter> listParam = new List<SqlParameter>(4); * listParam.Add(new SqlParameter("@x",p.X)); * listParam.Add(new SqlParameter("@y", p.Y)); * listParam.Add(new SqlParameter("@Color", p.PixelColor.ToArgb())); * listParam.Add(new SqlParameter("@ImageId ", 1)); * dataBase.RunProcedure("usp_ClusterPointsInsert", listParam.ToArray()); * }*/ KMeansAlgorithm alg = new KMeansAlgorithm(points, centroids, 2, filteredImage, (int)txtNumClusters.Value); int k = 0; do { if ((backgroundWorker.CancellationPending == true)) { e.Cancel = true; break; } else { 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)); toolStripStatusLabel2.Text = "Precision " + Math.Abs(alg.J - Jnew); // Format and display the TimeSpan value. string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", stopWatch.Elapsed.Hours, stopWatch.Elapsed.Minutes, stopWatch.Elapsed.Seconds, stopWatch.Elapsed.Milliseconds / 10); toolStripStatusLabel3.Text = "Duration: " + elapsedTime; picProcessed.Image = (Bitmap)alg.getProcessedImage; backgroundWorker.ReportProgress((100 * k) / maxIterations, "Iteration " + k); if (Math.Abs(alg.J - Jnew) < accuracy) { break; } } }while (maxIterations > k); Console.WriteLine("Done."); stopWatch.Stop(); // Get the elapsed time as a TimeSpan value. TimeSpan ts = stopWatch.Elapsed; // Save the segmented image picProcessed.Image = (Bitmap)alg.getProcessedImage.Clone(); // Create a new image for each cluster in order to extract the features from the original image double[,] Matrix = alg.U; Bitmap[] bmapArray = new Bitmap[centroids.Count]; for (int i = 0; i < centroids.Count; i++) { bmapArray[i] = new Bitmap(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppRgb); } for (int j = 0; j < points.Count; j++) { for (int i = 0; i < centroids.Count; i++) { ClusterPoint p = points[j]; if (Matrix[j, i] == p.ClusterIndex) { bmapArray[i].SetPixel((int)p.X, (int)p.Y, p.OriginalPixelColor); } } } k = Application.StartupPath.IndexOf("\\bin"); string sub = Application.StartupPath.Substring(k); string ImagePath = Application.StartupPath.Substring(0, Application.StartupPath.Length - sub.Length) + "\\AnhData\\"; DirectoryInfo dirInfo = new DirectoryInfo(ImagePath); if (dirInfo.Exists) { dirInfo.Create(); } List <SqlParameter> listParam = new List <SqlParameter>(4); string imageName = ofdCluster.FileName.Substring(ofdCluster.FileName.LastIndexOf(@"\") + 1); listParam.Add(new SqlParameter("@ImageName", imageName.Substring(0, ofdCluster.FileName.Substring(ofdCluster.FileName.LastIndexOf(@"\") + 1).Length - imageName.Substring(imageName.LastIndexOf(".")).Length) + "_segmented.png")); listParam.Add(new SqlParameter("@Url", "\\AnhData\\" + imageName.Substring(0, ofdCluster.FileName.Substring(ofdCluster.FileName.LastIndexOf(@"\") + 1).Length - imageName.Substring(imageName.LastIndexOf(".")).Length) + "_segmented.png")); listParam.Add(new SqlParameter("@Width", picPreview.Image.Width)); listParam.Add(new SqlParameter("@Height", picPreview.Image.Height)); dataBase.RunProcedure("usp_ImageInsert", listParam.ToArray()); alg.getProcessedImage.Save(ImagePath + imageName.Substring(0, ofdCluster.FileName.Substring(ofdCluster.FileName.LastIndexOf(@"\") + 1).Length - imageName.Substring(imageName.LastIndexOf(".")).Length) + "_segmented.png"); // Save the image for each segmented cluster for (int i = 0; i < centroids.Count; i++) { bmapArray[i].Save(ImagePath + imageName.Substring(0, ofdCluster.FileName.Substring(ofdCluster.FileName.LastIndexOf(@"\") + 1).Length - imageName.Substring(imageName.LastIndexOf(".")).Length) + "_" + i + ".png"); List <SqlParameter> listParam1 = new List <SqlParameter>(4); listParam1.Add(new SqlParameter("@ImageName", imageName.Substring(0, ofdCluster.FileName.Substring(ofdCluster.FileName.LastIndexOf(@"\") + 1).Length - imageName.Substring(imageName.LastIndexOf(".")).Length) + "_" + i + ".png")); listParam1.Add(new SqlParameter("@Url", "\\AnhData\\" + imageName.Substring(0, ofdCluster.FileName.Substring(ofdCluster.FileName.LastIndexOf(@"\") + 1).Length - imageName.Substring(imageName.LastIndexOf(".")).Length) + "_" + i + ".png")); listParam1.Add(new SqlParameter("@Width", picPreview.Image.Width)); listParam1.Add(new SqlParameter("@Height", picPreview.Image.Height)); dataBase.RunProcedure("usp_ImageInsert", listParam1.ToArray()); /*DataTable dt = dataBase.RunProcedureGet("usp_ImageGetAfterInsert"); * if (dt.Rows.Count > 0) * { * * List<SqlParameter> listParam1 = new List<SqlParameter>(4); * listParam1.Add(new SqlParameter("@x", centroids[i].X)); * listParam1.Add(new SqlParameter("@y", centroids[i].Y)); * listParam1.Add(new SqlParameter("@Color", centroids[i].PixelColor.ToArgb())); * listParam1.Add(new SqlParameter("@ImageId ", dt.Rows[0][0])); * dataBase.RunProcedure("usp_ClusterCentroidsInsert", listParam1.ToArray()); * }*/ } // Resource cleanup...more work to do here to avoid memory problems!!! backgroundWorker.ReportProgress(100, "Done in " + k + " iterations."); ////alg.Dispose(); for (int i = 0; i < points.Count; i++) { points[i] = null; } for (int i = 0; i < centroids.Count; i++) { centroids[i] = null; } alg = null; //centroids.Clear(); //points.Clear(); }