AForge.Imaging.Filters.CannyEdgeDetector.ProcessFilter C# (CSharp) Method

ProcessFilter() protected method

Process the filter on the specified image.
protected ProcessFilter ( UnmanagedImage source, UnmanagedImage destination, Rectangle rect ) : void
source UnmanagedImage Source image data.
destination UnmanagedImage Destination image data.
rect System.Drawing.Rectangle Image rectangle for processing by the filter.
return void
        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( );
        }
    }