Converting an Image (well, Bitmap really) to Grayscale
First thought – convert the picture to greyscale and increase the contrast to help any kind of edge-detection work. Some searching found me Bob Powell's handy guide to increasing contrast and converting to grayscale via ColorMatrix. With Wikipedia’s explanation of “naive” matrix multiplication in hand I cobbled up a converter that takes a bitmap and returns a grayscaled version.
public class GreyscaleBitmap
{
// Magic conversion to greyscale matrix
static float[][] _grayScaleMatrix = new float[][] {
new float[] {.3f, .3f, .3f, 0, 0},
new float[] {.59f, .59f, .59f, 0, 0},
new float[] {.11f, .11f, .11f, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {0, 0, 0, 0, 1}
};
// Doubles contrast
static float[][] _increaseContrast = new float[][] {
new float[] {2, 0, 0, 0, 0},
new float[] {0, 2, 0, 0, 0},
new float[] {0, 0, 2, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {0, 0, 0, 0, 1}
};
// Dumb and slow.
static float[][] MatrixMult2(float[][] first, float[][] second)
{
float[][] result = new float[5][];
for (int i = 0; i < 5; i++)
result[i] = new float[5];
for (int j = 0; j < 5; j++)
for (int k = 0; k < 5; k++)
for (int i = 0; i < 5; i++)
result[i][j] += first[i][k] * second[k][j];
return result;
}
// Only bother making one of these
static ColorMatrix _matrix = new ColorMatrix(MatrixMult2(_grayScaleMatrix, _increaseContrast));
// Cache this as well?
static ImageAttributes GetAttributes()
{
ImageAttributes result = new ImageAttributes();
result.SetColorMatrix(_matrix);
return result;
}
public static Bitmap Convert(Bitmap bmp)
{
Bitmap newBitmap = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(newBitmap))
{
Rectangle r = new Rectangle(0, 0, newBitmap.Width, newBitmap.Height);
g.DrawImage(bmp, r, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, GetAttributes());
}
return newBitmap;
}
}
Now, in another world the output image format would be 16bpp grayscale directly, instead of being re-encoded in 24bpp RGB. As a result, my eventual scanner will have to convert back from RGB to a grayscale value again. Not a great start, but hey – conversion to grayscale!