1

我想在代码中按需将 32 位 RGBA 图像对象(最初是 32 位 PNG)转换为其 32 位灰度对应物。

我已经在这里阅读了其他几个问题,以及许多在线文章。我试过用 ColorMatrix 来做,但它似乎不能很好地处理 alpha。完全不透明灰度的像素完美。任何部分透明的像素似乎都不能很好地转换,因为这些像素中仍然存在色彩。引人注目就足够了。

我使用的 ColorMatrix 如下:

new System.Drawing.Imaging.ColorMatrix(new float[][]{
                    new float[] {0.299f, 0.299f, 0.299f, 0, 0},
                    new float[] {0.587f, 0.587f, 0.587f, 0, 0},
                    new float[] {0.114f, 0.114f, 0.114f, 0, 0},
                    new float[] {     0,      0,      0, 1, 0},
                    new float[] {     0,      0,      0, 0, 1}
                    });

正如我所读到的,这是一个非常标准的 NTSC 加权矩阵。然后我将它与 一起使用Graphics.DrawImage,但正如我所说,部分透明的像素仍然是彩色的。我应该指出这是通过PictureBox白色背景上的 WinForms 显示 Image 对象。这可能只是 PictureBox 绘制图像和处理透明部分的方式吗?背景颜色不会影响它(颜色的色调肯定来自原始图像),但也许 PictureBox 没有正确重绘透明像素?

我见过一些使用 FormatConvertedBitmap 和 OpacityMask 的方法。我没有尝试过,主要是因为我真的不想导入 PresentationCore.dll(更不用说这意味着它在 .NET 2.0 受限的应用程序中不起作用)。当然,基本的 System.Drawing.* 东西可以完成这个简单的程序吗?或不?

4

3 回答 3

5

您是否有机会使用 ColorMatrix 将图像绘制到自身上?这当然行不通(因为如果你在绿色像素上画一些半透明灰色的东西,一些绿色会透出来)。您需要将其绘制到仅包含透明像素的新空位图上。

于 2010-06-16T14:22:36.020 回答
4

感谢danbystrom的闲散好奇心,我确实是在原作之上重新绘制。对于任何有兴趣的人,这是我使用的更正方法:

using System.Drawing;
using System.Drawing.Imaging;

public Image ConvertToGrayscale(Image image)
{
    Image grayscaleImage = new Bitmap(image.Width, image.Height, image.PixelFormat);

    // Create the ImageAttributes object and apply the ColorMatrix
    ImageAttributes attributes = new System.Drawing.Imaging.ImageAttributes();
    ColorMatrix grayscaleMatrix = new ColorMatrix(new float[][]{
        new float[] {0.299f, 0.299f, 0.299f, 0, 0},
        new float[] {0.587f, 0.587f, 0.587f, 0, 0},
        new float[] {0.114f, 0.114f, 0.114f, 0, 0},
        new float[] {     0,      0,      0, 1, 0},
        new float[] {     0,      0,      0, 0, 1}
        });
    attributes.SetColorMatrix(grayscaleMatrix);

    // Use a new Graphics object from the new image.
    using (Graphics g = Graphics.FromImage(grayscaleImage))
    {
        // Draw the original image using the ImageAttributes created above.
        g.DrawImage(image,
                    new Rectangle(0, 0, grayscaleImage.Width, grayscaleImage.Height),
                    0, 0, grayscaleImage.Width, grayscaleImage.Height,
                    GraphicsUnit.Pixel,
                    attributes);
    }

    return grayscaleImage;
}
于 2010-06-16T14:46:08.767 回答
0

如果您将图像转换为 TGA(一种未压缩的 imaeg 格式),您可以使用“RubyPixels”直接编辑像素数据,随心所欲。然后,您可以将其转换回 PNG。

我建议使用 ImageMagick 进行转换,也来自 ruby​​。

于 2010-06-16T14:00:34.010 回答