Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine the background color of document when there are 3 options, using c# or imagemagick

i am currently developing an application that has to process scanned forms. One of the tasks of my application is to determine which kind of form is scanned. There are 3 possible types of forms with a unique background color to identify each kind. The 3 colors that are possible are red/pink, green and blue. The problem i am having is, that my attempts fail to distinguish between the green and blue forms. Here are links to the green and blue sample files:

http://dl.dropbox.com/u/686228/Image0037.JPG

http://dl.dropbox.com/u/686228/Image0038.JPG

I am using C# .net Application and ImageMagick for some tasks i need to perform.

Currently i am getting color reduced histogram of my scanned form and try to determine which colors are in the form. But my app can't rely distinguish the green and blue ones.

Any advise or maybe a smarter approach would be gladly appreciated.

Thanks,

Erik

like image 845
Erik Reisig Avatar asked Dec 16 '22 13:12

Erik Reisig


1 Answers

I found this rather interesting and dug into it a little deeper.

The code to get the average color of a bitmap found at How to calculate the average rgb color values of a bitmap had problems like some invalid casts and red/blue channels swapped. Here is a fixed version:

private System.Drawing.Color CalculateAverageColor(Bitmap bm)
{
    int width = bm.Width;
    int height = bm.Height;
    int red = 0;
    int green = 0;
    int blue = 0;
    int minDiversion = 15; // drop pixels that do not differ by at least minDiversion between color values (white, gray or black)
    int dropped = 0; // keep track of dropped pixels
    long[] totals = new long[] { 0, 0, 0 };
    int bppModifier = bm.PixelFormat == System.Drawing.Imaging.PixelFormat.Format24bppRgb ? 3 : 4; // cutting corners, will fail on anything else but 32 and 24 bit images

    BitmapData srcData = bm.LockBits(new System.Drawing.Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadOnly, bm.PixelFormat);
    int stride = srcData.Stride;
    IntPtr Scan0 = srcData.Scan0;

    unsafe
    {
        byte* p = (byte*)(void*)Scan0;

        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                int idx = (y * stride) + x * bppModifier;
                red = p[idx + 2];
                green = p[idx + 1];
                blue = p[idx];
                if (Math.Abs(red - green) > minDiversion || Math.Abs(red - blue) > minDiversion || Math.Abs(green - blue) > minDiversion)
                {
                    totals[2] += red;
                    totals[1] += green;
                    totals[0] += blue;
                }
                else
                {
                    dropped++;
                }
            }
        }
    }

    int count = width * height - dropped;
    int avgR = (int)(totals[2] / count);
    int avgG = (int)(totals[1] / count);
    int avgB = (int)(totals[0] / count);

    return System.Drawing.Color.FromArgb(avgR, avgG, avgB);
}

Running this function on your input images, however, returned some indistinguishable grayish color for both of them, as already anticipated by Will A in the comments, which is why i'm dropping any colors from the calculation that do not have a difference of at least 15 between R, G and B.

The interesting thing is that the supposedly blue prescription scan averages equal values for G and B (R: 214, G: 237, B: 237). However the green prescription scan resulted in a big difference (18) between the values for G and B (R: 202, G: 232, B: 214) so that might be what you should be looking into. Ex:

if (color.G - color.B > 15) { form.Type = FormTypes.GreenForm }
like image 54
Till Avatar answered Jan 31 '23 01:01

Till