public Blob(Blob source)
 {
     id = source.id;
     rect = source.rect;
     cog = source.cog;
     area = source.area;
     fullness = source.fullness;
     colorMean = source.colorMean;
     colorStdDev = source.colorStdDev;
 }
        // Collect objects' rectangles
        private void CollectObjectsInfo(PixelRegion sourcePixelRegion)
        {
            int i = 0, label;

            // create object coordinates arrays
            int[] x1 = new int[objectsCount + 1];
            int[] y1 = new int[objectsCount + 1];
            int[] x2 = new int[objectsCount + 1];
            int[] y2 = new int[objectsCount + 1];

            int[] area = new int[objectsCount + 1];
            long[] xc = new long[objectsCount + 1];
            long[] yc = new long[objectsCount + 1];

            long[] meanR = new long[objectsCount + 1];
            long[] meanG = new long[objectsCount + 1];
            long[] meanB = new long[objectsCount + 1];

            long[] stdDevR = new long[objectsCount + 1];
            long[] stdDevG = new long[objectsCount + 1];
            long[] stdDevB = new long[objectsCount + 1];

            for (int j = 1; j <= objectsCount; j++)
            {
                x1[j] = imageWidth;
                y1[j] = imageHeight;
            }

            // color images
            byte r, g, b; // RGB value

            // walk through labels array
            for (int y = 0; y < imageHeight; y++)
            {
                for (int x = 0; x < imageWidth; x++, i++)
                {
                    // get current label
                    label = objectLabels[i];

                    // skip unlabeled pixels
                    if (label == 0)
                        continue;

                    // check and update all coordinates

                    if (x < x1[label])
                    {
                        x1[label] = x;
                    }
                    if (x > x2[label])
                    {
                        x2[label] = x;
                    }
                    if (y < y1[label])
                    {
                        y1[label] = y;
                    }
                    if (y > y2[label])
                    {
                        y2[label] = y;
                    }

                    area[label]++;
                    xc[label] += x;
                    yc[label] += y;

                    Color c = ToColor(sourcePixelRegion.ImagePixels[y * imageWidth + x]);
                    r = c.R;
                    g = c.G;
                    b = c.B;

                    meanR[label] += r;
                    meanG[label] += g;
                    meanB[label] += b;

                    stdDevR[label] += r * r;
                    stdDevG[label] += g * g;
                    stdDevB[label] += b * b;
                }
            }

            // create blobs
            blobs.Clear();

            for (int j = 1; j <= objectsCount; j++)
            {
                int blobArea = area[j];

                Blob blob = new Blob(j, new Rect(x1[j], y1[j], x2[j] - x1[j] + 1, y2[j] - y1[j] + 1));
                blob.Area = blobArea;
                blob.Fullness = (double)blobArea / ((x2[j] - x1[j] + 1) * (y2[j] - y1[j] + 1));
                blob.CenterOfGravity = new Point((float)xc[j] / blobArea, (float)yc[j] / blobArea);
                blob.ColorMean = Color.FromArgb(255, (byte)(meanR[j] / blobArea), (byte)(meanG[j] / blobArea), (byte)(meanB[j] / blobArea));
                blob.ColorStdDev = Color.FromArgb(
                    255,
                    (byte)(Math.Sqrt(stdDevR[j] / blobArea - blob.ColorMean.R * blob.ColorMean.R)),
                    (byte)(Math.Sqrt(stdDevG[j] / blobArea - blob.ColorMean.G * blob.ColorMean.G)),
                    (byte)(Math.Sqrt(stdDevB[j] / blobArea - blob.ColorMean.B * blob.ColorMean.B)));

                blobs.Add(blob);
            }
        }
        public Blob[] GetObjectsInformation()
        {
            // check if objects map was collected
            if (objectLabels == null)
                throw new ApplicationException("Image should be processed before to collect objects map.");

            Blob[] blobsToReturn = new Blob[objectsCount];

            // create each blob
            for (int k = 0; k < objectsCount; k++)
            {
                blobsToReturn[k] = new Blob(blobs[k]);
            }

            return blobsToReturn;
        }
        public void GetBlobsTopAndBottomEdges(Blob blob, out List<Point> topEdge, out List<Point> bottomEdge)
        {
            // check if objects map was collected
            if (objectLabels == null)
                throw new ApplicationException("Image should be processed before to collect objects map.");

            topEdge = new List<Point>();
            bottomEdge = new List<Point>();

            int xmin = (int)blob.Rectangle.Left;
            int xmax = (int)(xmin + blob.Rectangle.Width - 1);
            int ymin = (int)blob.Rectangle.Top;
            int ymax = (int)(ymin + blob.Rectangle.Height - 1);

            int label = blob.ID;

            // for each column
            for (int x = xmin; x <= xmax; x++)
            {
                // scan from top to bottom
                int p = ymin * imageWidth + x;
                for (int y = ymin; y <= ymax; y++, p += imageWidth)
                {
                    if (objectLabels[p] == label)
                    {
                        topEdge.Add(new Point(x, y));
                        break;
                    }
                }

                // scan from bottom to top
                p = ymax * imageWidth + x;
                for (int y = ymax; y >= ymin; y--, p -= imageWidth)
                {
                    if (objectLabels[p] == label)
                    {
                        bottomEdge.Add(new Point(x, y));
                        break;
                    }
                }
            }
        }
        public void GetBlobsLeftAndRightEdges(Blob blob, out List<Point> leftEdge, out List<Point> rightEdge)
        {
            // check if objects map was collected
            if (objectLabels == null)
                throw new Exception("Image should be processed before to collect objects map.");

            leftEdge = new List<Point>();
            rightEdge = new List<Point>();

            int xmin = (int)blob.Rectangle.Left;
            int xmax = (int)(xmin + blob.Rectangle.Width - 1);
            int ymin = (int)blob.Rectangle.Top;
            int ymax = (int)(ymin + blob.Rectangle.Height - 1);

            int label = blob.ID;

            // for each line
            for (int y = ymin; y <= ymax; y++)
            {
                // scan from left to right
                int p = y * imageWidth + xmin;
                for (int x = xmin; x <= xmax; x++, p++)
                {
                    if (objectLabels[p] == label)
                    {
                        leftEdge.Add(new Point(x, y));
                        break;
                    }
                }

                // scan from right to left
                p = y * imageWidth + xmax;
                for (int x = xmax; x >= xmin; x--, p--)
                {
                    if (objectLabels[p] == label)
                    {
                        rightEdge.Add(new Point(x, y));
                        break;
                    }
                }
            }
        }
        public List<Point> GetBlobsEdgePoints(Blob blob)
        {
            // check if objects map was collected
            if (objectLabels == null)
                throw new ApplicationException("Image should be processed before to collect objects map.");

            List<Point> edgePoints = new List<Point>();

            int xmin = (int)blob.Rectangle.Left;
            int xmax = (int)(xmin + blob.Rectangle.Width - 1);
            int ymin = (int)blob.Rectangle.Top;
            int ymax = (int)(ymin + blob.Rectangle.Height - 1);

            int label = blob.ID;

            // array of already processed points on left/right edges
            // (index in these arrays represent Y coordinate, but value - X coordinate)
            int[] leftProcessedPoints = new int[(int)blob.Rectangle.Height];
            int[] rightProcessedPoints = new int[(int)blob.Rectangle.Height];

            // for each line
            for (int y = ymin; y <= ymax; y++)
            {
                // scan from left to right
                int p = y * imageWidth + xmin;
                for (int x = xmin; x <= xmax; x++, p++)
                {
                    if (objectLabels[p] == label)
                    {
                        edgePoints.Add(new Point(x, y));
                        leftProcessedPoints[y - ymin] = x;
                        break;
                    }
                }

                // scan from right to left
                p = y * imageWidth + xmax;
                for (int x = xmax; x >= xmin; x--, p--)
                {
                    if (objectLabels[p] == label)
                    {
                        // avoid adding the point we already have
                        if (leftProcessedPoints[y - ymin] != x)
                        {
                            edgePoints.Add(new Point(x, y));
                        }
                        rightProcessedPoints[y - ymin] = x;
                        break;
                    }
                }
            }

            // for each column
            for (int x = xmin; x <= xmax; x++)
            {
                // scan from top to bottom
                int p = ymin * imageWidth + x;
                for (int y = ymin, y0 = 0; y <= ymax; y++, y0++, p += imageWidth)
                {
                    if (objectLabels[p] == label)
                    {
                        // avoid adding the point we already have
                        if ((leftProcessedPoints[y0] != x) &&
                             (rightProcessedPoints[y0] != x))
                        {
                            edgePoints.Add(new Point(x, y));
                        }
                        break;
                    }
                }

                // scan from bottom to top
                p = ymax * imageWidth + x;
                for (int y = ymax, y0 = ymax - ymin; y >= ymin; y--, y0--, p -= imageWidth)
                {
                    if (objectLabels[p] == label)
                    {
                        // avoid adding the point we already have
                        if ((leftProcessedPoints[y0] != x) &&
                             (rightProcessedPoints[y0] != x))
                        {
                            edgePoints.Add(new Point(x, y));
                        }
                        break;
                    }
                }
            }

            return edgePoints;
        }