Ejemplo n.º 1
0
        /// <summary>
        /// Construct integral image from source grayscale image.
        /// </summary>
        ///
        /// <param name="image">Source unmanaged image.</param>
        ///
        /// <returns>Returns integral image.</returns>
        ///
        /// <exception cref="UnsupportedImageFormatException">The source image has incorrect pixel format.</exception>
        ///
        public static IntegralImage FromBitmap(UnmanagedImage image)
        {
            // check image format
            if (image.PixelFormat != PixelFormat.Format8bppIndexed)
            {
                throw new ArgumentException("Source image can be grayscale (8 bpp indexed) image only.");
            }

            // get source image size
            int width  = image.Width;
            int height = image.Height;
            int offset = image.Stride - width;

            // create integral image
            var im = new IntegralImage(width, height);

            uint[][] matrix = im.matrix;

            // do the job
            unsafe
            {
                byte *src = (byte *)image.ImageData.ToPointer();

                // for each line
                for (int y = 1; y <= height; y++)
                {
                    uint rowSum = 0;

                    // for each pixel
                    for (int x = 1; x <= width; x++, src++)
                    {
                        image.CheckBounds(src);

                        rowSum += *src;

                        matrix[y][x] = rowSum + matrix[y - 1][x];
                    }
                    src += offset;
                }
            }

            return(im);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Process image looking for corners.
        /// </summary>
        ///
        /// <param name="image">Unmanaged source image to process.</param>
        ///
        /// <returns>Returns array of found corners (X-Y coordinates).</returns>
        ///
        /// <exception cref="UnsupportedImageFormatException">The source image has incorrect pixel format.</exception>
        ///
        public List <IntPoint> ProcessImage(UnmanagedImage image)
        {
            // check image format
            if (
                (image.PixelFormat != PixelFormat.Format8bppIndexed) &&
                (image.PixelFormat != PixelFormat.Format24bppRgb) &&
                (image.PixelFormat != PixelFormat.Format32bppRgb) &&
                (image.PixelFormat != PixelFormat.Format32bppArgb)
                )
            {
                throw new UnsupportedImageFormatException("Unsupported pixel format of the source image.");
            }

            // get source image size
            int width     = image.Width;
            int height    = image.Height;
            int stride    = image.Stride;
            int pixelSize = Bitmap.GetPixelFormatSize(image.PixelFormat) / 8;
            // window radius
            int windowRadius = windowSize / 2;

            // offset
            int offset = stride - windowSize * pixelSize;

            // create moravec cornerness map
            int[,] moravecMap = new int[height, width];

            // do the job
            unsafe
            {
                byte *ptr = (byte *)image.ImageData.ToPointer();

                // for each row
                for (int y = windowRadius, maxY = height - windowRadius; y < maxY; y++)
                {
                    // for each pixel
                    for (int x = windowRadius, maxX = width - windowRadius; x < maxX; x++)
                    {
                        int minSum = int.MaxValue;

                        // go through 8 possible shifting directions
                        for (int k = 0; k < 8; k++)
                        {
                            // calculate center of shifted window
                            int sy = y + yDelta[k];
                            int sx = x + xDelta[k];

                            // check if shifted window is within the image
                            if (
                                (sy < windowRadius) || (sy >= maxY) ||
                                (sx < windowRadius) || (sx >= maxX)
                                )
                            {
                                // skip this shifted window
                                continue;
                            }

                            int sum = 0;

                            byte *ptr1 = ptr + (y - windowRadius) * stride + (x - windowRadius) * pixelSize;
                            byte *ptr2 = ptr + (sy - windowRadius) * stride + (sx - windowRadius) * pixelSize;

                            // for each windows' rows
                            for (int i = 0; i < windowSize; i++)
                            {
                                // for each windows' pixels
                                for (int j = 0, maxJ = windowSize * pixelSize; j < maxJ; j++, ptr1++, ptr2++)
                                {
                                    image.CheckBounds(ptr1);
                                    image.CheckBounds(ptr2);

                                    int dif = *ptr1 - *ptr2;
                                    sum += dif * dif;
                                }
                                ptr1 += offset;
                                ptr2 += offset;
                            }

                            // check if the sum is mimimal
                            if (sum < minSum)
                            {
                                minSum = sum;
                            }
                        }

                        // threshold the minimum sum
                        if (minSum < threshold)
                        {
                            minSum = 0;
                        }

                        moravecMap[y, x] = minSum;
                    }
                }
            }

            // collect interesting points - only those points, which are local maximums
            List <IntPoint> cornersList = new List <IntPoint>();

            // for each row
            for (int y = windowRadius, maxY = height - windowRadius; y < maxY; y++)
            {
                // for each pixel
                for (int x = windowRadius, maxX = width - windowRadius; x < maxX; x++)
                {
                    int currentValue = moravecMap[y, x];

                    // for each windows' rows
                    for (int i = -windowRadius; (currentValue != 0) && (i <= windowRadius); i++)
                    {
                        // for each windows' pixels
                        for (int j = -windowRadius; j <= windowRadius; j++)
                        {
                            if (moravecMap[y + i, x + j] > currentValue)
                            {
                                currentValue = 0;
                                break;
                            }
                        }
                    }

                    // check if this point is really interesting
                    if (currentValue != 0)
                    {
                        cornersList.Add(new IntPoint(x, y));
                    }
                }
            }

            return(cornersList);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Actual objects map building.
        /// </summary>
        ///
        /// <param name="image">Unmanaged image to process.</param>
        ///
        /// <remarks>The method supports 8 bpp indexed grayscale images and 24/32 bpp color images.</remarks>
        ///
        /// <exception cref="UnsupportedImageFormatException">Unsupported pixel format of the source image.</exception>
        /// <exception cref="InvalidImagePropertiesException">Cannot process images that are one pixel wide. Rotate the image
        /// or use <see cref="RecursiveBlobCounter"/>.</exception>
        ///
        protected override void BuildObjectsMap(UnmanagedImage image)
        {
            int stride = image.Stride;

            // check pixel format
            if ((image.PixelFormat != PixelFormat.Format8bppIndexed) &&
                (image.PixelFormat != PixelFormat.Format24bppRgb) &&
                (image.PixelFormat != PixelFormat.Format32bppRgb) &&
                (image.PixelFormat != PixelFormat.Format32bppArgb) &&
                (image.PixelFormat != PixelFormat.Format32bppPArgb))
            {
                throw new UnsupportedImageFormatException("Unsupported pixel format of the source image.");
            }

            // we don't want one pixel width images
            if (ImageWidth == 1)
            {
                throw new InvalidImagePropertiesException("BlobCounter cannot process images that are one pixel wide. Rotate the image or use RecursiveBlobCounter.");
            }

            int imageWidthM1 = ImageWidth - 1;

            // allocate labels array
            ObjectLabels = new int[ImageWidth * ImageHeight];

            // initial labels count
            int labelsCount = 0;

            // create map
            int maxObjects = ((ImageWidth / 2) + 1) * ((ImageHeight / 2) + 1) + 1;

            int[] map = new int[maxObjects];

            // initially map all labels to themself
            for (int i = 0; i < maxObjects; i++)
            {
                map[i] = i;
            }

            // do the job
            unsafe
            {
                byte *src = (byte *)image.ImageData.ToPointer();
                int   p   = 0;

                if (image.PixelFormat == PixelFormat.Format8bppIndexed)
                {
                    int offset = stride - ImageWidth;

                    image.CheckBounds(src);

                    // 1 - for pixels of the first row
                    if (*src > backgroundThresholdG)
                    {
                        ObjectLabels[p] = ++labelsCount;
                    }
                    ++src;
                    ++p;

                    // process the rest of the first row
                    for (int x = 1; x < ImageWidth; x++, src++, p++)
                    {
                        image.CheckBounds(src);

                        // check if we need to label current pixel
                        if (*src > backgroundThresholdG)
                        {
                            image.CheckBounds(src - 1);

                            // check if the previous pixel already was labeled
                            if (src[-1] > backgroundThresholdG)
                            {
                                // label current pixel, as the previous
                                ObjectLabels[p] = ObjectLabels[p - 1];
                            }
                            else
                            {
                                // create new label
                                ObjectLabels[p] = ++labelsCount;
                            }
                        }
                    }
                    src += offset;

                    // 2 - for other rows
                    // for each row
                    for (int y = 1; y < ImageHeight; y++)
                    {
                        // for the first pixel of the row, we need to check
                        // only upper and upper-right pixels

                        image.CheckBounds(src);

                        if (*src > backgroundThresholdG)
                        {
                            image.CheckBounds(src - stride);
                            image.CheckBounds(src + 1 - stride);

                            // check surrounding pixels
                            if (src[-stride] > backgroundThresholdG)
                            {
                                // label current pixel, as the above
                                ObjectLabels[p] = ObjectLabels[p - ImageWidth];
                            }
                            else if (src[1 - stride] > backgroundThresholdG)
                            {
                                // label current pixel, as the above right
                                ObjectLabels[p] = ObjectLabels[p + 1 - ImageWidth];
                            }
                            else
                            {
                                // create new label
                                ObjectLabels[p] = ++labelsCount;
                            }
                        }
                        ++src;
                        ++p;

                        // check left pixel and three upper pixels for the rest of pixels
                        for (int x = 1; x < imageWidthM1; x++, src++, p++)
                        {
                            image.CheckBounds(src);

                            if (*src > backgroundThresholdG)
                            {
                                image.CheckBounds(src - 1);
                                image.CheckBounds(src - 1 - stride);
                                image.CheckBounds(src - stride);
                                image.CheckBounds(src + 1 - stride);

                                // check surrounding pixels
                                if (src[-1] > backgroundThresholdG)
                                {
                                    // label current pixel, as the left
                                    ObjectLabels[p] = ObjectLabels[p - 1];
                                }
                                else if (src[-1 - stride] > backgroundThresholdG)
                                {
                                    // label current pixel, as the above left
                                    ObjectLabels[p] = ObjectLabels[p - 1 - ImageWidth];
                                }
                                else if (src[-stride] > backgroundThresholdG)
                                {
                                    // label current pixel, as the above
                                    ObjectLabels[p] = ObjectLabels[p - ImageWidth];
                                }

                                if (src[1 - stride] > backgroundThresholdG)
                                {
                                    if (ObjectLabels[p] == 0)
                                    {
                                        // label current pixel, as the above right
                                        ObjectLabels[p] = ObjectLabels[p + 1 - ImageWidth];
                                    }
                                    else
                                    {
                                        int l1 = ObjectLabels[p];
                                        int l2 = ObjectLabels[p + 1 - ImageWidth];

                                        if ((l1 != l2) && (map[l1] != map[l2]))
                                        {
                                            // merge
                                            if (map[l1] == l1)
                                            {
                                                // map left value to the right
                                                map[l1] = map[l2];
                                            }
                                            else if (map[l2] == l2)
                                            {
                                                // map right value to the left
                                                map[l2] = map[l1];
                                            }
                                            else
                                            {
                                                // both values already mapped
                                                map[map[l1]] = map[l2];
                                                map[l1]      = map[l2];
                                            }

                                            // reindex
                                            for (int i = 1; i <= labelsCount; i++)
                                            {
                                                if (map[i] != i)
                                                {
                                                    // reindex
                                                    int j = map[i];
                                                    while (j != map[j])
                                                    {
                                                        j = map[j];
                                                    }
                                                    map[i] = j;
                                                }
                                            }
                                        }
                                    }
                                }

                                // label the object if it is not yet
                                if (ObjectLabels[p] == 0)
                                {
                                    // create new label
                                    ObjectLabels[p] = ++labelsCount;
                                }
                            }
                        }

                        // for the last pixel of the row, we need to check
                        // only upper and upper-left pixels
                        image.CheckBounds(src);

                        if (*src > backgroundThresholdG)
                        {
                            image.CheckBounds(src - 1);
                            image.CheckBounds(src - 1 - stride);
                            image.CheckBounds(src - stride);

                            // check surrounding pixels
                            if (src[-1] > backgroundThresholdG)
                            {
                                // label current pixel, as the left
                                ObjectLabels[p] = ObjectLabels[p - 1];
                            }
                            else if (src[-1 - stride] > backgroundThresholdG)
                            {
                                // label current pixel, as the above left
                                ObjectLabels[p] = ObjectLabels[p - 1 - ImageWidth];
                            }
                            else if (src[-stride] > backgroundThresholdG)
                            {
                                // label current pixel, as the above
                                ObjectLabels[p] = ObjectLabels[p - ImageWidth];
                            }
                            else
                            {
                                // create new label
                                ObjectLabels[p] = ++labelsCount;
                            }
                        }
                        ++src;
                        ++p;

                        src += offset;
                    }
                }
                else
                {
                    // color images
                    int pixelSize = Bitmap.GetPixelFormatSize(image.PixelFormat) / 8;
                    int offset    = stride - ImageWidth * pixelSize;

                    int strideM1 = stride - pixelSize;
                    int strideP1 = stride + pixelSize;

                    // 1 - for pixels of the first row
                    if ((src[RGB.R] | src[RGB.G] | src[RGB.B]) != 0)
                    {
                        ObjectLabels[p] = ++labelsCount;
                    }
                    src += pixelSize;
                    ++p;

                    // process the rest of the first row
                    for (int x = 1; x < ImageWidth; x++, src += pixelSize, p++)
                    {
                        // check if we need to label current pixel
                        if ((src[RGB.R] > backgroundThresholdR) ||
                            (src[RGB.G] > backgroundThresholdG) ||
                            (src[RGB.B] > backgroundThresholdB))
                        {
                            // check if the previous pixel already was labeled
                            if ((src[RGB.R - pixelSize] > backgroundThresholdR) ||
                                (src[RGB.G - pixelSize] > backgroundThresholdG) ||
                                (src[RGB.B - pixelSize] > backgroundThresholdB))
                            {
                                // label current pixel, as the previous
                                ObjectLabels[p] = ObjectLabels[p - 1];
                            }
                            else
                            {
                                // create new label
                                ObjectLabels[p] = ++labelsCount;
                            }
                        }
                    }
                    src += offset;

                    // 2 - for other rows
                    // for each row
                    for (int y = 1; y < ImageHeight; y++)
                    {
                        // for the first pixel of the row, we need to check
                        // only upper and upper-right pixels
                        if ((src[RGB.R] > backgroundThresholdR) ||
                            (src[RGB.G] > backgroundThresholdG) ||
                            (src[RGB.B] > backgroundThresholdB))
                        {
                            // check surrounding pixels
                            if ((src[RGB.R - stride] > backgroundThresholdR) ||
                                (src[RGB.G - stride] > backgroundThresholdG) ||
                                (src[RGB.B - stride] > backgroundThresholdB))
                            {
                                // label current pixel, as the above
                                ObjectLabels[p] = ObjectLabels[p - ImageWidth];
                            }
                            else if ((src[RGB.R - strideM1] > backgroundThresholdR) ||
                                     (src[RGB.G - strideM1] > backgroundThresholdG) ||
                                     (src[RGB.B - strideM1] > backgroundThresholdB))
                            {
                                // label current pixel, as the above right
                                ObjectLabels[p] = ObjectLabels[p + 1 - ImageWidth];
                            }
                            else
                            {
                                // create new label
                                ObjectLabels[p] = ++labelsCount;
                            }
                        }
                        src += pixelSize;
                        ++p;

                        // check left pixel and three upper pixels for the rest of pixels
                        for (int x = 1; x < ImageWidth - 1; x++, src += pixelSize, p++)
                        {
                            if ((src[RGB.R] > backgroundThresholdR) ||
                                (src[RGB.G] > backgroundThresholdG) ||
                                (src[RGB.B] > backgroundThresholdB))
                            {
                                // check surrounding pixels
                                if ((src[RGB.R - pixelSize] > backgroundThresholdR) ||
                                    (src[RGB.G - pixelSize] > backgroundThresholdG) ||
                                    (src[RGB.B - pixelSize] > backgroundThresholdB))
                                {
                                    // label current pixel, as the left
                                    ObjectLabels[p] = ObjectLabels[p - 1];
                                }
                                else if ((src[RGB.R - strideP1] > backgroundThresholdR) ||
                                         (src[RGB.G - strideP1] > backgroundThresholdG) ||
                                         (src[RGB.B - strideP1] > backgroundThresholdB))
                                {
                                    // label current pixel, as the above left
                                    ObjectLabels[p] = ObjectLabels[p - 1 - ImageWidth];
                                }
                                else if ((src[RGB.R - stride] > backgroundThresholdR) ||
                                         (src[RGB.G - stride] > backgroundThresholdG) ||
                                         (src[RGB.B - stride] > backgroundThresholdB))
                                {
                                    // label current pixel, as the above
                                    ObjectLabels[p] = ObjectLabels[p - ImageWidth];
                                }

                                if ((src[RGB.R - strideM1] > backgroundThresholdR) ||
                                    (src[RGB.G - strideM1] > backgroundThresholdG) ||
                                    (src[RGB.B - strideM1] > backgroundThresholdB))
                                {
                                    if (ObjectLabels[p] == 0)
                                    {
                                        // label current pixel, as the above right
                                        ObjectLabels[p] = ObjectLabels[p + 1 - ImageWidth];
                                    }
                                    else
                                    {
                                        int l1 = ObjectLabels[p];
                                        int l2 = ObjectLabels[p + 1 - ImageWidth];

                                        if ((l1 != l2) && (map[l1] != map[l2]))
                                        {
                                            // merge
                                            if (map[l1] == l1)
                                            {
                                                // map left value to the right
                                                map[l1] = map[l2];
                                            }
                                            else if (map[l2] == l2)
                                            {
                                                // map right value to the left
                                                map[l2] = map[l1];
                                            }
                                            else
                                            {
                                                // both values already mapped
                                                map[map[l1]] = map[l2];
                                                map[l1]      = map[l2];
                                            }

                                            // reindex
                                            for (int i = 1; i <= labelsCount; i++)
                                            {
                                                if (map[i] != i)
                                                {
                                                    // reindex
                                                    int j = map[i];
                                                    while (j != map[j])
                                                    {
                                                        j = map[j];
                                                    }
                                                    map[i] = j;
                                                }
                                            }
                                        }
                                    }
                                }

                                // label the object if it is not yet
                                if (ObjectLabels[p] == 0)
                                {
                                    // create new label
                                    ObjectLabels[p] = ++labelsCount;
                                }
                            }
                        }

                        // for the last pixel of the row, we need to check
                        // only upper and upper-left pixels
                        if ((src[RGB.R] > backgroundThresholdR) ||
                            (src[RGB.G] > backgroundThresholdG) ||
                            (src[RGB.B] > backgroundThresholdB))
                        {
                            // check surrounding pixels
                            if ((src[RGB.R - pixelSize] > backgroundThresholdR) ||
                                (src[RGB.G - pixelSize] > backgroundThresholdG) ||
                                (src[RGB.B - pixelSize] > backgroundThresholdB))
                            {
                                // label current pixel, as the left
                                ObjectLabels[p] = ObjectLabels[p - 1];
                            }
                            else if ((src[RGB.R - strideP1] > backgroundThresholdR) ||
                                     (src[RGB.G - strideP1] > backgroundThresholdG) ||
                                     (src[RGB.B - strideP1] > backgroundThresholdB))
                            {
                                // label current pixel, as the above left
                                ObjectLabels[p] = ObjectLabels[p - 1 - ImageWidth];
                            }
                            else if ((src[RGB.R - stride] > backgroundThresholdR) ||
                                     (src[RGB.G - stride] > backgroundThresholdG) ||
                                     (src[RGB.B - stride] > backgroundThresholdB))
                            {
                                // label current pixel, as the above
                                ObjectLabels[p] = ObjectLabels[p - ImageWidth];
                            }
                            else
                            {
                                // create new label
                                ObjectLabels[p] = ++labelsCount;
                            }
                        }
                        src += pixelSize;
                        ++p;

                        src += offset;
                    }
                }
            }

            // allocate remapping array
            int[] reMap = new int[map.Length];

            // count objects and prepare remapping array
            ObjectsCount = 0;
            for (int i = 1; i <= labelsCount; i++)
            {
                if (map[i] == i)
                {
                    // increase objects count
                    reMap[i] = ++ObjectsCount;
                }
            }
            // second pass to complete remapping
            for (int i = 1; i <= labelsCount; i++)
            {
                if (map[i] != i)
                {
                    reMap[i] = reMap[map[i]];
                }
            }

            // repair object labels
            for (int i = 0, n = ObjectLabels.Length; i < n; i++)
            {
                ObjectLabels[i] = reMap[ObjectLabels[i]];
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        ///   Constructs a new Integral image from an unmanaged image.
        /// </summary>
        ///
        /// <param name="image">The source image from where the integral image should be computed.</param>
        /// <param name="channel">The image channel to consider in the computations. Default is 0.</param>
        /// <param name="computeTilted"><c>True</c> to compute the tilted version of the integral image,
        ///   <c>false</c> otherwise. Default is false.</param>
        ///
        /// <returns>
        ///   The <see cref="IntegralImage2"/> representation of
        ///   the <paramref name="image">source image</paramref>.</returns>
        ///
        public static IntegralImage2 FromBitmap(UnmanagedImage image, int channel, bool computeTilted)
        {
            // check image format
            if (!(image.PixelFormat == PixelFormat.Format8bppIndexed ||
                  image.PixelFormat == PixelFormat.Format24bppRgb ||
                  image.PixelFormat == PixelFormat.Format32bppArgb ||
                  image.PixelFormat == PixelFormat.Format32bppRgb))
            {
                throw new UnsupportedImageFormatException("Only grayscale, 24 and 32 bpp RGB images are supported.");
            }

            int pixelSize = System.Drawing.Image.GetPixelFormatSize(image.PixelFormat) / 8;

            // get source image size
            int width  = image.Width;
            int height = image.Height;
            int stride = image.Stride;
            int offset = stride - width * pixelSize;

            // create integral image
            IntegralImage2 im   = new IntegralImage2(width, height, computeTilted);
            long *         nSum = im.nSum;
            long *         sSum = im.sSum;
            long *         tSum = im.tSum;

            int nWidth = im.nWidth;
            int tWidth = im.tWidth;

            if (image.PixelFormat == PixelFormat.Format8bppIndexed && channel != 0)
            {
                throw new ArgumentException("Only the first channel is available for 8 bpp images.", "channel");
            }

            byte *srcStart = (byte *)image.ImageData.ToPointer() + channel;

            // do the job
            byte *src = srcStart;

            // for each line
            for (int y = 1; y <= height; y++)
            {
                int yy = nWidth * (y);
                int y1 = nWidth * (y - 1);

                // for each pixel
                for (int x = 1; x <= width; x++, src += pixelSize)
                {
                    image.CheckBounds(src);

                    long p1 = *src;
                    long p2 = p1 * p1;

                    int r = yy + (x);
                    int a = yy + (x - 1);
                    int b = y1 + (x);
                    int c = y1 + (x - 1);

                    nSum[r] = p1 + nSum[a] + nSum[b] - nSum[c];
                    sSum[r] = p2 + sSum[a] + sSum[b] - sSum[c];
                }
                src += offset;
            }


            if (computeTilted)
            {
                src = srcStart;

                // Left-to-right, top-to-bottom pass
                for (int y = 1; y <= height; y++, src += offset)
                {
                    int yy = tWidth * (y);
                    int y1 = tWidth * (y - 1);

                    for (int x = 2; x < width + 2; x++, src += pixelSize)
                    {
                        image.CheckBounds(src);

                        int a = y1 + (x - 1);
                        int b = yy + (x - 1);
                        int c = y1 + (x - 2);
                        int r = yy + (x);

                        tSum[r] = *src + tSum[a] + tSum[b] - tSum[c];
                    }
                }

                {
                    int yy = tWidth * (height);
                    int y1 = tWidth * (height + 1);

                    for (int x = 2; x < width + 2; x++, src += pixelSize)
                    {
                        int a = yy + (x - 1);
                        int c = yy + (x - 2);
                        int b = y1 + (x - 1);
                        int r = y1 + (x);

                        tSum[r] = tSum[a] + tSum[b] - tSum[c];
                    }
                }


                // Right-to-left, bottom-to-top pass
                for (int y = height; y >= 0; y--)
                {
                    int yy = tWidth * (y);
                    int y1 = tWidth * (y + 1);

                    for (int x = width + 1; x >= 1; x--)
                    {
                        int r = yy + (x);
                        int b = y1 + (x - 1);

                        tSum[r] += tSum[b];
                    }
                }

                for (int y = height + 1; y >= 0; y--)
                {
                    int yy = tWidth * (y);

                    for (int x = width + 1; x >= 2; x--)
                    {
                        int r = yy + (x);
                        int b = yy + (x - 2);

                        tSum[r] -= tSum[b];
                    }
                }
            }


            return(im);
        }
Ejemplo n.º 5
0
        /// <summary>
        ///   Extracts the contour from a single object in a grayscale image.
        /// </summary>
        ///
        /// <param name="image">A grayscale image.</param>
        /// <returns>A list of <see cref="IntPoint"/>s defining a contour.</returns>
        ///
        public List <IntPoint> FindContour(UnmanagedImage image)
        {
            CheckPixelFormat(image.PixelFormat);

            int width  = image.Width;
            int height = image.Height;
            int stride = image.Stride;

            List <IntPoint> contour = new List <IntPoint>();

            unsafe
            {
                byte *src = (byte *)image.ImageData.ToPointer();

                byte *start = null;

                IntPoint prevPosition = new IntPoint();

                // 1. Find the lowest point in the image

                // The lowest point is searched first by lowest X, then lowest Y, to use
                // the same ordering of AForge.NET's GrahamConvexHull. Unfortunately, this
                // means we have to search our image by inspecting columns rather than rows.

                bool found = false;

                byte *col = src;
                for (int x = 0; x < width && !found; x++, col++)
                {
                    byte *row = col;
                    for (int y = 0; y < height && !found; y++, row += stride)
                    {
                        image.CheckBounds(row);

                        if (*row > Threshold)
                        {
                            start        = row;
                            prevPosition = new IntPoint(x, y);
                            contour.Add(prevPosition);
                            found = true;
                        }
                    }
                }

                if (contour.Count == 0)
                {
                    // Empty image
                    return(contour);
                }


                // 2. Beginning on the first point, starting from left
                //    neighbor and going into counter-clockwise direction,
                //    find a neighbor pixel which is black.

                int[] windowOffset =
                {
                    +1,          // 0: Right
                    -stride + 1, // 1: Top-Right
                    -stride,     // 2: Top
                    -stride - 1, // 3: Top-Left
                    -1,          // 4: Left
                    +stride - 1, // 5: Bottom-Left
                    +stride,     // 6: Bottom
                    +stride + 1, // 7: Bottom-Right
                };

                int   direction = 4; // 4: Left
                byte *current   = start;
                byte *previous  = null;


                do // Search until we find a dead end (or the starting pixel)
                {
                    found = false;

                    // Search in the neighborhood window
                    for (int i = 0; i < windowOffset.Length; i++)
                    {
                        // Find the next candidate neighbor point
                        IntPoint next = prevPosition + positionOffset[direction];

                        // Check if it is inside the blob area
                        if (next.X < 0 || next.X >= width ||
                            next.Y < 0 || next.Y >= height)
                        {
                            // It isn't. Change direction and continue.
                            direction = (direction + 1) % windowOffset.Length;
                            continue;
                        }

                        // It is inside. Then find the next candidate neighbor pixel
                        byte *neighbor = unchecked (current + windowOffset[direction]);

                        image.CheckBounds(neighbor); // Make sure we are in the image

                        // Check if it is a colored pixel
                        if (*neighbor <= Threshold)
                        {
                            // It isn't. Change direction and continue.
                            direction = (direction + 1) % windowOffset.Length;
                            continue;
                        }

                        // Check if it is a previously found pixel
                        if (neighbor == previous || neighbor == start)
                        {
                            // We found a dead end.
                            found = false; break;
                        }

                        // If we reached until here, we have
                        //  found a neighboring black pixel.
                        found = true; break;
                    }

                    if (found)
                    {
                        // Navigate to neighbor pixel
                        previous = current;
                        current  = unchecked (current + windowOffset[direction]);

                        // Add to the contour
                        prevPosition += positionOffset[direction];
                        contour.Add(prevPosition);

                        // Continue counter-clockwise search
                        //  from the most promising direction
                        direction = nextDirection[direction];
                    }
                } while (found);
            }


            return(contour);
        }
Ejemplo n.º 6
0
        public void Update(UnmanagedImage image, int channel)
        {
            int width     = image.Width;
            int height    = image.Height;
            int offset    = image.Offset;
            int pixelSize = System.Drawing.Image.GetPixelFormatSize(image.PixelFormat) / 8;

            // create integral image
            long *nSum = this.nSum;
            long *sSum = this.sSum;
            long *tSum = this.tSum;

            size_t nWidth = this.nWidth;
            size_t tWidth = this.tWidth;

            if (image.PixelFormat == PixelFormat.Format8bppIndexed && channel != 0)
            {
                throw new ArgumentException("Only the first channel is available for 8 bpp images.", "channel");
            }

            byte *srcStart = (byte *)image.ImageData.ToPointer() + channel;

            // do the job
            byte *src = srcStart;

            //var t1 = Task.Factory.StartNew(() =>
            //{
            // for each line
            for (int y = 1; y <= height; y++, src += offset)
            {
                size_t yy = nWidth * (y);
                size_t y1 = nWidth * (y - 1);

                // for each pixel
                for (int x = 1; x <= width; x++, src += pixelSize)
                {
                    image.CheckBounds(src);

                    long p1 = *src;
                    long p2 = p1 * p1;

                    size_t r = yy + (x);
                    size_t a = yy + (x - 1);
                    size_t b = y1 + (x);
                    size_t c = y1 + (x - 1);

                    nSum[r] = p1 + nSum[a] + nSum[b] - nSum[c];
                    sSum[r] = p2 + sSum[a] + sSum[b] - sSum[c];
                }
            }
            //});

            //var t2 = Task.Factory.StartNew(() =>
            //{
            if (this.tSumImage != null)
            {
                src = srcStart;

                // Left-to-right, top-to-bottom pass
                for (int y = 1; y <= height; y++, src += offset)
                {
                    size_t yy = tWidth * (y);
                    size_t y1 = tWidth * (y - 1);

                    for (int x = 2; x < width + 2; x++, src += pixelSize)
                    {
                        image.CheckBounds(src);

                        size_t a = y1 + (x - 1);
                        size_t b = yy + (x - 1);
                        size_t c = y1 + (x - 2);
                        size_t r = yy + (x);

                        tSum[r] = *src + tSum[a] + tSum[b] - tSum[c];
                    }
                }

                {
                    size_t yy = tWidth * (height);
                    size_t y1 = tWidth * (height + 1);

                    for (int x = 2; x < width + 2; x++, src += pixelSize)
                    {
                        size_t a = yy + (x - 1);
                        size_t c = yy + (x - 2);
                        size_t b = y1 + (x - 1);
                        size_t r = y1 + (x);

                        tSum[r] = tSum[a] + tSum[b] - tSum[c];
                    }
                }


                // Right-to-left, bottom-to-top pass
                for (int y = height; y >= 0; y--)
                {
                    size_t yy = tWidth * (y);
                    size_t y1 = tWidth * (y + 1);

                    for (int x = width + 1; x >= 1; x--)
                    {
                        size_t r = yy + (x);
                        size_t b = y1 + (x - 1);

                        tSum[r] += tSum[b];
                    }
                }

                for (int y = height + 1; y >= 0; y--)
                {
                    size_t yy = tWidth * (y);

                    for (int x = width + 1; x >= 2; x--)
                    {
                        size_t r = yy + (x);
                        size_t b = yy + (x - 2);

                        tSum[r] -= tSum[b];
                    }
                }
            }
            //});

            //Task.WaitAll(t1, t2);
        }