C# Normalizing RGB and creating a new image

3.5k views Asked by At

I am trying to create a program that accepts an image, recursively goes through each pixel, normalizes the pixel and re-creates a NEW image that looks the same as the original, but has normalized pixels instead.

    public void parseJpeg(String jpegPath)
    {
        var normalizedRed = 0.0;
        var normalizedGreen = 0.0;
        var normalizedBlue = 0.0;
        Bitmap normalizedImage = null;

        var image = new Bitmap(jpegPath);
        normalizedImage = new Bitmap(image.Width, image.Height);
        for (int x = 0; x < image.Width; ++x)
        {
            for (int y = 0; y < image.Height; ++y)
            {
                Color color = image.GetPixel(x, y);

                double exponent = 2;
                double redDouble = Convert.ToDouble(color.R);
                double blueDouble = Convert.ToDouble(color.B);
                double greenDouble = Convert.ToDouble(color.G);

                double redResult = Math.Pow(redDouble, exponent);
                double blueResult = Math.Pow(blueDouble, exponent);
                double greenResult = Math.Pow(greenDouble, exponent);

                double totalResult = redResult + blueResult + greenResult;                    

                normalizedRed = Convert.ToDouble(color.R) / Math.Sqrt(totalResult);
                normalizedGreen = Convert.ToDouble(color.G) / Math.Sqrt(totalResult);
                normalizedBlue = Convert.ToDouble(color.B) / Math.Sqrt(totalResult);


                Color newCol = Color.FromArgb(Convert.ToInt32(normalizedRed), Convert.ToInt32(normalizedGreen), Convert.ToInt32(normalizedBlue));

                normalizedImage.SetPixel(x, y, newCol);                                                                
            }                
        }

        normalizedImage.Save("C:\\Users\\username\\Desktop\\test1.jpeg"); 
        resultsViewBox.AppendText("Process completed.\n");
    }

Using the above code produces all black pixels and I do not understand why. When it normalizes it sets RGB = 1. After normalization, how do I set pixels with the NEW normalized value?

When I perform the below code, I get a black and blue image in my preview, but when I open the file it's blank. This is better than what I was getting before, which was ALL black pixels. This only works on one image though. So I am not sure how much of a step forward it is.

public void parseJpeg(String jpegPath)
    {
        Bitmap normalizedImage = null;           

        var image = new Bitmap(jpegPath);
        normalizedImage = new Bitmap(image.Width, image.Height);
        for (int x = 0; x < image.Width; ++x)
        {
            for (int y = 0; y < image.Height; ++y)
            {
                Color color = image.GetPixel(x, y);

                float norm = (float)System.Math.Sqrt(color.R * color.R + color.B * color.B + color.G * color.G);

                Color newCol = Color.FromArgb(Convert.ToInt32(norm));

                normalizedImage.SetPixel(x, y, newCol);
            }
        }

        normalizedImage.Save("C:\\Users\\username\\Desktop\\test1.jpeg");
        resultsViewBox.AppendText("Process completed.\n");
    }

I found the code for what I was trying to do: http://www.lukehorvat.com/blog/normalizing-image-brightness-in-csharp/

    public void parseJpeg(String jpegPath)
    {
        var image = new Bitmap(jpegPath);
        normalizedImage = new Bitmap(image.Width, image.Height);


        for (int x = 0; x < image.Width; ++x)
        {
            for (int y = 0; y < image.Height; ++y)
            {
                float pixelBrightness = image.GetPixel(x, y).GetBrightness();
                minBrightness = Math.Min(minBrightness, pixelBrightness);
                maxBrightness = Math.Max(maxBrightness, pixelBrightness);
            }
        }

        for (int x = 0; x < image.Width; x++)
        {
            for (int y = 0; y < image.Height; y++)
            {
                Color pixelColor = image.GetPixel(x, y);
                float normalizedPixelBrightness = (pixelColor.GetBrightness() - minBrightness) / (maxBrightness - minBrightness);
                Color normalizedPixelColor = ColorConverter.ColorFromAhsb(pixelColor.A, pixelColor.GetHue(), pixelColor.GetSaturation(), normalizedPixelBrightness);

                normalizedImage.SetPixel(x, y, normalizedPixelColor);
            }
        }

        normalizedImage.Save("C:\\Users\\username\\Desktop\\test1.jpeg");
        resultsViewBox.AppendText("Process completed.\n");
    }
3

There are 3 answers

3
Golden Dragon On BEST ANSWER

You are creating a new Bitmap and saving over the file for every pixel in your image. Move the

normalizedImage = new Bitmap(image.Width, image.Height);

line to before your loops, and the

normalizedImage.Save("C:\\Users\\username\\Desktop\\test1.jpeg");

line to after your loops.

Your normalization algorithm does not appear to be correct. Let's say your original color was red (255,0,0) Then your totalResult will be 65025, and your normalizedRed will be 255/sqrt(65025), which is 1, giving you a new normalized color of (1,0,0), which is essentially black.

0
Jonathan On

Just as a note, your code will run a bit faster if you define all the doubles once outside the look and then assign them within the loop rather than defining and deleting each of the 8 doubles each iteration

0
mathsRuinedme On

Instead of messing with the colors you should use the brightness or luminosity factor to achieve normalization. Here is a link to the already answered question that can help you. you can convert each RGB pixel to HSL and minupulate L factor:

How do I normalize an image?

The code that you shared is actually a trim down version of HSL manipulation.