/// <summary>
        /// This performs the union operation on the set which contains the values passed
        /// This Union is union by size for smaller trees
        /// Performs path compression upon performing this union becuase it must find the root
        /// </summary>
        /// <seealso cref="https://www.youtube.com/watch?v=gcmjC-OcWpI"/>
        /// <param name="p_labels">up to 4 values whose sets need to be merged</param>
        /// <returns>The new root of the unioned values</returns>
        public static ComponentLabel Union(int[] p_labels)
        {
            ComponentLabel bigger, smaller;

            bigger = null;

            for (int i = 0; i < p_labels.Length - 1; ++i)
            {
                for (int j = i + 1; j < p_labels.Length; ++j)
                {
                    //Get the root of each value
                    smaller = Find(p_labels[j]);
                    bigger  = Find(p_labels[i]);

                    if (bigger.m_id != smaller.m_id)
                    {
                        if ((bigger.m_size == smaller.m_size && smaller.m_id < bigger.m_id) ||
                            bigger.m_size < smaller.m_size)
                        {
                            //I want to merge smaller sets to larger ones and higher numbers to lesser numbers
                            ComponentLabel temp = smaller;
                            smaller = bigger;
                            bigger  = temp;
                        }

                        smaller.m_parent = bigger;
                        bigger.m_size   += smaller.m_size;
                    }
                }
            }

            return(bigger);
        }
 /// <summary>
 /// recursively search the parent structure of the label until it cannot go any further
 /// </summary>
 /// <param name="p_label">instantiated label</param>
 /// <returns>the root of the set that contains this label</returns>
 public static ComponentLabel Find(ComponentLabel p_label)
 {
     if (p_label.m_parent == null)
     {
         return(p_label);
     }
     else
     {
         return(Find(p_label.m_parent));
     }
 }
Esempio n. 3
0
        /// <summary>
        /// This uses the two pass method to search for blobs
        /// </summary>
        /// <seealso cref="https://en.wikipedia.org/wiki/Connected-component_labeling"/>
        /// <param name="p_data"></param>
        /// <param name="p_buffer"></param>
        /// <returns>All blobs found from search</returns>
        static public Dictionary <int, List <Point> > findBlobs(ref BitmapData p_data, ref byte[] p_buffer)
        {
            Dictionary <int, List <Point> > blobs    = new Dictionary <int, List <Point> >();
            Dictionary <int, int>           labelMap = new Dictionary <int, int>();

            //Create and populate a binary map
            int[,] binMap = new int[p_data.Height, p_data.Width];

            for (int i = 0; i < p_buffer.Length; i += 4)
            {
                if (p_buffer[i] != 0)
                {
                    binMap[i / p_data.Stride, (i % p_data.Stride) / 4] = 1;
                }
            }

            //curLabel is not instantiated here because the first pixel will never have a point to the left or above it.
            //  Therefore it will be instantiated before I use it.
            ComponentLabel curLabel = null;

            #region First Pass
            HashSet <int> searchSpace = new HashSet <int>();
            int           min;
            //iterate through binmap and find foreground pixels
            for (int y = 1; y < p_data.Height; ++y)
            {
                for (int x = 1; x < p_data.Width - 1; ++x)
                {
                    if (binMap[y, x] == 1)
                    {
                        for (int i = 0; i < 4; ++i)
                        {
                            searchSpace.Add(binMap[y + (i / 3) - 1, x + (i % 3) - 1]);
                        }

                        searchSpace.Remove(0); //remove background pixels
                        searchSpace.Remove(1); //remove first row and last column foreground pixels
                        switch (searchSpace.Count)
                        {
                        case 0:
                            curLabel = ComponentLabel.getInstance();
                            break;

                        case 1:
                            if (curLabel.Id != searchSpace.First())
                            {
                                curLabel = ComponentLabel.getInstance(searchSpace.First());
                            }
                            break;

                        case 4:
                        case 3:
                        case 2:     //This is gaurenteed to be two different values from left and top right
                            curLabel = ComponentLabel.Union(searchSpace.ToArray());
                            break;

                        default:
                            throw new Exception("4 distinct values in blob detection");
                        }

                        searchSpace.Clear();
                        binMap[y, x] = curLabel.Id;
                    }
                }
            }
            #endregion
            #region Second Pass
            if (curLabel != null)
            {
                int root, label;
                label = curLabel.Id;
                root  = ComponentLabel.Find(label).Id;

                for (int y = 1; y < p_data.Height; ++y)
                {
                    for (int x = 1; x < p_data.Width - 1; ++x)
                    {
                        if (binMap[y, x] != 0)
                        {
                            //Store the labels and roots into a map for constant lookup
                            if (binMap[y, x] != label)
                            {
                                label = binMap[y, x];

                                if (!labelMap.ContainsKey(label))
                                {
                                    labelMap[label] = ComponentLabel.Find(label).Id;
                                }

                                root = labelMap[label];
                            }
                            //if the blob for this root doesn't exist create it
                            if (!blobs.ContainsKey(root))
                            {
                                blobs[root] = new List <Point>();
                            }

                            blobs[root].Add(new Point(x, y));
                        }
                    }
                }
            }
            #endregion

            ComponentLabel.dispose();

            return(blobs);
        }