protected override unsafe void ProcessFilter(UnmanagedImage image, Rectangle rect)
{
if ((channelImage == null) && (unmanagedChannelImage == null))
throw new InvalidOperationException("Channel image was not specified.");
int pixelSize = Image.GetPixelFormatSize(image.PixelFormat) / 8;
int width = image.Width;
int height = image.Height;
int startX = rect.Left;
int startY = rect.Top;
int stopX = startX + rect.Width;
int stopY = startY + rect.Height;
int offset = image.Stride - rect.Width * pixelSize;
BitmapData chData = null;
// pointer to channel's data
byte* ch;
// channel's image stride
int chStride = 0;
// check channel's image type
if (channelImage != null)
{
// check channel's image dimension
if ((width != channelImage.Width) || (height != channelImage.Height))
throw new InvalidImagePropertiesException("Channel image size does not match source image size.");
// lock channel image
chData = channelImage.LockBits(
new Rectangle(0, 0, width, height),
ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed);
ch = (byte*)chData.Scan0.ToPointer();
chStride = chData.Stride;
}
else
{
// check channel's image dimension
if ((width != unmanagedChannelImage.Width) || (height != unmanagedChannelImage.Height))
throw new InvalidImagePropertiesException("Channel image size does not match source image size.");
ch = (byte*)unmanagedChannelImage.ImageData;
chStride = unmanagedChannelImage.Stride;
}
int offsetCh = chStride - rect.Width;
RGB rgb = new RGB();
YCbCr ycbcr = new YCbCr();
// do the job
byte* dst = (byte*)image.ImageData.ToPointer();
// allign pointer to the first pixel to process
dst += (startY * image.Stride + startX * pixelSize);
ch += (startY * chStride + startX);
// for each line
for (int y = startY; y < stopY; y++)
{
// for each pixel
for (int x = startX; x < stopX; x++, dst += pixelSize, ch++)
{
rgb.Red = dst[RGB.R];
rgb.Green = dst[RGB.G];
rgb.Blue = dst[RGB.B];
// convert to YCbCr
Accord.Imaging.YCbCr.FromRGB(rgb, ycbcr);
switch (channel)
{
case YCbCr.YIndex:
ycbcr.Y = (float)*ch / 255;
break;
case YCbCr.CbIndex:
ycbcr.Cb = (float)*ch / 255 - 0.5f;
break;
case YCbCr.CrIndex:
ycbcr.Cr = (float)*ch / 255 - 0.5f;
break;
}
// convert back to RGB
Accord.Imaging.YCbCr.ToRGB(ycbcr, rgb);
dst[RGB.R] = rgb.Red;
dst[RGB.G] = rgb.Green;
dst[RGB.B] = rgb.Blue;
}
dst += offset;
ch += offsetCh;
}
if (chData != null)
{
// unlock
channelImage.UnlockBits(chData);
}
}
}