[C# Helper]
Index Books FAQ Contact About Rod
[Beginning Database Design Solutions, Second Edition]

[Beginning Software Engineering, Second Edition]

[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

[C# 24-Hour Trainer]

[C# 5.0 Programmer's Reference]

[MCSD Certification Toolkit (Exam 70-483): Programming in C#]

Title: Brighten saturated pixels in an image in C#

[Brighten saturated pixels in an image in C#]

[Brighten saturated pixels in an image in C#]

Sometimes when I take a picture, the poor lighting makes some pixels come out less brightly than I would like. For example, in the picture on the right the red raspberries aren't very red.

This example lets you brighten pixels. Use the radio buttons to select red, green, or blue. Then enter a threshold amount and a multiplier. If a pixel's selected component is at least the threshold amount greater than its other two components, then the program multiples that pixel's selected component value by the multiplier.

For example, in the picture shown at the top of the post, Red is selected, the threshold is 40, and the multiplier is 4. If a pixel's red component is at least 40 more than its green and blue components, then the program multiplies that pixel's red component by 4.

That is very large multiplier so the reddish pixels become very red. I chose that value to make the changes in the example obvious. A more reasonable multiplier might be 1.5.

The example does not brighten pixels that don't pass the threshold test. In this example, the pixel must be mostly red or it is left unchanged.

Brighten Pixels

The example program demonstrates a few useful techniques that I've described in earlier posts. For example, it shows how to load a bitmap without locking it and how to save an image using different file extensions such as .png and .jpg. The most important of those techniques is using the Bitmap32 class to quickly manipulate the pixels in an image. For information about the Bitmap32 class, see the post Use the Bitmap32 class to manipulate image pixels very quickly in C#.

The key to this example is the following BrightenPixels method.

private Bitmap BrightenPixels( Bitmap bitmap, PixelTypes pixel_type, int threshold, float scale) { Bitmap bm = new Bitmap(bitmap); Bitmap32 bm32 = new Bitmap32(bm); bm32.LockBitmap(); int width = bm.Width; int height = bm.Height; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { byte r, g, b, a; bm32.GetPixel(x, y, out r, out g, out b, out a); bool over_threshold = false; switch (pixel_type) { case PixelTypes.Red: if ((r >= g + threshold) && (r > b + threshold)) { int new_r = (int)(r * scale); if (new_r > 255) new_r = 255; else if (new_r < 0) new_r = 0; r = (byte)new_r; } break; case PixelTypes.Green: if ((g >= r + threshold) && (g > b + threshold)) { int new_g = (int)(g * scale); if (new_g > 255) new_g = 255; else if (new_g < 0) new_g = 0; g = (byte)new_g; } break; case PixelTypes.Blue: if ((b >= r + threshold) && (b > g + threshold)) { int new_b = (int)(b * scale); if (new_b > 255) new_b = 255; else if (new_b < 0) new_b = 0; b = (byte)new_b; } break; } bm32.SetPixel(x, y, r, g, b, a); } } bm32.UnlockBitmap(); return bm; }

This code creates a copy of the original bitmap and makes an associated Bitmap32 object. It then locks the Bitmap32 object and loops through the image's pixels.

For each pixel, the code uses the Bitmap32 object's GetPixel method to get the pixel's color components. It then uses a switch statement to operate on the selected red, green, or blue pixel component. If the selected component's value is greater than the other components' values plus the threshold, then the code multiplies the selected component by the multiplier. The code then ensures that the result is between 0 and 255 because component values, which are bytes, must lie between 0 and 255.

After the code has updated the selected component's value, it uses the Bitmap32 object's SetPixel method to update the pixel in the bitmap.

Once it has finished processing all of the image's pixels, the code unlocks the Bitmap32 object and returns the modified bitmap.

Unusual Uses

You can use the program to brighten pixels, but you can also use it to darken them. If you set the multiplier to a value less than 1, then the selected pixels lose some of the selected color component. For example, if you select the red component, then the program would remove some of the red from the selected pixels. If you set the multiplier to 0 (or a negative value), then the program completely removes the selected component from the pixels.

The program has a couple of possible weird side uses. For example, if you set the threshold to -255, then every pixel passes the threshold test. If you then set the multiplier to 0, the program removes all of the selected color component from the entire image. If you set the multiplier to 255, then the program sets the selected component to 255 for all pixels that begin with any of that component.

Conclusion

This example has some limitations. For example, it only processes pixels where one component is larger than the others. It won't, for example, process yellow pixels because those pixels have relatively large red and green components. You could make the pixel selection criteria more complicated to try to address this issue.

This example also processes all of the pixels that meet its criteria even if some of those pixels should not be processed. If you look at the picture at the top of the post, you'll see that the program made parts of the box red even though I really just wanted to brighten the raspberries. In my next post, I'll show one method that you can use to address this issue.

Download the example to experiment with it and to see additional details.

© 2009-2023 Rocky Mountain Computer Consulting, Inc. All rights reserved.