Is there a way to set the Gamma value when changing the WriteableBitmap pixel color?

HoneyBee 186 Reputation points
2022-08-05T01:19:10.103+00:00

I'm developing a part that inverts the colors of an image.

I got a lot of advice from MSDN and I ended up with one way to do it very quickly.

It looks like the code below.

The speed is very fast.

However, when the color is converted, the sharpness decreases.
(The text in the image is not clearly visible.)

If you convert an image with black text, the text turns white. At this time, my goal is to make the letters that have changed to white thicker and darker.

Is there any other way other than setting the gamma value?

If the gamma value can be set, which part of my code should I supplement?

I also want to create an option that allows the user to adjust the gamma value.

public static WriteableBitmap ConvertNagativePage(BitmapImage source)  
        {  
            FormatConvertedBitmap newFormatedBitmapSource = new FormatConvertedBitmap();  
            newFormatedBitmapSource.BeginInit();  
            newFormatedBitmapSource.Source = source;  
            newFormatedBitmapSource.DestinationFormat = PixelFormats.Bgra32;  
            newFormatedBitmapSource.EndInit();  
            WriteableBitmap wb = new WriteableBitmap(newFormatedBitmapSource);  
            int nWidth = wb.PixelWidth;  
            int nHeight = wb.PixelHeight;  
            int[] pixelData = new int[nWidth * nHeight];  
            int nWidthBytes = nWidth * 4;  
            wb.CopyPixels(pixelData, nWidthBytes, 0);  
            for (int i = 0; i < pixelData.Length; ++i)  
            {  
                pixelData[i] ^= 0x00FFFFFF;  
                pixelData[i] = MakePixelGray(pixelData[i]);  
            }  
            wb.WritePixels(new Int32Rect(0, 0, nWidth, nHeight), pixelData, nWidthBytes, 0);  
  
            return wb;  
        }  
  
        private static int MakePixelGray(int pixel)  
        {  
            byte blue = (byte)pixel;  
            byte green = (byte)(pixel >> 8);  
            byte red = (byte)(pixel >> 16);  
            byte alpha = (byte)(pixel >> 24);  
            byte gray = (byte)(((red * 77) + (green * 150) + (blue * 29) + 128) / 256);  
            return (int)(alpha << 24 | gray << 16 | gray << 8 | gray);  
        }  
Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,669 questions
{count} votes

Accepted answer
  1. Castorix31 81,636 Reputation points
    2022-08-08T10:10:09.07+00:00

    You can test with Gamma formulas found on Google

    For example :

    {  
        var imgSource = image1.Source;  
        FormatConvertedBitmap newFormatedBitmapSource = new FormatConvertedBitmap();  
        newFormatedBitmapSource.BeginInit();  
        newFormatedBitmapSource.Source = (BitmapSource)imgSource;  
        newFormatedBitmapSource.DestinationFormat = PixelFormats.Bgra32;  
        newFormatedBitmapSource.EndInit();  
      
        WriteableBitmap wb = new WriteableBitmap(newFormatedBitmapSource);  
        int nWidth = wb.PixelWidth;  
        int nHeight = wb.PixelHeight;  
      
        int nPitch = (int)(nWidth << 2);  
        int nSize = (int)(nPitch * nHeight);  
        byte[] pixelData = new byte[nSize];  
      
        int nWidthBytes = nWidth * 4;  
        wb.CopyPixels(pixelData, nWidthBytes, 0);  
      
        for (int nY = 0; nY < nHeight; nY++)  
        {  
            for (int nX = 0; nX < nWidth; nX++)  
            {  
                int nPos = (int)(nY * nPitch + nX * 4);  
                byte b = (byte)pixelData[nPos], g = (byte)pixelData[nPos + 1], r = (byte)pixelData[nPos + 2], a = (byte)pixelData[nPos + 3];  
      
                //byte nGray = Gray(r, g, b);  
                //b = nGray;  
                //g = nGray;  
                //r = nGray;  
      
                // > 1 : lighten, < 1 : darken  
                double nGamma = 2;  
                double nGammaCorrection = (1 / nGamma);  
                b = (byte)(Math.Pow((double)(b / 255.0), nGammaCorrection) * 255.0f);  
                g = (byte)(Math.Pow((double)(g / 255.0), nGammaCorrection) * 255.0f);  
                r = (byte)(Math.Pow((double)(r / 255.0), nGammaCorrection) * 255.0f);  
      
                pixelData[nPos] = b;  
                pixelData[nPos + 1] = g;  
                pixelData[nPos + 2] = r;  
            }  
        }  
      
        wb.WritePixels(new Int32Rect(0, 0, nWidth, nHeight), pixelData, nWidthBytes, 0);  
        image1.Source = wb;  
    }  
    // Test for gray       
    private byte Gray(byte nRed, byte nGreen, byte nBlue)  
    {  
        return (byte)((nRed * 299 + nGreen * 587 + nBlue * 114) / 1000);  
    }  
    

    Test with 2 and 0.3 :

    229114-gamma.jpg


1 additional answer

Sort by: Most helpful
  1. HoneyBee 186 Reputation points
    2022-08-05T08:52:06.227+00:00

    @Hui Liu-MSFT
    Remember the advice you gave me at this link?

    how-to-use-colormatrix-to-highlight-a-specific-col.html

    It's the same project.
    228465-000013.png
    Your advice was great.

    Obviously, the letters are much clearer.

    But it was very slow...

    So I replaced it with the code attached above and cut the speed in half.

    I am attaching my sample image here.

    This image is used as the Background ImageSource of the InkCanvas.

    I used this image applied to the Background of InkCanvas
    I load it as an ImageSource, invert the color, and apply it back to the InkCanvas' Background.

    I want to apply the idea you gave me, how to use the SetGamma method, to the code below.

    With the sample you helped, it takes about 0.35 seconds.

    But the code below takes about 0.17 seconds. Very fast.

    Here I want to adjust the Gamma value to improve speed and also increase sharpness.

    public static WriteableBitmap ConvertNagativePage(BitmapImage source)  
            {  
                System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();  
                sw.Start();  
                FormatConvertedBitmap newFormatedBitmapSource = new FormatConvertedBitmap();  
                newFormatedBitmapSource.BeginInit();  
                newFormatedBitmapSource.Source = source;  
                newFormatedBitmapSource.DestinationFormat = PixelFormats.Bgra32;  
                newFormatedBitmapSource.EndInit();  
                WriteableBitmap wb = new WriteableBitmap(newFormatedBitmapSource);  
                int nWidth = wb.PixelWidth;  
                int nHeight = wb.PixelHeight;  
                  
                int[] pixelData = new int[nWidth * nHeight];  
                int nWidthBytes = nWidth * 4;  
                  
                int[] pixelData = new int[nHeight * nWidthBytes];  
      
                wb.CopyPixels(pixelData, nWidthBytes, 0);  
      
      
                for (int i = 0; i < pixelData.Length; ++i)  
                {  
                    pixelData[i] ^= 0x00FFFFFF;  
                    pixelData[i] = MakePixelGray(pixelData[i]);  
                }  
                wb.WritePixels(new Int32Rect(0, 0, nWidth, nHeight), pixelData, nWidthBytes, 0);  
                sw.Stop();  
                System.Diagnostics.Debug.WriteLine(sw.Elapsed);  
                return wb;  
            }  
      
            private static int MakePixelGray(int pixel)  
            {  
                byte blue = (byte)pixel;  
                byte green = (byte)(pixel >> 8);  
                byte red = (byte)(pixel >> 16);  
                byte alpha = (byte)(pixel >> 24);  
                byte gray = (byte)(((red * 77) + (green * 150) + (blue * 29) + 128) / 256);  
                return (int)(alpha << 24 | gray << 16 | gray << 8 | gray);  
            }  
    
    0 comments No comments