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

ProcessFilter() protected method

Process the filter on the specified image.
protected ProcessFilter ( UnmanagedImage sourceData, UnmanagedImage destinationData ) : void
sourceData UnmanagedImage Source image data.
destinationData UnmanagedImage Destination image data.
return void
        protected override unsafe void ProcessFilter( UnmanagedImage sourceData, UnmanagedImage destinationData )
        {
            // get source and destination images size
            int srcWidth  = sourceData.Width;
            int srcHeight = sourceData.Height;
            int dstWidth  = destinationData.Width;
            int dstHeight = destinationData.Height;

            int pixelSize = Image.GetPixelFormatSize( sourceData.PixelFormat ) / 8;
            int srcStride = sourceData.Stride;
            int dstStride = destinationData.Stride;

            // find equations of four quadrilateral's edges ( f(x) = k*x + b )
            double kTop,    bTop;
            double kBottom, bBottom;
            double kLeft,   bLeft;
            double kRight,  bRight;

            // top edge
            if ( sourceQuadrilateral[1].X == sourceQuadrilateral[0].X )
            {
                kTop = 0;
                bTop = sourceQuadrilateral[1].X;
            }
            else
            {
                kTop = (double) ( sourceQuadrilateral[1].Y - sourceQuadrilateral[0].Y ) /
                                ( sourceQuadrilateral[1].X - sourceQuadrilateral[0].X );
                bTop = (double) sourceQuadrilateral[0].Y - kTop * sourceQuadrilateral[0].X;
            }

            // bottom edge
            if ( sourceQuadrilateral[2].X == sourceQuadrilateral[3].X )
            {
                kBottom = 0;
                bBottom = sourceQuadrilateral[2].X;
            }
            else
            {
                kBottom = (double) ( sourceQuadrilateral[2].Y - sourceQuadrilateral[3].Y ) /
                                   ( sourceQuadrilateral[2].X - sourceQuadrilateral[3].X );
                bBottom = (double) sourceQuadrilateral[3].Y - kBottom * sourceQuadrilateral[3].X;
            }

            // left edge
            if ( sourceQuadrilateral[3].X == sourceQuadrilateral[0].X )
            {
                kLeft = 0;
                bLeft = sourceQuadrilateral[3].X;
            }
            else
            {
                kLeft = (double) ( sourceQuadrilateral[3].Y - sourceQuadrilateral[0].Y ) /
                                 ( sourceQuadrilateral[3].X - sourceQuadrilateral[0].X );
                bLeft = (double) sourceQuadrilateral[0].Y - kLeft * sourceQuadrilateral[0].X;
            }

            // right edge
            if ( sourceQuadrilateral[2].X == sourceQuadrilateral[1].X )
            {
                kRight = 0;
                bRight = sourceQuadrilateral[2].X;
            }
            else
            {
                kRight = (double) ( sourceQuadrilateral[2].Y - sourceQuadrilateral[1].Y ) /
                                  ( sourceQuadrilateral[2].X - sourceQuadrilateral[1].X );
                bRight = (double) sourceQuadrilateral[1].Y - kRight * sourceQuadrilateral[1].X;
            }

            // some precalculated values
            double leftFactor  = (double) ( sourceQuadrilateral[3].Y - sourceQuadrilateral[0].Y ) / dstHeight;
            double rightFactor = (double) ( sourceQuadrilateral[2].Y - sourceQuadrilateral[1].Y ) / dstHeight;

            int srcY0 = sourceQuadrilateral[0].Y;
            int srcY1 = sourceQuadrilateral[1].Y;

            // do the job
            byte* baseSrc = (byte*) sourceData.ImageData.ToPointer( );
            byte* baseDst = (byte*) destinationData.ImageData.ToPointer( );

            // source width and height decreased by 1
            int ymax = srcHeight - 1;
            int xmax = srcWidth - 1;

            // coordinates of source points
            double  dx1, dy1, dx2, dy2;
            int     sx1, sy1, sx2, sy2;

            // temporary pointers
            byte* p1, p2, p3, p4, p;

            // for each line
            for ( int y = 0; y < dstHeight; y++ )
            {
                byte* dst = baseDst + dstStride * y;

                // find corresponding Y on the left edge of the quadrilateral
                double yHorizLeft = leftFactor * y + srcY0;
                // find corresponding X on the left edge of the quadrilateral
                double xHorizLeft = ( kLeft == 0 ) ? bLeft : ( yHorizLeft - bLeft ) / kLeft;

                // find corresponding Y on the right edge of the quadrilateral
                double yHorizRight = rightFactor * y + srcY1;
                // find corresponding X on the left edge of the quadrilateral
                double xHorizRight = ( kRight == 0 ) ? bRight : ( yHorizRight - bRight ) / kRight;

                // find equation of the line joining points on the left and right edges
                double kHoriz, bHoriz;

                if ( xHorizLeft == xHorizRight )
                {
                    kHoriz = 0;
                    bHoriz = xHorizRight;
                }
                else
                {
                    kHoriz = ( yHorizRight - yHorizLeft ) / ( xHorizRight - xHorizLeft );
                    bHoriz = yHorizLeft - kHoriz * xHorizLeft;
                }

                double horizFactor = ( xHorizRight - xHorizLeft ) / dstWidth;

                if ( !useInterpolation )
                {
                    for ( int x = 0; x < dstWidth; x++ )
                    {
                        double xs = horizFactor * x + xHorizLeft;
                        double ys = kHoriz * xs + bHoriz;

                        if ( ( xs >= 0 ) && ( ys >= 0 ) && ( xs < srcWidth ) && ( ys < srcHeight ) )
                        {
                            // get pointer to the pixel in the source image
                            p = baseSrc + ( (int) ys * srcStride + (int) xs * pixelSize );
                            // copy pixel's values
                            for ( int i = 0; i < pixelSize; i++, dst++, p++ )
                            {
                                *dst = *p;
                            }
                        }
                        else
                        {
                            dst += pixelSize;
                        }
                    }
                }
                else
                {
                    for ( int x = 0; x < dstWidth; x++ )
                    {
                        double xs = horizFactor * x + xHorizLeft;
                        double ys = kHoriz * xs + bHoriz;

                        if ( ( xs >= 0 ) && ( ys >= 0 ) && ( xs < srcWidth ) && ( ys < srcHeight ) )
                        {
                            sx1 = (int) xs;
                            sx2 = ( sx1 == xmax ) ? sx1 : sx1 + 1;
                            dx1 = xs - sx1;
                            dx2 = 1.0 - dx1;

                            sy1 = (int) ys;
                            sy2 = ( sy1 == ymax ) ? sy1 : sy1 + 1;
                            dy1 = ys - sy1;
                            dy2 = 1.0 - dy1;

                            // get four points
                            p1 = p2 = baseSrc + sy1 * srcStride;
                            p1 += sx1 * pixelSize;
                            p2 += sx2 * pixelSize;

                            p3 = p4 = baseSrc + sy2 * srcStride;
                            p3 += sx1 * pixelSize;
                            p4 += sx2 * pixelSize;

                            // interpolate using 4 points
                            for ( int i = 0; i < pixelSize; i++, dst++, p1++, p2++, p3++, p4++ )
                            {
                                *dst = (byte) (
                                    dy2 * ( dx2 * ( *p1 ) + dx1 * ( *p2 ) ) +
                                    dy1 * ( dx2 * ( *p3 ) + dx1 * ( *p4 ) ) );
                            }
                        }
                        else
                        {
                            dst += pixelSize;
                        }
                    }
                }
            }
        }
    }