【问题标题】:Check If Image Is Colored Or Not检查图像是否有颜色
【发布时间】:2018-09-19 04:07:15
【问题描述】:

我正在尝试确定图像是否是彩色的。在this StackOverflow 问题上,有一个回复说我应该检查ImagePixelFormat 枚举。不幸的是,我的回答不是很清楚。检查image.PixelFormat 是否与PixelFormat.Format16bppGrayScale 不同以认为它是彩色图像是否安全?枚举的其他值呢? MSDN 文档不是很清楚...

【问题讨论】:

  • 你想检查它是否支持颜色,或者它是否包含颜色?它可以是 Format32bppArgb 并且仍然只包含黑色、白色和灰色。
  • @YoryeNathan:我想知道它是否包含颜色。
  • 那是另一回事。您希望它适用于每种 PixelFormat 吗?
  • @YoryeNathan:我不敢说实话。问题是用户可以将图像上传到站点,然后我需要检查该图像是否是彩色的。因此,我需要做不同的事情......
  • 用户上传任何类型的图像,然后呢?有一个文件对话框等?没有扩展过滤器?

标签: c# .net image gdi+ pixelformat


【解决方案1】:

您可以通过避免使用 Color.FromArgb 并迭代字节而不是整数来改进这一点,但我认为这对您来说更具可读性,并且作为一种方法更容易理解。

总体思路是将图像绘制成已知格式(32bpp ARGB)的位图, 然后检查该位图是否包含任何颜色。

锁定位图的位允许您使用不安全的代码比使用 GetPixel 快很多倍地迭代它的颜色数据。

如果一个像素的 alpha 为 0,那么它显然是 GrayScale,因为 alpha 0 意味着它完全不透明。除此之外 - 如果 R = G = B,则为灰色(如果它们 = 255,则为黑色)。

private static unsafe bool IsGrayScale(Image image)
{
    using (var bmp = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb))
    {
        using (var g = Graphics.FromImage(bmp))
        {
            g.DrawImage(image, 0, 0);
        }

        var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);

        var pt = (int*)data.Scan0;
        var res = true;

        for (var i = 0; i < data.Height * data.Width; i++)
        {
            var color = Color.FromArgb(pt[i]);

            if (color.A != 0 && (color.R != color.G || color.G != color.B))
            {
                res = false;
                break;
            }
        }

        bmp.UnlockBits(data);

        return res;
    }
}

【讨论】:

  • 很高兴我能帮上忙。只要确保我没有与 alpha(0 或 255)混淆。除此之外它应该很顺利:)
【解决方案2】:
    private bool isGrayScale(Bitmap processedBitmap)
    { 
        bool res = true;
        unsafe
        {
            System.Drawing.Imaging.BitmapData bitmapData = processedBitmap.LockBits(new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, processedBitmap.PixelFormat);
            int bytesPerPixel = System.Drawing.Bitmap.GetPixelFormatSize(processedBitmap.PixelFormat) / 8;
            int heightInPixels = bitmapData.Height;
            int widthInBytes = bitmapData.Width * bytesPerPixel;
            byte* PtrFirstPixel = (byte*)bitmapData.Scan0;
            Parallel.For(0, heightInPixels, y =>
            {
                byte* currentLine = PtrFirstPixel + (y * bitmapData.Stride);
                for (int x = 0; x < widthInBytes; x = x + bytesPerPixel)
                {
                    int b = currentLine[x];
                    int g = currentLine[x + 1];
                    int r = currentLine[x + 2];
                    if (b != g || r != g)
                    {
                        res = false;
                        break;
                    }
                }
            });
            processedBitmap.UnlockBits(bitmapData);
        }
        return res;
    }

【讨论】:

【解决方案3】:

SimpleVar 的答案大部分是正确的:当源图像具有索引颜色格式时,该代码无法正确处理。

要解决这个问题,只需将外部 using 块替换为:

using (var bmp = new Bitmap(image)) {

并完全删除内部using,因为不再需要Graphics 对象。无论原始图像的像素格式如何,这都会以非索引格式创建图像的完美副本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-26
    相关资源
    最近更新 更多