public double GetEuclClr(KMCPoint <int> Point1, KMCPoint <int> Point2)
 {
     // Compute the Euclidian distance between two colors in the 3D-space
     return(Math.Sqrt(Math.Pow(Math.Abs(Point1.Clr.R - Point2.Clr.R), 2) +
                      Math.Pow(Math.Abs(Point1.Clr.G - Point2.Clr.G), 2) +
                      Math.Pow(Math.Abs(Point1.Clr.B - Point2.Clr.B), 2)));
 }
        private bool IsValidDistance(List <KMCPoint <int> > Points, KMCPoint <int> Target, Int32 Distance)
        {
            Int32 Index = -1; bool Exists = false;

            // Iterate through the array of super-pixels until we've found the super-pixel which
            // distance to the target super-pixel is less than or equals to the specified boundary
            while (++Index < Points.Count() && !Exists)
            {
                // For each super-pixel from the array we compute the value of distance and
                // perform a check if the following value is less than or equals to
                // the value of specific boundary parameter.
                Exists = ((Math.Abs(Target.X - Points.ElementAt(Index).X) <= Distance) ||
                          (Math.Abs(Target.Y - Points.ElementAt(Index).Y) <= Distance)) ? true : false;
            }

            return(Exists);
        }
        private bool IsValidColor(List <KMCPoint <int> > Points, KMCPoint <int> Target, Int32 Offset)
        {
            Int32 Index = -1; bool Exists = false;

            // Iterate through the array of super-pixels until we've found the super-pixel which
            // color offset to the target super-pixel is less than or equals to the specified boundary
            while (++Index < Points.Count() && !Exists)
            {
                // For each super-pixel from the array we compute the value of color offset and
                // perform a check if the following value is less than or equals to
                // the value of specific boundary parameter.
                Exists = (Math.Sqrt(Math.Pow(Math.Abs(Points[Index].Clr.R - Target.Clr.R), 2) +
                                    Math.Pow(Math.Abs(Points[Index].Clr.G - Target.Clr.G), 2) +
                                    Math.Pow(Math.Abs(Points[Index].Clr.B - Target.Clr.B), 2))) <= Offset ? true : false;
            }

            return(Exists);
        }
        public void Init(Bitmap Filename, Int32 Distance, Int32 Offset)
        {
            // Declare a bitmap object to load and use the original image to be segmented
            LockedBitmap FrameBuffer = new LockedBitmap(Filename);

            // Initialize the array of super-pixels by creating List<KMCPoint<int>> class object
            List <KMCPoint <int> > Centroids = new List <KMCPoint <int> >();

            // Generate an initial array of super-pixels of the original source image
            // stored in the FrameBuffer bitmap object
            this.Generate(ref Centroids, FrameBuffer, Distance, Offset);

            // Compute the value of the centeral super-pixel coordinates and assign it
            // to the Mean local variable
            KMCPoint <int> Mean = this.GetMean(FrameBuffer, Centroids);

            // Append an initial cluster being initialized to the array of clusters
            m_Clusters.Add(new KMCFrame(FrameBuffer, Centroids, Mean));
        }
        public void Generate(ref List <KMCPoint <int> > Centroids, LockedBitmap ImageFrame, Int32 Distance, Int32 Offset)
        {
            // Compute the number of iterations performed by the main loop equal to image W * H
            // The following value is the maximum possible number of random super-pixel being generated
            Int32 Size = ImageFrame.Width * ImageFrame.Height;

            ImageFrame.LockBits();
            // Performing Size - iterations of the following loop to generate a specific amount of super-pixels
            for (Int32 IterCount = 0; IterCount < Size; IterCount++)
            {
                // Obtain a random value of X - coordinate of the current super-pixel
                Int32 Rand_X = rand.Next(0, ImageFrame.Width);
                // Obtain a random value of Y - coordinate of the current super-pixel
                Int32 Rand_Y = rand.Next(0, ImageFrame.Height);

                // Create and instantinate a point object by using the values of
                // Rand_X, Rand_Y and Colorref parameters. The value of colorref is
                // retrieved by using the GetPixel method for the current bitmap object
                KMCPoint <int> RandPoint = new KMCPoint <int>(Rand_X,
                                                              Rand_Y, ImageFrame.GetPixel(Rand_X, Rand_Y));

                // Performing a validity check if none of those super-pixel previously
                // selected don't exceed the distance and color offset boundary to the
                // currently generated super-pixel with coordinates Rand_X and Rand_Y and
                // specific color stored as a parameter value of Clr variable
                if (!this.IsValidColor(Centroids, RandPoint, Offset) &&
                    !this.IsValidDistance(Centroids, RandPoint, Distance))
                {
                    // If not, check if the super-pixel with the following coordinates and color
                    // already exists in the array of centroid super-pixels being generated.
                    if (!Centroids.Contains(RandPoint))
                    {
                        // If not, append the object RandPoint to the array of super-pixel objects
                        Centroids.Add(RandPoint);
                    }
                }
            }

            ImageFrame.UnlockBits();
        }
 public void Add(LockedBitmap FrameImage, List <KMCPoint <int> > Centroids, KMCPoint <int> Center)
 {
     m_Clusters.Add(new KMCFrame(FrameImage, Centroids, Center));
 }
 // KMCFrame Constructor
 public KMCFrame(LockedBitmap Frame, List <KMCPoint <Int32> > Centroids, KMCPoint <Int32> Center)
 {
     this.Frame       = Frame;
     this.m_Centroids = Centroids; this.Center = Center;
 }
        public Bitmap Compute(Bitmap InputFile)
        {
            // Initialize the code execution timer
            var watch = System.Diagnostics.Stopwatch.StartNew();

            // Initialize the directory info reference object
            DirectoryInfo dir_info = new DirectoryInfo("Clusters");

            // Check if the directory with name "Clusters" is created.
            // If not, create the directory with name "Clusters"
            if (dir_info.Exists == false)
            {
                dir_info.Create();
            }

            // Initialize the array of clusters by generating an initial cluster
            // containing the original source image associated with the array of super-pixels
            m_Clusters.Init((Bitmap)InputFile.Clone(), m_Distance, m_OffsetClr);

            // Initialize the bitmap object used to store the resulting segmented image
            LockedBitmap ResultBitmap = new LockedBitmap(m_Clusters[0].Frame.Width, m_Clusters[0].Frame.Height);

            Int32 FrameIndex = 0;

            // Iterate throught the array of clusters until we've process all clusters being generated
            for (Int32 Index = 0; Index < m_Clusters.Count(); Index++)
            {
                // For each particular cluster from the array, obtain the values of bitmap object and
                // the List<KMCPoint<int>> object which is the array of centroid super-pixels
                List <KMCPoint <int> > Centroids   = m_Clusters[Index].Centroids.ToList();
                LockedBitmap           FrameBuffer = new LockedBitmap(m_Clusters[Index].Frame.m_Bitmap);

                // Save the image containg the segmented area associated with the current cluster to the
                // specific file, which name has the following format, for example "D:\Clusters\Cluster_N.jpg"
                FrameBuffer.Save("Clusters\\Cluster_" + FrameIndex + ".jpg");

                FrameBuffer.LockBits();

                // Iterating through the array of centroid super pixels and for each super-pixels
                // perform a linear search to find all those pixel in the current image which distance
                // does not exceed the value of specific boundary parameter.
                for (Int32 Cnt = 0; Cnt < Centroids.Count(); Cnt++)
                {
                    // Obtain the value of Width and Height of the image for the current cluster
                    Int32 Width  = FrameBuffer.Width;
                    Int32 Height = FrameBuffer.Height;

                    // Create a bitmap object to store an image for the newly built cluster
                    LockedBitmap TargetFrame = new LockedBitmap(FrameBuffer.Width, FrameBuffer.Height);

                    TargetFrame.LockBits();

                    // Iterate through each element of the matrix of pixels for the current image
                    for (Int32 Row = 0; Row < FrameBuffer.Width; Row++)
                    {
                        for (Int32 Col = 0; Col < Height; Col++)
                        {
                            // For each pixel in this matrix, compute the value of color offset of the current centroid super-pixel
                            double OffsetClr = GetEuclClr(new KMCPoint <int>(Row, Col, FrameBuffer.GetPixel(Row, Col)),
                                                          new KMCPoint <int>(Centroids[Cnt].X, Centroids[Cnt].Y, Centroids[Cnt].Clr));

                            //Perform a check if the color offset value does not exceed the value of boundary parameter
                            if (OffsetClr <= 50)
                            {
                                // Copy the current pixel to the target image for the newly created cluster
                                TargetFrame.SetPixel(Row, Col, Centroids[Cnt].Clr);
                            }

                            // Otherwise, set the color of the current pixel to "white" (R;G;B) => (255;255;255)
                            // in the target bitmap for the newly built cluster
                            else
                            {
                                TargetFrame.SetPixel(Row, Col, Color.FromArgb(255, 255, 255));
                            }
                        }
                    }

                    TargetFrame.UnlockBits();

                    // Create an array of centroid super-pixels and append
                    // it the value of current centroid super-pixel retrieved
                    List <KMCPoint <int> > TargetCnts = new List <KMCPoint <int> >();
                    TargetCnts.Add(Centroids[0]);

                    // Compute the "mean" value for the newly created cluster
                    KMCPoint <int> Mean = m_Clusters.GetMean(TargetFrame, TargetCnts);

                    // Perform a check if the "mean" point coordinates of the newly created cluster are
                    // not equal to the coordinates of the current centroid super-pixel (e.g. the centroid
                    // super-pixel has been moved). If so, append a newly built cluster to the array of clusters
                    if (Mean.X != m_Clusters[Index].Center.X && Mean.Y != m_Clusters[Index].Center.Y)
                    {
                        m_Clusters.Add(TargetFrame, TargetCnts, Mean);
                    }

                    FrameIndex++;
                }

                FrameBuffer.UnlockBits();
            }

            ResultBitmap.LockBits();

            // Iterate through the array of clusters previously obtained
            for (Int32 Index = 0; Index < m_Clusters.Count(); Index++)
            {
                // For each cluster retrieve a specific image containing the segmented area
                LockedBitmap FrameOut = new LockedBitmap(m_Clusters[Index].Frame.m_Bitmap);

                FrameOut.LockBits();

                FrameOut.Save("temp_" + Index + ".jpg");

                // Obtain the dimensions of that image
                int Width = FrameOut.Width, Height = FrameOut.Height;
                // Iterate through the matrix of pixels for the current image and for each
                // pixel perform a check if its color is not equal to "white" (R;G;B) => (255;255;255).
                // If not, copy the pixel data to the target matrix of pixels for the resulting segmented image
                for (Int32 Row = 0; Row < Width; Row++)
                {
                    for (Int32 Col = 0; Col < Height; Col++)
                    {
                        if (FrameOut.GetPixel(Row, Col) != Color.FromArgb(255, 255, 255))
                        {
                            ResultBitmap.SetPixel(Row, Col, FrameOut.GetPixel(Row, Col));
                        }
                    }
                }

                FrameOut.UnlockBits();
            }

            ResultBitmap.UnlockBits();

            // Save the segmented image to file with name which is the value of OutputFile variable
            //ResultBitmap.Save(OutputFile);

            watch.Stop(); // Stop the execution timer
            // Obtain the value of executing time in milliseconds
            var elapsedMs = watch.ElapsedMilliseconds;

            // Create timespan from the elapsed milliseconds value
            TimeSpan ts = TimeSpan.FromMilliseconds(elapsedMs);

            // Print the message "Done" and the formatted execution time
            Console.WriteLine("***Done***\n" + ts.ToString(@"hh\:mm\:ss"));

            return(ResultBitmap.m_Bitmap);
        }
 public double GetEuclD(KMCPoint <int> Point1, KMCPoint <int> Point2)
 {
     // Compute the Euclidian distance between two pixel in the 2D-space
     return(Math.Sqrt(Math.Pow(Point1.X - Point2.X, 2) +
                      Math.Pow(Point1.Y - Point2.Y, 2)));
 }