public void Apply(SRegion region)
        {
            Rectangle bounds = region.RegionRectangle;
            unsafe
            {
                int dilationCenterX =   (structElementSize.Width - 1) / 2;
                int dilationCenterY =   (structElementSize.Height - 1) / 2;
                int dilationMaxX =      structElementSize.Width - 1;
                int dilationMaxY =      structElementSize.Height - 1;

                int* _dilationCenterX = (int*)dilationCenterX;
                int* _dilationCenterY = (int*)dilationCenterY;
                int* _dilationMaxX = (int*)dilationMaxX;
                int* _dilationMaxY = (int*)dilationMaxX;

                int* x_min = (int*)bounds.X;
                int* x_max = (int*)(bounds.X + bounds.Width - (int)_dilationCenterX);
                int* y_min = (int*)bounds.Y;
                int* y_max = (int*)(bounds.Y + bounds.Height - (int)_dilationCenterY);

                for (int* x = x_min; x < x_max; x++)
                {
                    for (int* y = y_min; y < y_max; y++)
                    {
                        bool bitVal = region[(int)x, (int)y];

                        for (int* sX = (int*)0; sX < _dilationMaxX; sX++)
                        {
                            for (int* sY = (int*)0; sY < _dilationMaxY; sY++)
                            {
                                if (structElement[(int)sX, (int)sY] & region[(int)x + (int)sX, (int)y + (int)sY])
                                {
                                    region.AddPoint((int)x + dilationCenterX, (int)y + dilationCenterY);
                                }
                            }
                        }
                    }
                }
            }
        }
        private unsafe void CreateRegionCollection()
        {
            ///Create regions collection
            Dictionary<int, SRegion> regionDictionary = new Dictionary<int, SRegion>();
            unchecked
            {
                for (int x = 0; x < Image.Size.Width; x++)
                {
                    for (int y = 0; y < Image.Size.Height; y++)
                    {
                        int regionId = binaryMask[x, y];
                        if (regionId > 0)
                        {
                            if (regionDictionary.ContainsKey(regionId))
                            {
                                regionDictionary[regionId].AddPoint(x, y);
                            }
                            else
                            {
                                SRegion region = new SRegion(ref binaryMask, regionId, base.Image.Size);
                                region.AddPoint(x, y);
                                regionDictionary.Add(regionId, region);
                            }
                        }
                    }
                }
            }

            ///Convert region connection to array of regions
            regions = new SRegion[regionDictionary.Count];
            int index = 0;
            foreach (SRegion r in regionDictionary.Values)
            {
                regions[index] = r;
                index++;
            }
        }
        public override void Execute()
        {
            foreach (IPreProcessFilter filter in preProcessFilters)
            {
                filter.Apply(base.Image.Size, this.regionMask);
            }

            int regionIndex = 1;
            regionMask = new int[base.Image.Width, base.Image.Height];
            for (int x = 0; x < base.Image.Width; x++)
            {
                for (int y = 0; y < base.Image.Height; y++)
                {
                    if (regionMask[x, y] == 0 & learned.Contains(base.Image.GetPixel(x, y)))
                    {
                        ///Flood-Fill algorithm
                        Queue<Point> q = new Queue<Point>();

                        if (regionMask[x, y] != 0)
                            continue;

                        regionIndex++;

                        q.Enqueue(new Point(x, y));

                        while (q.Count > 0)
                        {
                            Point p = q.Peek();
                            int x1 = p.X;
                            int y1 = p.Y;

                            if (IsValid(p) & learned.Contains(base.Image.GetPixel(x1, y1)))
                            {
                                regionMask[x1, y1] = regionIndex;
                            }

                            if (IsValid(new Point(x1, y1 + 1)))
                            {
                                regionMask[x1, y1 + 1] = regionIndex;
                                q.Enqueue(new Point(x1, y1 + 1));
                            }

                            if (IsValid(new Point(x1, y1 - 1)))
                            {
                                regionMask[x1, y1 - 1] = regionIndex;
                                q.Enqueue(new Point(x1, y1 - 1));
                            }

                            if (IsValid(new Point(x1 + 1, y1)))
                            {
                                regionMask[x1 + 1, y1] = regionIndex;
                                q.Enqueue(new Point(x1 + 1, y1));
                            }

                            if (IsValid(new Point(x1 - 1, y1)))
                            {
                                regionMask[x1 - 1, y1] = regionIndex;
                                q.Enqueue(new Point(x1 - 1, y1));
                            }

                            q.Dequeue();
                        }
                        ///end of Flood-Fill algorithm
                    }
                }
            }

            ///TODO: Check this.
            ///scan regionsMask pixel-by-pixel and forming regions groups
            Dictionary<int, SRegion> regionDictionary = new Dictionary<int, SRegion>();
            for (int x = 0; x < base.Image.Size.Width; x++)
            {
                for (int y = 0; y < base.Image.Size.Height; y++)
                {
                    int regionId = regionMask[x, y];
                    if (regionId > 0)
                    {
                        if (regionDictionary.ContainsKey(regionId))
                        {
                            regionDictionary[regionId].AddPoint(x, y);
                        }
                        else
                        {
                            //SRegion region = new SRegion(base.Image.Size);
                            SRegion region = new SRegion(ref regionMask, regionIndex, base.Image.Size);
                            region.AddPoint(x, y);
                            regionDictionary.Add(regionId, region);
                        }
                    }
                }
            }

            regions = new SRegion[regionDictionary.Count];
            int index = 0;
            foreach (SRegion r in regionDictionary.Values)
            {
                regions[index] = r;
                index++;
            }

            foreach (IPostProcessFilter filter in regionFilters)
            {
                filter.Apply(ref regions);
            }

            foreach (IPostProcessFilter filter in regionFilters)
            {
                foreach (SRegion region in regions)
                {
                    filter.Apply(region);
                }
            }
        }