Вопрос

Я сканирую документы на изображения JPG. Сканер должен сканировать все страницы как цвет или все страницы как черно -белые. Поскольку многие из моих страниц цветной, я должен сканировать все страницы как цвет. После завершения сканирования я хотел бы изучить изображения с .NET и попытаться обнаружить, какие изображения черно -белые, чтобы я мог преобразовать эти изображения в серогойс и сохранить на хранении.

Кто -нибудь знает, как обнаружить изображение серого с .NET?

Пожалуйста, дай мне знать.

Это было полезно?

Решение

Простой алгоритм для тестирования на цвет: пройдите пиксель с изображением пикселем в вложенном цикле (ширина и высота) и тестируйте, чтобы увидеть, равны ли значения RGB пикселя. Если это не так, то изображение имеет информацию о цвете. Если вы делаете это все через все пиксели, не столкнувшись с этим условием, то у вас есть изображение серого масштаба.

Пересмотр с более сложным алгоритмом:

В первом обороте этого поста я предложил простой алгоритм, который предполагает, что пиксели представляют собой серой шкалу, если RGB каждого пикселя равны значениям. Таким образом, RGBS в размере 0,0,0 или 128 128 128 или 230 230 230 будет проверяться как серый, а 123,90,78 - нет. Простой.

Вот фрагмент кода, который проверяет дисперсию от Grey. Эти два метода представляют собой небольшой подраздел более сложного процесса, но должен обеспечить достаточно необработанного кода, чтобы помочь с исходным вопросом.

/// <summary>
/// This function accepts a bitmap and then performs a delta
/// comparison on all the pixels to find the highest delta
/// color in the image. This calculation only works for images
/// which have a field of similar color and some grayscale or
/// near-grayscale outlines. The result ought to be that the
/// calculated color is a sample of the "field". From this we
/// can infer which color in the image actualy represents a
/// contiguous field in which we're interested.
/// See the documentation of GetRgbDelta for more information.
/// </summary>
/// <param name="bmp">A bitmap for sampling</param>
/// <returns>The highest delta color</returns>
public static Color CalculateColorKey(Bitmap bmp)
{
    Color keyColor = Color.Empty;
    int highestRgbDelta = 0;

    for (int x = 0; x < bmp.Width; x++)
    {
        for (int y = 0; y < bmp.Height; y++)
        {
            if (GetRgbDelta(bmp.GetPixel(x, y)) <= highestRgbDelta) continue;

            highestRgbDelta = GetRgbDelta(bmp.GetPixel(x, y));
            keyColor = bmp.GetPixel(x, y);
        }
    }

    return keyColor;
}

/// <summary>
/// Utility method that encapsulates the RGB Delta calculation:
/// delta = abs(R-G) + abs(G-B) + abs(B-R) 
/// So, between the color RGB(50,100,50) and RGB(128,128,128)
/// The first would be the higher delta with a value of 100 as compared
/// to the secong color which, being grayscale, would have a delta of 0
/// </summary>
/// <param name="color">The color for which to calculate the delta</param>
/// <returns>An integer in the range 0 to 510 indicating the difference
/// in the RGB values that comprise the color</returns>
private static int GetRgbDelta(Color color)
{
    return
        Math.Abs(color.R - color.G) +
        Math.Abs(color.G - color.B) +
        Math.Abs(color.B - color.R);
}

Другие советы

If you can't find a library for this, you could try grabbing a large number (or all) of the pixels for an image and see if their r, g, and b values are within a certain threshold (which you might set empirically, or have as a setting) of one another. If they are, the image is grayscale.

I would definitely make the threshold for a test a bit larger than 0, though...so I wouldn't test r=g, for example, but (abs(r-g) < e) where e is your threshold. That way you can keep your false color positives down...as I suspect you'll otherwise get a decent number, unless your original image and scanning techniques give precisely grayscale.

A faster versión. Test with a threshold of 8. Work well for my

Use:

bool grayScale;
Bitmap bmp = new Bitmap(strPath + "\\temp.png");
grayScale = TestGrayScale(bmp, 8);
if (grayScale)
   MessageBox.Show("Grayscale image");


/// <summary>Test a image is in grayscale</summary>
/// <param name="bmp">The bmp to test</param>
/// <param name="threshold">The threshold for maximun color difference</param>
/// <returns>True if is grayscale. False if is color image</returns>
public bool TestGrayScale(Bitmap bmp, int threshold)
{
    Color pixelColor = Color.Empty;
    int rgbDelta;

    for (int x = 0; x < bmp.Width; x++)
    {
        for (int y = 0; y < bmp.Height; y++)
        {
            pixelColor = bmp.GetPixel(x, y);
            rgbDelta = Math.Abs(pixelColor.R - pixelColor.G) + Math.Abs(pixelColor.G - pixelColor.B) + Math.Abs(pixelColor.B - pixelColor.R);
            if (rgbDelta > threshold) return false;
        }
    }
    return true;
}

Do you have a faster one?

As JPEG have support for metadata, you should first to check if your scanner software place some special data on saved images and if you can rely on that information.

The answer I posted in the python section might be helpful. Images you find e.g. on the web that a human would consider grayscale often do not have identical R,G,B values. You need some calculation of the variance and some kind of sampling process so you don't have to check a million pixels. The solution Paul gave is based on the max difference so a single red pixel artefact from a scanner could turn a grayscale image into non-grayscale. The solution I posted got 99.1% precision and 92.5% recall on 13,000 images.

I think that this approach should require the least code, it's been tested on jpegs. bImage below is a byte array.

 MemoryStream ms = new MemoryStream(bImage);
 System.Drawing.Image returnImage = System.Drawing.Image.FromStream(ms);
 if (returnImage.Palette.Flags == 2)
 {
      System.Diagnostics.Debug.WriteLine("Image is greyscale");
 }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top