如何将 32 位 RGBA 图像转换为保留 alpha 的灰度
我想在代码中按需将 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 一起使用,但正如我所说,部分透明的像素仍然是彩色的。我应该指出,这是通过 WinForms PictureBox
在白色背景上显示 Image 对象。这可能就是 PictureBox 绘制图像和处理透明部分的方式吗?背景颜色不会影响它(颜色的色调肯定来自原始图像),但也许 PictureBox 没有正确重绘透明像素?
我见过一些使用 FormatConvertedBitmap 和 OpacityMask 的方法。我还没有尝试过,主要是因为我真的不想导入PresentationCore.dll(更不用说这意味着它无法在.NET 2.0 限制的应用程序中工作)。当然基本的 System.Drawing.* 东西可以完成这个简单的过程吗?或不?
I'd like to, in code and on demand, convert a 32-bit RGBA Image object (originally a 32-bit PNG) to its 32-bit grayscale counterpart.
I've already read several other questions here, as well as many articles online. I've tried using ColorMatrix to do it, but it doesn't seem to handle the alpha very well. Pixels that are entirely opaque grayscale perfectly. Any pixel that is partially transparent seems not to translate well as there are still tinges of color in those pixels. It is enough to be noticeable.
The ColorMatrix I use is as follows:
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}
});
This is, as I've read, a pretty standard NTSC weighted matrix. I then use it, along with Graphics.DrawImage
, but as I said the partially transparent pixels are still colored. I should point out this is displaying the Image object via a WinForms PictureBox
on a white background. Could it be perhaps just the way PictureBox's draw their images and handle the transparent parts? The background colors are not affecting it (the tinge of color is from the original image for sure), but perhaps PictureBox isn't redrawing the transparent pixels correctly?
I've seen some methods that use a FormatConvertedBitmap along with an OpacityMask. I haven't tried it, mainly because I'd really prefer not to have to import PresentationCore.dll (not to mention that means it won't work in .NET 2.0 limited apps). Surely the basic System.Drawing.* stuff can do this simple procedure? Or not?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您是否有机会使用 ColorMatrix 将图像绘制到自身上?这当然行不通(因为如果你在绿色像素上绘制半透明灰色的东西,一些绿色就会透过)。您需要将其绘制到仅包含透明像素的新的空位图上。
Are you by any chance painting the image onto itself using a ColorMatrix? That won't work of course (because if you paint something semi-transparent-gray over a green pixel, some green will shine through). You need to paint it onto a new, empty bitmap containing only transparent pixels.
感谢 danbystrom 出于好奇,我确实是在原图的基础上重画了。对于任何感兴趣的人,这是我使用的更正方法:
Thanks to danbystrom's idle curiosity, I was indeed redrawing on top of the original. For anyone interested, here's the corrected method I used:
如果将图像转换为 TGA(一种未压缩的 imaeg 格式),您可以使用“RubyPixels”直接编辑像素数据,随心所欲。然后您可以将其转换回 PNG。
我建议使用同样来自 ruby 的 ImageMagick 进行转换。
If you convert the image to TGA, an uncompressed imaeg format you can use "RubyPixels" to edit the pixel data directly, doing whatever you please. You can then convert it back to PNG.
I recomend doing to conversion with ImageMagick, also from ruby.