使用.Net检测灰度图像

发布于 2024-08-14 07:27:12 字数 181 浏览 4 评论 0原文

我正在将文档扫描为 JPG 图像。扫描仪必须将所有页面扫描为彩色或将所有页面扫描为黑白。由于我的许多页面都是彩色的,因此我必须将所有页面扫描为彩色。扫描完成后,我想使用 .Net 检查图像并尝试检测哪些图像是黑白的,以便我可以将这些图像转换为灰度并保存在存储中。

有人知道如何用.Net 检测灰度图像吗?

请告诉我。

I am scanning documents to JPG images. The scanner must scan all pages as color or all pages as black and white. Since many of my pages are color, I must scan all pages as color. After the scanning is complete, I would like to examine the images with .Net and try to detect what images are black and white so that I can convert those images to grayscale and save on storage.

Does anybody know how to detect a grayscale image with .Net?

Please let me know.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

懒的傷心 2024-08-21 07:27:12

如果您找不到这样的库,您可以尝试抓取图像的大量(或全部)像素,并查看它们的 r、g 和 b 值是否在某个阈值内(您可以根据经验设置该阈值) ,或作为一种设置)彼此。如果是,则图像是灰度的。

不过,我肯定会让测试的阈值大于 0...所以我不会测试 r=g,但是 (abs(rg) < e) 其中 e 是你的阈值。这样你就可以降低你的假彩色正数......因为我怀疑你会得到一个不错的数字,除非你的原始图像和扫描技术给出精确灰度。

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.

时光磨忆 2024-08-21 07:27:12

测试颜色的简单算法:在嵌套的 for 循环(宽度和高度)中逐像素遍历图像,并测试像素的 RGB 值是否相等。如果不是,则图像具有颜色信息。如果您一直遍历所有像素而没有遇到这种情况,那么您将获得灰度图像。

使用更复杂的算法进行修订:

在本文的第一版中,我提出了一种简单的算法,该算法假设如果每个像素的 RGB 值相等,则像素为灰度。因此 0,0,0 或 128,128,128 或 230,230,230 的 RGB 都将测试为灰色,而 123,90,78 则不会。简单的。

这是测试与灰色的差异的代码片段。这两种方法是更复杂过程的一小部分,但应该提供足够的原始代码来帮助解决原始问题。

/// <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);
}

A simple algorithm to test for color: Walk the image pixel by pixel in a nested for loop (width and height) and test to see if the pixel's RGB values are equal. If they are not then the image has color info. If you make it all the way through all the pixels without encountering this condition, then you have a gray scale image.

Revision with a more complex algorithm:

In the first rev of this post i proposed a simple algorithm that assumes that pixels are gray scale if each pixel's RGB are values are equal. So RGBs of 0,0,0 or 128,128,128 or 230,230,230 would all test as gray while 123,90,78 would not. Simple.

Here's a snippet of code that tests for a variance from gray. The two methods are a small subsection of a more complex process but ought to provide enough raw code to help with the original question.

/// <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);
}
决绝 2024-08-21 07:27:12

更快的版本。使用阈值 8 进行测试。很适合我的

用途:

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;
}

您有更快的吗?

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?

埖埖迣鎅 2024-08-21 07:27:12

由于 JPEG 支持元数据,因此您应该首先检查您的扫描仪软件是否在保存的图像上放置了一些特殊数据,以及您是否可以依赖该信息。

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.

若言繁花未落 2024-08-21 07:27:12

我在 python 部分发布的答案可能会有所帮助。例如,您在网络上发现的人们认为灰度的图像通常不具有相同的 R、G、B 值。您需要一些方差计算和某种采样过程,这样您就不必检查一百万个像素。 Paul 给出的解决方案基于最大差异,因此扫描仪中的单个红色像素伪影可以将灰度图像变成非灰度图像。我发布的解决方案在 13,000 张图像上获得了 99.1% 的准确率和 92.5% 的召回率。

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.

梦晓ヶ微光ヅ倾城 2024-08-21 07:27:12

我认为这种方法应该需要最少的代码,它已经在 jpeg 上进行了测试。下面的bImage是一个字节数组。

 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");
 }

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");
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文