BLOG.CSHARPHELPER.COM: Reduce the number of colors in a Bitmap and remap them to make interesting effects in C#
Reduce the number of colors in a Bitmap and remap them to make interesting effects in C#
Andy Warhol was an American painter, print maker, and file maker. One particularly striking kind of image he produced featured a famous person such as John Lennon or Marilyn Monroe painted in very few colors. Sometimes several images of the same person painted with different color schemes were displayed together.
This program achieves a vaguely similar result by mapping each pixel in an image to the closest target pixel and then changing its value to a corresponding result color. For example, in the picture shown here pixels that are closer to red than to the other target colors are mapped to yellow in the result.
The following code shows how the program "warholizes" an image.
// Get the input and output color data. PictureBox[] in_boxes = { picFromColor0, picFromColor1, picFromColor2, picFromColor3, picFromColor4 }; PictureBox[] out_boxes = { picToColor0, picToColor1, picToColor2, picToColor3, picToColor4 }; byte[] in_r = new byte[in_boxes.Length]; byte[] in_g = new byte[in_boxes.Length]; byte[] in_b = new byte[in_boxes.Length]; byte[] out_r = new byte[in_boxes.Length]; byte[] out_g = new byte[in_boxes.Length]; byte[] out_b = new byte[in_boxes.Length]; for (int i = 0; i < in_boxes.Length; i++) { in_r[i] = in_boxes[i].BackColor.R; in_g[i] = in_boxes[i].BackColor.G; in_b[i] = in_boxes[i].BackColor.B; out_r[i] = out_boxes[i].BackColor.R; out_g[i] = out_boxes[i].BackColor.G; out_b[i] = out_boxes[i].BackColor.B; }
// Get and lock the Bitmap32. Bitmap original_bm = picInput.Image as Bitmap; Bitmap bm = new Bitmap(original_bm); Bitmap32 bm32 = new Bitmap32(bm); bm32.LockBitmap();
// Process the pixels. for (int y = 0; y < bm.Height; y++) { for (int x = 0; x < bm.Width; x++) { // Process pixel (row, col). byte r, g, b, a; bm32.GetPixel(x, y, out r, out g, out b, out a); int best_i = 0; int best_dist = int.MaxValue; for (int i = 0; i < in_boxes.Length; i++) { // Compute the distance from this pixel to input pixel i. int dr = r - in_r[i]; int dg = g - in_g[i]; int db = b - in_b[i]; int dist = dr * dr + dg * dg + db * db;
// See if this is an improvement. if (dist < best_dist) { best_dist = dist; best_i = i; } }
// Update the pixel. bm32.SetPixel(x, y, out_r[best_i], out_g[best_i], out_b[best_i], 255); } }
// Unlock the Bitmap32. bm32.UnlockBitmap();
// Display the result. picOutput.Image = bm; }
The code uses the Bitmap32 class to quickly manipulate the red, green, and blue color components of the image's pixels. For information about that class, see Manipulate 32-bit image pixels using a class with simple pixel get and set methods in C#.
The code loads the image into a Bitmap32 object and locks it. It then loops over each of the image's pixels.
For each pixel, the program finds the target color closest to the pixel's color. It then changes the pixel's value to the corresponding output color.
Load your own images and experiment with the program. Click a target or output color to change the color values and see what happens.
This program can save the result images but it uses 24-bit color depth even though the result image only uses 5 colors.
This example can process a 1000x1000 pixel image in about half a second so it's fast enough that you can use it to make other programs that manipulate an image's pixels in a similar way.
Comments