// Process both images transforming source image into quadrilateral in destination image
private unsafe void ProcessFilter(UnmanagedImage dstImage, UnmanagedImage srcImage)
{
// get source and destination images size
int srcWidth = srcImage.Width;
int srcHeight = srcImage.Height;
int dstWidth = dstImage.Width;
int dstHeight = dstImage.Height;
int pixelSize = Image.GetPixelFormatSize(srcImage.PixelFormat) / 8;
int srcStride = srcImage.Stride;
int dstStride = dstImage.Stride;
// get bounding rectangle of the quadrilateral
IntPoint minXY, maxXY;
PointsCloud.GetBoundingRectangle(destinationQuadrilateral, out minXY, out maxXY);
// make sure the rectangle is inside of destination image
if ((maxXY.X < 0) || (maxXY.Y < 0) || (minXY.X >= dstWidth) || (minXY.Y >= dstHeight))
{
return; // nothing to do, since quadrilateral is completely outside
}
// correct rectangle if required
if (minXY.X < 0)
{
minXY.X = 0;
}
if (minXY.Y < 0)
{
minXY.Y = 0;
}
if (maxXY.X >= dstWidth)
{
maxXY.X = dstWidth - 1;
}
if (maxXY.Y >= dstHeight)
{
maxXY.Y = dstHeight - 1;
}
int startX = minXY.X;
int startY = minXY.Y;
int stopX = maxXY.X + 1;
int stopY = maxXY.Y + 1;
int offset = dstStride - (stopX - startX) * pixelSize;
// calculate tranformation matrix
List <IntPoint> srcRect = new List <IntPoint>();
srcRect.Add(new IntPoint(0, 0));
srcRect.Add(new IntPoint(srcWidth - 1, 0));
srcRect.Add(new IntPoint(srcWidth - 1, srcHeight - 1));
srcRect.Add(new IntPoint(0, srcHeight - 1));
double[,] matrix = QuadTransformationCalcs.MapQuadToQuad(destinationQuadrilateral, srcRect);
// do the job
byte *ptr = (byte *)dstImage.ImageData.ToPointer();
byte *baseSrc = (byte *)srcImage.ImageData.ToPointer();
// allign pointer to the first pixel to process
ptr += (startY * dstStride + startX * pixelSize);
if (!useInterpolation)
{
byte *p;
// for each row
for (int y = startY; y < stopY; y++)
{
// for each pixel
for (int x = startX; x < stopX; x++)
{
double factor = matrix[2, 0] * x + matrix[2, 1] * y + matrix[2, 2];
double srcX = (matrix[0, 0] * x + matrix[0, 1] * y + matrix[0, 2]) / factor;
double srcY = (matrix[1, 0] * x + matrix[1, 1] * y + matrix[1, 2]) / factor;
if ((srcX >= 0) && (srcY >= 0) && (srcX < srcWidth) && (srcY < srcHeight))
{
// get pointer to the pixel in the source image
p = baseSrc + (int)srcY * srcStride + (int)srcX * pixelSize;
// copy pixel's values
for (int i = 0; i < pixelSize; i++, ptr++, p++)
{
*ptr = *p;
}
}
else
{
// skip the pixel
ptr += pixelSize;
}
}
ptr += offset;
}
}
else
{
int srcWidthM1 = srcWidth - 1;
int srcHeightM1 = srcHeight - 1;
// coordinates of source points
double dx1, dy1, dx2, dy2;
int sx1, sy1, sx2, sy2;
// temporary pointers
byte *p1, p2, p3, p4;
// for each row
for (int y = startY; y < stopY; y++)
{
// for each pixel
for (int x = startX; x < stopX; x++)
{
double factor = matrix[2, 0] * x + matrix[2, 1] * y + matrix[2, 2];
double srcX = (matrix[0, 0] * x + matrix[0, 1] * y + matrix[0, 2]) / factor;
double srcY = (matrix[1, 0] * x + matrix[1, 1] * y + matrix[1, 2]) / factor;
if ((srcX >= 0) && (srcY >= 0) && (srcX < srcWidth) && (srcY < srcHeight))
{
sx1 = (int)srcX;
sx2 = (sx1 == srcWidthM1) ? sx1 : sx1 + 1;
dx1 = srcX - sx1;
dx2 = 1.0 - dx1;
sy1 = (int)srcY;
sy2 = (sy1 == srcHeightM1) ? sy1 : sy1 + 1;
dy1 = srcY - 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++, ptr++, p1++, p2++, p3++, p4++)
{
*ptr = (byte)(
dy2 * (dx2 * (*p1) + dx1 * (*p2)) +
dy1 * (dx2 * (*p3) + dx1 * (*p4)));
}
}
else
{
// skip the pixel
ptr += pixelSize;
}
}
ptr += offset;
}
}
}