Title: Rainbowize an image in Python
My post Use a color matrix to set an image's color tone in Python shows how to modify an image so it matches a color tone. This example uses that technique to rainbowize an image, to make strips of the image use different color tones.
To use the program, use the File menu's Open command to load an image. Set a brightness value and click Rainbowize.
When I first built this example, the results were pretty dark, particularly for the green and blue strips, so I added the brightness entry. Use it to make the results brighter or darker.
Rainbowizing Images
When you click Rainbowize, the following rainbowize_image method executes.
def rainbowize_image(self, *args):
'''Rainbowize the image.'''
brightness = float(self.brightness_var.get())
colors = [
(0.894, 0.012, 0.012, brightness),
(1.000, 0.549, 0.000, brightness),
(1.000, 0.929, 0.000, brightness),
(0.000, 0.502, 0.149, brightness),
(0.000, 0.298, 1.000, brightness),
(0.451, 0.161, 0.510, brightness),
]
self.rainbowized_image = \
rainbowize_image(self.original_image, colors)
# Display the result.
self.show_result()
This code gets the brightness value and then uses it to initialize a list of color parameters. Each entry gives a color tone's red, green, and blue components on a 0.0 to 1.0 scale, followed by the brightness.
You might want to experiment with using different brightness values for different components. For example, the orange and yellow strips are brighter than the green and blue ones, so you might prefer a result that uses a larger brightness value for green and blue.
The code then calls the following rainbowize_image function to do the real work.
def rainbowize_image(image, colors):
'''Rainbowize the image.'''
# Each color entry is r, g, b, brightness all between 0.0 and 1.0.
result = image.copy()
# Process the slices.
num_colors = len(colors)
x = 0
dx = image.width // num_colors
extra = image.width - num_colors * dx
for i, color in enumerate(colors):
# Crop out the next section.
rect = (x, 0, x + dx + extra, image.height - 1)
x += dx
image_part = image.crop(rect)
# Colorized it.
r, g, b, brightness = color
image_part = PointOps.to_color_tone(image_part, r, g, b, brightness)
# Paste it onto the result.
position = (i * dx, 0)
result.paste(image_part, position)
return result
This function starts by making a copy of the image so it doesn't mess up the original.
Before I describe the function's loop, I want to say a bit about the variables x, dx, and extra. You might like to divide the image's width by the number of colors and make each strip have that width. However, the image methods that crop and paste pieces of images work with pixel boundaries and cannot handle fractional pixels. You could calculate the start and width of each strip using floating point numbers, but the cropping and pasting functions will round off those values so there may be gaps between the strips and the final strip may not extend all the way to the edge of the image.
To work around that, the code calculates dx as an integer. To prevent gaps between strips and to make sure the final strip reaches the edge of the image, the code adds extra to each strip's width.
With that explanation out of the way, the code enumerates through the colors. For each color, it defines a rectangle for the next strip and uses image.crop to pull out that part of the image. It then calls PointOps.to_color_tone to colorize that strip. (See my previous post.)
The code then pastes the colorized strip onto the result image.
After it finishes processing all of the strips, the function returns the result.
Conclusion
The rainbowize_image function does all of the work, and the image colorizing part is done by PointOps.to_color_tone from the previous post, so this example isn't too complicated.
In my next post, I'll show how to colorize images in a much more interesting way. Meanwhile download the example to experiment with it and to see additional details.
|