private unsafe void ProcessWithoutChecksParallel(UnmanagedImage source, UnmanagedImage destination, Rectangle rect)
{
int startX = rect.Left;
int startY = rect.Top;
int stopX = rect.Right;
int stopY = rect.Bottom;
int pixelSize = System.Drawing.Image.GetPixelFormatSize(source.PixelFormat) / 8;
int kernelHalf = kernelSize / 2;
int bytesInKernelRow = kernelSize * pixelSize;
int srcStride = source.Stride;
int dstStride = destination.Stride;
// offset of the first kernel's pixel
int srcKernelFistPixelOffset = kernelHalf * (srcStride + pixelSize);
// offset to move to the next kernel's pixel after processing one kernel's row
int srcKernelOffset = srcStride - bytesInKernelRow;
byte* srcBase = (byte*)source.ImageData.ToPointer();
byte* dstBase = (byte*)destination.ImageData.ToPointer();
// align pointers to the left most pixel in the first row
srcBase += startX * pixelSize;
dstBase += startX * pixelSize;
if (pixelSize > 1)
{
Parallel.For(startY, stopY, delegate(int y)
{
byte* src = srcBase + y * srcStride;
byte* dst = dstBase + y * dstStride;
byte srcR, srcG, srcB;
byte srcR0, srcG0, srcB0;
byte* srcPixel;
int tx, ty;
double sCoefR, sCoefG, sCoefB, sMembR, sMembG, sMembB, coefR, coefG, coefB;
for (int x = startX; x < stopX; x++, src += pixelSize, dst += pixelSize)
{
// lower right corner - to start processing from that point
srcPixel = src + srcKernelFistPixelOffset;
sCoefR = 0;
sCoefG = 0;
sCoefB = 0;
sMembR = 0;
sMembG = 0;
sMembB = 0;
srcR0 = src[RGB.R];
srcG0 = src[RGB.G];
srcB0 = src[RGB.B];
// move from lower right to upper left corner
ty = kernelSize;
while (ty != 0)
{
ty--;
tx = kernelSize;
while (tx != 0)
{
tx--;
srcR = srcPixel[RGB.R];
srcG = srcPixel[RGB.G];
srcB = srcPixel[RGB.B];
coefR = spatialFunc[tx, ty] * colorFunc[srcR, srcR0];
coefG = spatialFunc[tx, ty] * colorFunc[srcG, srcG0];
coefB = spatialFunc[tx, ty] * colorFunc[srcB, srcB0];
sCoefR += coefR;
sCoefG += coefG;
sCoefB += coefB;
sMembR += coefR * srcR;
sMembG += coefG * srcG;
sMembB += coefB * srcB;
srcPixel -= pixelSize;
}
srcPixel -= srcKernelOffset;
}
dst[RGB.R] = (byte)(sMembR / sCoefR);
dst[RGB.G] = (byte)(sMembG / sCoefG);
dst[RGB.B] = (byte)(sMembB / sCoefB);
}
});
}
else
{
// 8bpp grayscale images
Parallel.For(startY, stopY, delegate(int y)
{
byte* src = srcBase + y * srcStride;
byte* dst = dstBase + y * dstStride;
byte srcC;
byte srcC0;
byte* srcPixel;
double sCoefC, sMembC, coefC;
int tx, ty;
for (int x = startX; x < stopX; x++, src++, dst++)
{
// lower right corner - to start processing from that point
srcPixel = src + srcKernelFistPixelOffset;
sCoefC = 0;
sMembC = 0;
srcC0 = *src;
// move from lower right to upper left corner
ty = kernelSize;
while (ty != 0)
{
ty--;
tx = kernelSize;
while (tx != 0)
{
tx--;
srcC = *(srcPixel);
coefC = spatialFunc[tx, ty] * colorFunc[srcC, srcC0];
sCoefC += coefC;
sMembC += coefC * srcC;
srcPixel -= pixelSize;
}
srcPixel -= srcKernelOffset;
}
*dst = (byte)(sMembC / sCoefC);
}
});
}
}