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

后端 未结 3 1198
Happy的楠姐
Happy的楠姐 2020-12-09 23:37

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 pos

3条回答
  •  青春惊慌失措
    2020-12-10 00:07

    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 }
    

提交回复
热议问题