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!