0
votes

I want to change all colors #FF00FF in an image to #0000FF while keeping shades, ideally. So I figured I should at least get it to change colors to begin with to see if the software is even capable of doing things like that.

However its only changing a bit of the color to white and only with a high Fuzz. So it's obvious that RGB in Imagemagick doesn't work like it does anywhere else and I can't find anything to explain how it works.

It seems to replace some off-white with pure white.

Using PHP I do:

exec("convert ".$dir."".$file." -channel RGB -fuzz 30% -opaque rgb\(255,0,255\) -fill rgb\(0,0,255\) ".$dir."".$file);  
1
This seems very unclear in its current form. You don't want to change only those colours, but similar ones, too, correct? Can you show an example of what you want, and how IM is not doing what you want? - Pekka
I don't know why it didn't occur to me to post images when posting about modifying images, however the answer is complete, thanks for the suggestion ;) - Jack M.

1 Answers

2
votes

I am not 100% certain what you mean as you haven't provided a sample of what other software does, but I'll have a try and see if we can get there.

So, if we make a starting image, including your presumed shades of magenta on the left and some test colours on the right:

convert -size 256x256 gradient:black-magenta -size 50x256 \
   xc:black xc:white xc:red xc:lime xc:blue +append start.png

enter image description here

And, you want to change magenta shades into blue. I would call that a hue modulation, so I would want to find out the hue angle between blue and magenta, so I would create a 2x1 image with one magenta and one blue pixel and get their HSI values:

convert xc:magenta xc:blue -append -colorspace hsi txt:

Output

# ImageMagick pixel enumeration: 1,2,65535,hsi
0,0: (54612.5,65535,43690)  #D555FFFFAAAA  hsi(300,100%,66.6667%)
0,1: (43690,65535,21845)  #AAAAFFFF5555  hsi(240,100%,33.3333%)

And I can see their hues are 60 degrees apart (300-240). So I would use the -modulate operator, which takes a Brightness, Saturation and Hue, leave the first two unchanged at 100%, and modify the Hue by 60 degrees:

convert start.png -modulate 100,100,60 result.png

enter image description here


Or maybe that is not what you mean? Maybe you only mean to affect specific colour. If so, it gets harder... but not that hard :-)

First, extract the Hue, Saturation and Brightness layers to separate files:

convert start.png -colorspace HSL -separate -colorspace gray HSL-%d.png

That will give us the Hue as a single channel greyscale image in HSL-0.png, the Saturation in HSL-1.png and the Lightness in HSL-2.png.

Now we want to make a new LUT (Lookup Table) for the Hue channel, so we make a 360 pixel long LUT that maps 1:1, i.e. everything maps to normal.

convert -size 1x360 gradient: -rotate 90 greyscale.png

enter image description here

Then we want to dink with the lookups around magenta (300) and make them blue (240). So we want to subtract 60 degrees (which is 0.16 if you scale 0-360 degrees onto the range 0-1) from all pixels in the range 280-320 so there is some tolerance:

convert -size 1x360 gradient: -rotate 90 -colorspace gray -fx "i<280||i>320?u:u-0.16" hueCLUT.png

enter image description here

Now apply that LUT to the Hue of the original image and rebuild it...

convert HSL-0.png -colorspace gray hueCLUT.png -clut  HSL-1.png HSL-2.png -set colorspace HSL -combine -colorspace RGB result.png

enter image description here

So, as a simpler script, that might become:

#!/bin/bash

# Make a hue CLUT, transforming magenta hues to blue
convert -size 1x360 gradient: -rotate 90 -colorspace gray -fx "i<295||i>305?u:u-0.16" -resize 256x1! hueclut.png

# Apply to the hue channel
convert start.png -colorspace HSL -write MPR:HSL \
        -channel R -separate hueclut.png -clut   \
        \( MPR:HSL -channel G -separate \)       \
        \( MPR:HSL -channel B -separate \)       \
        -set colorspace HSL -combine -colorspace RGB result.png