Reputation: 46493
This is general question (between programming and math):
How to replace a color by another in a bitmap?
I assume the bitmap is a 2D-array
Example : Let's replace RGB color [234,211,23] by RGB color [234,205,10].
How to do this color replacement, such that the neighbour colors are replaced as well ? I.e. a smooth color replacement.
I assume there exists methods like linear interpolation for neighbour colors, etc.
What are the classical ways to do this?
Here is an example of how to detect color RGB 234,211,23 and its neighbour colors in a 500x500px image bitmap array x
:
for i in range(500):
for j in range(500):
if abs(x[i,j][0] - 234) < TRESH and abs(x[i,j][1] - 211) < TRESH and abs(x[i,j][2] - 23) < TRESH:
x[i,j] = ... # how to set the new color in a smooth way?
Upvotes: 1
Views: 625
Reputation: 207465
New Answer
New answer coming - now I understand that you mean the neighbours in the colour sense rather than the geometric sense...
You could calculate the vector colour distance from each pixel of your image to the colour you want to change and use that as a mask. So, if we create the same image as below... say we have a red-yellow gradient as background with a blue square on it and we wish to replace the central orange colour across the middle.
# Make red-yellow gradient with blue square within
convert -size 500x500 gradient:red-yellow -fill none -stroke blue -strokewidth 10 -draw "rectangle 100,100 400,400" image.png
Now clone that image, and fill the clone with the orange tone we want to replace, then calculate the vector colour distance from each pixel to that orange tone:
convert image.png \( +clone -fill "rgb(255,128,0)" -colorize 100% \) \
-compose difference -composite \
-evaluate Pow 2 -separate \
-evaluate-sequence Add -evaluate pow 0.5 \
-negate \
colour_distance.png
You can then use this colour_distance.png
as a mask for alpha-compositing, so if we decide to replace that orangey tone with pink, we can do this:
convert image.png \
\( +clone -fill fuchsia -colorize 100% \) \
\( colour_distance.png -sigmoidal-contrast 20 \) \
-composite z.png
Note that I changed the pow 0.5
to pow 0.3
to roll off the mask more sharply.
Original Answer
Here's one way to do it. Say we have a red-yellow gradient as background with a blue square on it and we wish to replace the blue with green...
First, extract all the blue pixels onto a transparent background, then change them to green and blur them so they spread into the neighbouring pixels. Then overlay the blurred green pixels onto the original image.
I choose to do it with ImageMagick but you seem happy to adapt to other languages and libraries...
#!/bin/bash
# Make red-yellow gradient with blue square within
convert -size 500x500 gradient:red-yellow -fill none -stroke blue -strokewidth 10 -draw "rectangle 100,100 400,400" image.png
# Make everything blue green, then everything else transparent, then blur the lot
convert image.png -fill green -opaque blue -fill white +opaque green -transparent white -blur x6 x.png
# Now overlay the blurred greeness onto the original after replacing blues with green
convert x.png \( image.png -fill green -opaque blue \) -compose overlay -composite result.png
Image.png
x.png (the blurred, colour-replaced image)
result.png
Upvotes: 0
Reputation: 509
I think that a good approach that you can use is to change the whole image to a new color space, I'd rather use HSV color space instead of RGB, you can find some info here: HSV color Space.
When you wish to search for a specific color, RGB model is not the best option the principal reason is the large changes between brightness and darkness of the color. The thresholds on the RGB color space are not useful in this case. In HSV color space you have a channel to select the color of your interest and the other 2 channels are for the saturation and brightness of the color. But you can get accurate results only using the Hue channel (the first). The only thing that you need to take care about is in realize that you need to work this channel as a circular buffer because the maximum and minimum value are very similar in color, both are the red color.
Once you have the detected color you can set the new one and you can keep the saturation and brightness properties of the old color, by doing this the color changes will look like smoother.
Upvotes: 1
Reputation: 69
If you wish to replace the colours of pixel in a 2D - Array you do so as following:
Array[x][y] = new value
where x and y stand for the location of the pixel, but keep in mind that images use the right-handed system thus the values of y grow bottom to top while in computers you use the left handed system so y values grow from top to bottom. The exact syntax of assigning the value of the new colour depends on the programming language you are using (the example above works in ruby). Also some programming languages already offer image manipulation functions built in so make sure to read the documentation to avoid implementing an already implemented function.
Upvotes: 0