Counting Regions in Images II

Carrying on from the previous post, in order to better illustrate the affects of the different thresholds, the thresholds were made as input parameters to this new algorithm, and in addition the color of each region was made different from each other, plus some bug fixes (casting fixes, etc.).

To illustrate the concept I picked up an image of me running and applied the algorithm varying the thresholds. As you can see from the image below, the smaller the thresholds the more regions it finds, and conversely as we increase the thresholds the bigger and the fewer the regions are.

If one makes the thresholds zero, it will imply that each pixel will be its own region. Similarly, when the threshold goes to infinity, the entire image becomes just one big region. Hope this helps - cheers, Marcelo.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Collections;

namespace CountRegions
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length != 3)
            {
                Console.WriteLine("Usage: CountRegions.exe <image file> <neighbors threshold> <center threshold>");
                return;
            }

            MyImage myImage = new MyImage(args[0], Int32.Parse(args[1]), Int32.Parse(args[2]));

            Console.WriteLine("Processing...");
            myImage.CountRegions();
            Console.WriteLine("Done!");
        }
    }

    class MyImage
    {
        Bitmap image = null;
        int thresholdNeighbor = 50; //Some default...
        int thresholdSeed = 60; //Some default...

        private MyImage() { }

        public MyImage(string imageFileName, int thresholdNeighbor, int thresholdSeed)
        {
            this.image = new Bitmap(imageFileName);
            this.thresholdNeighbor = thresholdNeighbor;
            this.thresholdSeed = thresholdSeed;
        }

        public void CountRegions()
        {
            bool[,] mark = new bool[image.Width, image.Height];

            Color[] regionColors = {
                                    Color.DarkBlue,
                                    Color.DarkCyan,
                                    Color.DarkGoldenrod,
                                    Color.DarkGray,
                                    Color.DarkGreen,
                                    Color.DarkKhaki,
                                    Color.DarkMagenta,
                                    Color.DarkOliveGreen,
                                    Color.DarkOrange,
                                    Color.DarkOrchid,
                                    Color.DarkRed,
                                    Color.DarkSalmon,
                                    Color.DarkSeaGreen,
                                    Color.DarkSlateBlue,
                                    Color.DarkSlateGray,
                                    Color.DarkTurquoise,
                                    Color.DarkViolet
                                   };
            int indexRegionColors = 0;

            for (int c = 0; c < image.Width; c++)
            {
                for (int r = 0; r < image.Height; r++)
                {
                    Color color = image.GetPixel(c, r);
                    if (!(color.R == 255 && color.G == 255 && color.B == 255))
                    {
                        if (!mark[c, r])
                        {
                            RegionMarkdownBFS(c, r, thresholdNeighbor, thresholdSeed, mark, regionColors[indexRegionColors]);
                            indexRegionColors = (indexRegionColors + 1) % regionColors.Length;
                        }
                    }
                }
            }

            Random rd = new Random();
            string outputFileName = "output_" + rd.Next().ToString() + ".jpg";
            image.Save(outputFileName);
            Console.WriteLine("File saved to {0}", outputFileName);
        }

        private void RegionMarkdownBFS(int c, int r, int thresholdNeighbor, int thresholdSeed, bool[,] mark, Color regionColor)
        {
            Queue queue = new Queue();

            Color pixelSeed = image.GetPixel(c, r);
            mark[c, r] = true;
            image.SetPixel(c, r, regionColor);

            long key = r * image.Width + c;
            queue.Enqueue(key);
            while (queue.Count > 0)
            {
                key = (long)queue.Dequeue();

                int currentRow = (int)(key / image.Width);
                int currentCol = (int)(key % image.Width);

                Color currentColor = image.GetPixel(currentCol, currentRow);

                //Mark in the image
                image.SetPixel(currentCol, currentRow, regionColor);

                //Check neighbors
                for (int or = -1; or <= 1; or++)
                {
                    for (int oc = -1; oc <= 1; oc++)
                    {
                        if (currentRow + or >= 0 &&
                            currentRow + or < image.Height &&
                            currentCol + oc >= 0 &&
                            currentCol + oc < image.Width &&
                            !mark[currentCol + oc, currentRow + or])
                        {
                            Color neighborColor = image.GetPixel(currentCol + oc, currentRow + or);

                            if (!(neighborColor.R == 255 && neighborColor.G == 255 && neighborColor.B == 255))
                            {
                                if (Math.Abs(neighborColor.R - currentColor.R) <= thresholdNeighbor &&
                                    Math.Abs(neighborColor.G - currentColor.G) <= thresholdNeighbor &&
                                    Math.Abs(neighborColor.B - currentColor.B) <= thresholdNeighbor)
                                {
                                    if (Math.Abs(neighborColor.R - pixelSeed.R) <= thresholdSeed &&
                                        Math.Abs(neighborColor.G - pixelSeed.G) <= thresholdSeed &&
                                        Math.Abs(neighborColor.B - pixelSeed.B) <= thresholdSeed)
                                    {
                                        queue.Enqueue((long)(currentRow + or) * image.Width + currentCol + oc);
                                        mark[currentCol + oc, currentRow + or] = true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        public void Print()
        {
            for (int r = 0; r < image.Height; r++)
            {
                for (int c = 0; c < image.Width; c++)
                {
                    Color color = image.GetPixel(c, r);
                    Console.Write("({0},{1},{2}) ", color.R, color.G, color.B);
                }
                Console.WriteLine();
            }
        }
    }
}

Comments

Popular posts from this blog

Changing the root of a binary tree

Prompt Engineering and LeetCode

ProjectEuler Problem 719 (some hints, but no spoilers)