将图像转换为灰度

Posted

技术标签:

【中文标题】将图像转换为灰度【英文标题】:Convert an image to grayscale 【发布时间】:2011-01-16 23:29:09 【问题描述】:

有没有办法将图像转换为每像素 16 位的灰度格式,而不是将 r、g 和 b 分量中的每一个都设置为亮度。我目前有一个来自文件的 bmp。

Bitmap c = new Bitmap("filename");

我想要一个位图 d,即 c 的灰度版本。我确实看到了一个包含 System.Drawing.Imaging.PixelFormat 的构造函数,但我不明白如何使用它。我是图像处理和相关 C# 库的新手,但对 C# 本身有一定的经验。

我们将不胜感激任何帮助、参考在线资源、提示或建议。

编辑:d 是 c 的灰度版本。

【问题讨论】:

【参考方案1】:

"我想要一个Bitmap d,也就是灰度。 我确实看到了一个建设者,其中包括 System.Drawing.Imaging.PixelFormat, 但我不明白如何使用 那个。”

这里是如何做到这一点

Bitmap grayScaleBP = new 
         System.Drawing.Bitmap(2, 2, System.Drawing.Imaging.PixelFormat.Format16bppGrayScale);

编辑:转换为灰度

             Bitmap c = new Bitmap("fromFile");
             Bitmap d;
             int x, y;

             // Loop through the images pixels to reset color.
             for (x = 0; x < c.Width; x++)
             
                 for (y = 0; y < c.Height; y++)
                 
                     Color pixelColor = c.GetPixel(x, y);
                     Color newColor = Color.FromArgb(pixelColor.R, 0, 0);
                     c.SetPixel(x, y, newColor); // Now greyscale
                 
             
            d = c;   // d is grayscale version of c  

来自switchonthecode 的更快版本点击链接进行全面分析:

public static Bitmap MakeGrayscale3(Bitmap original)

   //create a blank bitmap the same size as original
   Bitmap newBitmap = new Bitmap(original.Width, original.Height);

   //get a graphics object from the new image
   using(Graphics g = Graphics.FromImage(newBitmap))

       //create the grayscale ColorMatrix
       ColorMatrix colorMatrix = new ColorMatrix(
          new float[][] 
          
             new float[] .3f, .3f, .3f, 0, 0,
             new float[] .59f, .59f, .59f, 0, 0,
             new float[] .11f, .11f, .11f, 0, 0,
             new float[] 0, 0, 0, 1, 0,
             new float[] 0, 0, 0, 0, 1
          );

       //create some image attributes
       using(ImageAttributes attributes = new ImageAttributes())

           //set the color matrix attribute
           attributes.SetColorMatrix(colorMatrix);

           //draw the original image on the new image
           //using the grayscale color matrix
           g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),
                       0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);
       
   
   return newBitmap;

【讨论】:

对不起,我应该在我的问题中说明我想要原始位图的灰度版本,我已经编辑了帖子以反映这一点。 这种方法(逐个像素太慢)在这里查看这篇文章:switchonthecode.com/tutorials/… 如何更改此方法以仅考虑 RGB 值而不考虑透明度?谢谢 我进行了第一次编辑,所有的白色都变成了红色,它仍然是真正的 24 位颜色...我将代码更改为使用绿色和蓝色,结果图像似乎之后和原来的一样。 看来包含原始文章的博客不再可用。矩阵的链接或解释?【参考方案2】:
Bitmap d = new Bitmap(c.Width, c.Height);

for (int i = 0; i < c.Width; i++)

    for (int x = 0; x < c.Height; x++)
    
        Color oc = c.GetPixel(i, x);
        int grayScale = (int)((oc.R * 0.3) + (oc.G * 0.59) + (oc.B * 0.11));
        Color nc = Color.FromArgb(oc.A, grayScale, grayScale, grayScale);
        d.SetPixel(i, x, nc);
    

这样它还保留了 Alpha 通道。 享受吧。

【讨论】:

我知道这是一个旧答案,但您能否详细说明您在 R、G、B 值上相乘的常数?我看到它总结为“1.0”,但有什么解释原因吗? @lukegravitt,谢谢! :) 现在,在我自己使用它之后,我必须补充一点,将它用于小的禁用图标或在任何必须注意差异的情况下都是一个坏主意。灰度结果非常接近颜色一......很难区分。 这个解决方案似乎很慢。第一个“for 循环”应该越过高度,第二个循环(内部循环)应该越过宽度(cols)。图像在磁盘空间中逐行存储。当您从一行迭代到另一行时,您会从一个磁盘空间“跳”到另一个磁盘空间。在宽度上迭代时,您只需转到光盘上的下一个值。你可以看看opencv主题link你总是看到你应该在行(外部)和cols(内部循环)中进行迭代。 这些循环变量名到处都是……“x”实际上是y坐标,整幅图像是逐列处理的,因为高度循环在宽度循环内。 【参考方案3】:

ToolStripRenderer 类中有一个静态方法,名为CreateDisabledImage。 它的用法很简单:

Bitmap c = new Bitmap("filename");
Image d = ToolStripRenderer.CreateDisabledImage(c);

它使用的矩阵与接受的答案中的矩阵略有不同,并将其乘以透明度值 0.7,因此效果与灰度略有不同,但如果您只想让图像变灰,它是最简单最好的解决方案。

【讨论】:

天哪,谢谢你。这与 WinForms 中禁用控件中的图像外观相匹配,从而使所有内容看起来一致。 图片有蓝色的触感。看起来不太好。【参考方案4】:

下面的代码是最简单的解决方案:

Bitmap bt = new Bitmap("imageFilePath");

for (int y = 0; y < bt.Height; y++)

    for (int x = 0; x < bt.Width; x++)
    
        Color c = bt.GetPixel(x, y);

        int r = c.R;
        int g = c.G;
        int b = c.B;
        int avg = (r + g + b) / 3;
        bt.SetPixel(x, y, Color.FromArgb(avg,avg,avg));
       


bt.Save("d:\\out.bmp");

【讨论】:

【参考方案5】:

以上示例均未创建 8 位 (8bpp) 位图图像。有些软件,比如图像处理,只支持8bpp。不幸的是,MS .NET 库没有解决方案。 PixelFormat.Format8bppIndexed 格式看起来很有希望,但经过多次尝试后我无法让它工作。

要创建真正的 8 位位图文件,您需要创建 proper headers。最终,我找到了用于创建 8 位位图 (BMP) 文件的Grayscale library 解决方案。代码很简单:

Image image = Image.FromFile("c:/path/to/image.jpg");
GrayBMP_File.CreateGrayBitmapFile(image, "c:/path/to/8bpp/image.bmp");

这个项目的代码远非漂亮,但它可以工作,有一个易于修复的小问题。作者将图像分辨率硬编码为 10x10。图像处理程序不喜欢这样。修复方法是打开 GrayBMP_File.cs(是的,我知道的时髦的文件命名)并用下面的代码替换第 50 行和第 51 行。该示例将分辨率设置为 200x200,但您应该将其更改为正确的数字。

int resX = 200;
int resY = 200;
// horizontal resolution
Copy_to_Index(DIB_header, BitConverter.GetBytes(resX * 100), 24);
// vertical resolution 
Copy_to_Index(DIB_header, BitConverter.GetBytes(resY * 100), 28);

【讨论】:

我想对其进行测试并投票,但现在时间紧迫。不过感谢您的回答。 8bpp 的诀窍是您需要编辑支持图像的原始内部数组。您可以通过调用image.LockBits() 然后使用Marshal.Copy 复制输入/输出数据来获得它。谷歌它以获得完整的过程。请注意图像的步幅(从数据中读取的一行)通常比实际宽度长,因为它四舍五入到最接近的 4 个字节的倍数。【参考方案6】:

这里总结几点: 有一些逐像素的选项,虽然很简单,但速度并不快。

@Luis 的评论链接到:(存档)https://web.archive.org/web/20110827032809/http://www.switchonthecode.com/tutorials/csharp-tutorial-convert-a-color-image-to-grayscale 非常棒。

他遍历了三个不同的选项,并包括了每个选项的时间安排。

【讨论】:

上面链接中的第三个例子效率超高,直接解决了我的问题 @RichardEverett 确实如此。网络存档来救援!固定。

以上是关于将图像转换为灰度的主要内容,如果未能解决你的问题,请参考以下文章

将灰度图像转换为 rgb 图像并在 matlab 中将其替换为 imread()

将图像转换为灰度

Matlab图像处理彩色图像转换为灰度图像(初学必看)

对于IOS,如何使用vImage将ARGB图像转换为灰度图像

转换语音就像将彩色图像转换为灰度?

Python如何将RGB图像转换为Pytho灰度图像?