Convert BitmapImage to grayscale, and keep alpha channel
Asked Answered
J

4

5

I'm having an issue with converting a BitmapImage (WPF) to grayscale, whilst keeping the alpha channel. The source image is a PNG.

The MSDN article here works fine, but it removes the alpha channel.

Is there any quick and effective way of converting a BitmapImage to a grayscale?

Jeanniejeannine answered 24/9, 2009 at 6:58 Comment(0)
M
2

You should have a look at image transformation using matrices.

In particular, this article describes how to convert a bitmap to grayscale using a ColorMatrix. (It is written in VB.NET, but it should be easy enough to translate to C#).

I haven't tested if it works with the alpha channel, but I'd say it's worth a try, and it definitely is a quick and effective way of modifying bitmaps.

Malleable answered 24/9, 2009 at 7:22 Comment(3)
I have used this on System.Drawing.Image and it works great. Not ideal for WPF images unless you are converting GDI bitmaps to BitmapSources.Prandial
My experience with WPF is very limited, so you're probably right.Malleable
Marking this as the answer as I was forced to use GDI Bitmaps and convert them into WPF BitmapsSources post changeJeanniejeannine
P
2

It really depends upon what your source PixelFormat is. Assuming your source is PixelFormats.Bgra32 and that you want to go to grayscale, you might consider using a target pixel format of PixelFormats.Gray16. However, Gray16 doesn't support alpha. It just has 65,535 graduations between black and white, inclusive.

You have a few options. One is to stay with Bgra32 and just set the blue, green and red channels to the same value. That way you can keep the alpha channel. This may be wasteful if you don't require an 8-bit alpha channel (for differing levels of alpha per pixel).

Another option is to use an indexed pixel format such as PixelFormats.Indexed8 and create a palette that contains the gray colours you need and alpha values. If you don't need to blend alpha, you could make the palette colour at position zero be completely transparent (an alpha of zero) and then progress solid black in index 1 through to white in 255.

Plainsman answered 31/10, 2012 at 1:29 Comment(0)
M
1

if relying on API calls fails. You can always try the 'do it yourself' approach: Just get access to the RGBA bytes of the picture, and for every RGBA replace it with MMMA, where M = (R+G+B)/3;

If you want it more perfect, you should add weights to the contribution of the RGB components. I believe your eye is more receptive for green, and as such that value should weigh more.

Mounting answered 24/9, 2009 at 7:4 Comment(1)
Thanks for that. I'm looking into the WriteableBitmap class as the easiest way to access the pixels directly.Jeanniejeannine
R
0

While not exactly quick and easy, a ShaderEffect would do the job and perform quite well. I've done it myself, and it works great. This article references how to do it and has source associated. I've not used his source, so I can't vouch for it. If you run into problems, ask, and I may be able to post some of my code.

Not every day you get to use HLSL in your LOB app. :)

Rehearing answered 24/9, 2009 at 13:46 Comment(1)
As an aside...this is assuming that you're wanting to display the image in your app after converting it to grayscale. If you're wanting to do this as an image processing step and then save the image or something there may be more work to try to get a ShaderEffect to work outside of the WPF effect pipeline. At that point, GDI or one of the other answers may be your best bet, anyway.Rehearing

© 2022 - 2024 — McMap. All rights reserved.