Find Max value for a given channel and set it to a specific value.

IMagick is a native PHP extension to create and modify images using the ImageMagick API. ImageMagick Studio LLC did not write nor does it maintain the IMagick extension, however, IMagick users are welcome to discuss the extension here.
Post Reply
GiantCowFilms
Posts: 17
Joined: 2017-02-28T22:08:29-07:00
Authentication code: 1151

Find Max value for a given channel and set it to a specific value.

Post by GiantCowFilms »

I'm trying to figure out a way to find the largest value in a given channel, and set it to a particular value. Note that the largest value could be different to the possible maximum (for example it could only be 202 instead of 255 in an eight bit image). I would then like to assign it a particular value (for example if it is 202 set it to 235). I found a way to identify the maximum using

Code: Select all

-format "%[max]" info:
, but have been unable to figure out how to set a particular value on a particular channel to a different value while ignoring the other channel. The -fill option seems to be specifically designed for multi-channel operations. Combining all this into one command would be ideal.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Find Max value for a given channel and set it to a specific value.

Post by fmw42 »

What is your IM version and platform? Please always provide that with questions, since syntax differs. It can be done in one command if using IM 7, but not IM 6.

You will have to convert your new value to QuantumRange for your IM compile, since that is what is produce by %[max], i.e. 0-255 for Q8, 0-65535 for Q16, etc, or use "%[fx:100*max]" as a percent value between 0 and 100 (as a float) and -fuzz XXX% to ensure you stay within the equivalent quantum range equivalent integer value.

For IM 6 and Unix, this should work (untested)

Code: Select all

oldmax=`convert image -format "%[max]" info:
newmax=your (integer) value in quantum range
convert image -channel X -fill newmax -opaque oldmax +channel result
where X is R or G or B for an RGB image.

In IM 7 and Unix, try

Code: Select all

magick image -set option:oldmax "%[max]" -channel X -fill newmax -opaque "%[oldmax]" +channel result
GiantCowFilms
Posts: 17
Joined: 2017-02-28T22:08:29-07:00
Authentication code: 1151

Re: Find Max value for a given channel and set it to a specific value.

Post by GiantCowFilms »

Platform: Windows 10. Version 7 something, I can always install a new one as needed.

Note: I meant the max for the channel. "%[max]" will give you the greatest of the three channel. I want to use the max for the channel I'm manipulating.

Also, your all-in-one command fails. I think newmax and "%[oldmax]" might be in the wrong places . . .

Further -fill doesn't work with just an integer value, at least not on my end:

Code: Select all

magick: unable to open image '65535': No such file or directory @ error/blob.c/OpenBlob/3094.
magick: no decode delegate for this image format `' @ error/constitute.c/ReadImage/509.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Find Max value for a given channel and set it to a specific value.

Post by fmw42 »

Sorry, my error, since I did not test. You must use "gray(value)" for the old and new values where value is in the range 0-255. So this works with the IM internal image logo:

In unix replacing 200 for the red max (which is 255):

Code: Select all

magick logo: -set option:oldmax "%[fx:round(255*maxima.r)]" -separate +channel \
\( -clone 0 -fill "gray(200)" -opaque "gray(%[oldmax])" \) \
-swap 0,3 +delete -combine result.png
In windows replacing 200 for the red max (which is 255):

Code: Select all

magick logo: -set option:oldmax "%[fx:round(255*maxima.r)]" -separate +channel ^
( -clone 0 -fill "gray(200)" -opaque "gray(%[oldmax])" ) ^
-swap 0,3 +delete -combine result.png
%[fx:maxima] is in the range 0 to 1. So I must multiply by 255 and round to an integer. The suffix .r means get the red maximum value

This could have been simpler, but it seems that -fill ... -opaque ... is not channel sensitive.

Code: Select all

im7 magick logo: -channel r -fill "gray(200)" -opaque "gray(255)" +channel tmp2.png
But this must be a bug, since it works in IM 6

Code: Select all

convert logo: -channel r -fill "gray(200)" -opaque "gray(255)" +channel tmp2.png
I will report this.
GiantCowFilms
Posts: 17
Joined: 2017-02-28T22:08:29-07:00
Authentication code: 1151

Re: Find Max value for a given channel and set it to a specific value.

Post by GiantCowFilms »

Still get an error, Invalid swap index. Also, what values would I need to get that to work for any of the other channels if I needed?
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Find Max value for a given channel and set it to a specific value.

Post by fmw42 »

Are you running my command in a bat file? If so, then you must double % to %%. Otherwise, I do not know why it should fail. I do not use Windows, so am not sure what is the issue. Try taking out the ^ at the end of the lines and make it into one long line. Perhaps a copy and paste from my command is not keeping the proper ^ end of line character without spaces after it.

Code: Select all

magick logo: -set option:oldmax "%[fx:round(255*maxima.r)]" -separate +channel ( -clone 0 -fill "gray(200)" -opaque "gray(%[oldmax])" ) -swap 0,3 +delete -combine result.png
For other channels replace maxima.r with maxima.g or maximal.b. Then change -clone 0 to -clone 1 or -clone 2 correspondingly. Then you have to use -swap 1,3 or -swap 2,3 correspondingly

Code: Select all

magick logo: -set option:oldmax "%[fx:round(255*maxima.g)]" -separate +channel ( -clone 1 -fill "gray(200)" -opaque "gray(%[oldmax])" ) -swap 1,3 +delete -combine result.png

Code: Select all

magick logo: -set option:oldmax "%[fx:round(255*maxima.b)]" -separate +channel ( -clone 2 -fill "gray(200)" -opaque "gray(%[oldmax])" ) -swap 2,3 +delete -combine result.png
see
http://www.imagemagick.org/Usage/basics/#clone
http://www.imagemagick.org/Usage/basics/#swap
http://www.imagemagick.org/Usage/color_basics/#separate
http://www.imagemagick.org/Usage/color_basics/#combine

What I am doing is:
separate into 3 channel
clone the color channel desired
modify the cloned channel
swap the old color channel with the new cloned one
delete the swapped old channel, which is now the last image in the command line sequence
then recombine the 3 color channels
GiantCowFilms
Posts: 17
Joined: 2017-02-28T22:08:29-07:00
Authentication code: 1151

Re: Find Max value for a given channel and set it to a specific value.

Post by GiantCowFilms »

Round doesn't seem to work correctly on 32 bit images, giving this output for the value 67335:
6733567335.

I'm currently using this on 32 bit tiffs. Which might also explain why swap wasn't working...
GiantCowFilms
Posts: 17
Joined: 2017-02-28T22:08:29-07:00
Authentication code: 1151

Re: Find Max value for a given channel and set it to a specific value.

Post by GiantCowFilms »

Round doesn't seem to work correctly on 32 bit images, giving this output for the value 67335:
6733567335.

I'm currently using this on 32 bit tiffs. Which might also explain why swap wasn't working...
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Find Max value for a given channel and set it to a specific value.

Post by fmw42 »

Yes, you now have 4 channels from the -separate including the alpha channel. Do you need the alpha channel? If so, then you have a more complex issue of the combine followed by re-inserting the alpha channel.

In unix, if I make the logo: image transparent where it is white, then I have 32-bit image and need to do this to change the red value from 255 to 200

Code: Select all

magick \( logo: -transparent white \) \
-set option:oldmax "%[fx:round(255*maxima.r)]" -separate +channel \
\( -clone 0 -fill "gray(200)" -opaque "gray(%[oldmax])" \) \
-swap 0,4 +delete \( -clone 0-2 -combine \) \
-delete 0-2 +swap -alpha off -compose copy_opacity -composite \
result.png
In windows, if I remove the new line \ and make it one long line, then try

Code: Select all

magick ( logo: -transparent white ) -set option:oldmax "%[fx:round(255*maxima.r)]" -separate +channel ( -clone 0 -fill "gray(200)" -opaque "gray(%[oldmax])" ) -swap 0,4 +delete ( -clone 0-2 -combine ) -delete 0-2 +swap -alpha off -compose copy_opacity -composite result.png
If you are not using an RGBA TIFF (ie. CMYK) then you should convert to sRGB first, otherwise, you would now have to deal with colorspace difference in the combine step and if an alpha channel as well, then 5 channels rather than 4.

When posting questions, it is always a good idea to send your input images to avoid confusion and misunderstandings. They can be uploaded to some free hosting service such as dropbox.com and the URL posted here.
GiantCowFilms
Posts: 17
Joined: 2017-02-28T22:08:29-07:00
Authentication code: 1151

Re: Find Max value for a given channel and set it to a specific value.

Post by GiantCowFilms »

Sorry for not being clear, I mean 32 bits per channel. And yes, it also has an alpha, so 128 bits net total.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Find Max value for a given channel and set it to a specific value.

Post by fmw42 »

What do you get from

Code: Select all

magick yourimage -format "%[maxima.r]" info:
it should still be between 0 and 1, even for 32bit IM compile.


What do you get from

Code: Select all

magick -version
Are you using 32bit IM and with or without HDRI?

Can you post your image to some free hosting service and put the URL here?
Post Reply