Accord.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 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;
                        }
                    }
                }
            }
        }
    }