/// <summary>
        ///   Process the filter on the specified image.
        /// </summary>
        ///
        /// <param name="image">Source image data.</param>
        ///
        protected override void ProcessFilter(UnmanagedImage image)
        {
            // Apply first Gaussian blur
            var image1 = first.Apply(image);

            // Apply second Gaussian blur
            second.ApplyInPlace(image);

            // Subtract the two images
            subtract.UnmanagedOverlayImage = image1;
            subtract.ApplyInPlace(image);
        }
Exemple #2
0
        /// <summary>
        /// Process the filter on the specified image.
        /// </summary>
        ///
        /// <param name="source">Source image data.</param>
        /// <param name="destination">Destination image data.</param>
        /// <param name="rect">Image rectangle for processing by the filter.</param>
        ///
        protected override unsafe void ProcessFilter(UnmanagedImage source, UnmanagedImage destination, Rectangle rect)
        {
            // processing start and stop X,Y positions
            int startX = rect.Left + 1;
            int startY = rect.Top + 1;
            int stopX  = startX + rect.Width - 2;
            int stopY  = startY + rect.Height - 2;

            int width  = rect.Width - 2;
            int height = rect.Height - 2;

            int dstStride = destination.Stride;
            int srcStride = source.Stride;

            int dstOffset = dstStride - rect.Width + 2;
            int srcOffset = srcStride - rect.Width + 2;

            // pixel's value and gradients
            int gx, gy;
            //
            double orientation, toAngle = 180.0 / System.Math.PI;
            float  leftPixel = 0, rightPixel = 0;

            // STEP 1 - blur image
            UnmanagedImage blurredImage = gaussianFilter.Apply(source);

            // orientation array
            byte[] orients = new byte[width * height];
            // gradients array
            float[,] gradients = new float[source.Width, source.Height];
            float maxGradient = float.NegativeInfinity;

            // do the job
            byte *src = (byte *)blurredImage.ImageData.ToPointer( );

            // allign pointer
            src += srcStride * startY + startX;

            // STEP 2 - calculate magnitude and edge orientation
            int p = 0;

            // for each line
            for (int y = startY; y < stopY; y++)
            {
                // for each pixel
                for (int x = startX; x < stopX; x++, src++, p++)
                {
                    gx = src[-srcStride + 1] + src[srcStride + 1]
                         - src[-srcStride - 1] - src[srcStride - 1]
                         + 2 * (src[1] - src[-1]);

                    gy = src[-srcStride - 1] + src[-srcStride + 1]
                         - src[srcStride - 1] - src[srcStride + 1]
                         + 2 * (src[-srcStride] - src[srcStride]);

                    // get gradient value
                    gradients[x, y] = (float)Math.Sqrt(gx * gx + gy * gy);
                    if (gradients[x, y] > maxGradient)
                    {
                        maxGradient = gradients[x, y];
                    }

                    // --- get orientation
                    if (gx == 0)
                    {
                        // can not divide by zero
                        orientation = (gy == 0) ? 0 : 90;
                    }
                    else
                    {
                        double div = (double)gy / gx;

                        // handle angles of the 2nd and 4th quads
                        if (div < 0)
                        {
                            orientation = 180 - System.Math.Atan(-div) * toAngle;
                        }
                        // handle angles of the 1st and 3rd quads
                        else
                        {
                            orientation = System.Math.Atan(div) * toAngle;
                        }

                        // get closest angle from 0, 45, 90, 135 set
                        if (orientation < 22.5)
                        {
                            orientation = 0;
                        }
                        else if (orientation < 67.5)
                        {
                            orientation = 45;
                        }
                        else if (orientation < 112.5)
                        {
                            orientation = 90;
                        }
                        else if (orientation < 157.5)
                        {
                            orientation = 135;
                        }
                        else
                        {
                            orientation = 0;
                        }
                    }

                    // save orientation
                    orients[p] = (byte)orientation;
                }
                src += srcOffset;
            }

            // STEP 3 - suppres non maximums
            byte *dst = (byte *)destination.ImageData.ToPointer( );

            // allign pointer
            dst += dstStride * startY + startX;

            p = 0;

            // for each line
            for (int y = startY; y < stopY; y++)
            {
                // for each pixel
                for (int x = startX; x < stopX; x++, dst++, p++)
                {
                    // get two adjacent pixels
                    switch (orients[p])
                    {
                    case 0:
                        leftPixel  = gradients[x - 1, y];
                        rightPixel = gradients[x + 1, y];
                        break;

                    case 45:
                        leftPixel  = gradients[x - 1, y + 1];
                        rightPixel = gradients[x + 1, y - 1];
                        break;

                    case 90:
                        leftPixel  = gradients[x, y + 1];
                        rightPixel = gradients[x, y - 1];
                        break;

                    case 135:
                        leftPixel  = gradients[x + 1, y + 1];
                        rightPixel = gradients[x - 1, y - 1];
                        break;
                    }
                    // compare current pixels value with adjacent pixels
                    if ((gradients[x, y] < leftPixel) || (gradients[x, y] < rightPixel))
                    {
                        *dst = 0;
                    }
                    else
                    {
                        *dst = (byte)(gradients[x, y] / maxGradient * 255);
                    }
                }
                dst += dstOffset;
            }

            // STEP 4 - hysteresis
            dst = (byte *)destination.ImageData.ToPointer( );
            // allign pointer
            dst += dstStride * startY + startX;

            // for each line
            for (int y = startY; y < stopY; y++)
            {
                // for each pixel
                for (int x = startX; x < stopX; x++, dst++)
                {
                    if (*dst < highThreshold)
                    {
                        if (*dst < lowThreshold)
                        {
                            // non edge
                            *dst = 0;
                        }
                        else
                        {
                            // check 8 neighboring pixels
                            if ((dst[-1] < highThreshold) &&
                                (dst[1] < highThreshold) &&
                                (dst[-dstStride - 1] < highThreshold) &&
                                (dst[-dstStride] < highThreshold) &&
                                (dst[-dstStride + 1] < highThreshold) &&
                                (dst[dstStride - 1] < highThreshold) &&
                                (dst[dstStride] < highThreshold) &&
                                (dst[dstStride + 1] < highThreshold))
                            {
                                *dst = 0;
                            }
                        }
                    }
                }
                dst += dstOffset;
            }

            // STEP 5 - draw black rectangle to remove those pixels, which were not processed
            // (this needs to be done for those cases, when filter is applied "in place" -
            //  source image is modified instead of creating new copy)
            Drawing.Rectangle(destination, rect, Color.Black);

            // release blurred image
            blurredImage.Dispose( );
        }