possible bug or clarification requested for -fuzz

Post any defects you find in the released or beta versions of the ImageMagick software here. Include the ImageMagick version, OS, and any command-line required to reproduce the problem. Got a patch for a bug? Post it here.
Post Reply
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

possible bug or clarification requested for -fuzz

Post by fmw42 »

I would expect the following gradient image to be completely converted to a constant specified new graylevel of 60% when using a -fuzz of 50% and starting graylevel of 50%. But I have to add a slight amount to the fuzz of a minimum of 50.001% to make it work.

convert -size 256x256 gradient: -fuzz 50% -fill "gray(60%)" -opaque "gray(50%)" grad_g60pct_A.png
identify -verbose grad_g60pct_A.png
Channel statistics:
gray:
min: 0 (0)
max: 39321 (0.6)
mean: 39167.4 (0.597656)

So it is not a constant result of gray(60%). Graylevel 0 is not covered by the combination of midval=gray(50%) and fuzz=50%

But

convert -size 256x256 gradient: -fuzz 50.001% -fill "gray(60%)" -opaque "gray(50%)" grad_g60pct_B.png
identify -verbose grad_g60pct_B.png
Channel statistics:
gray:
min: 39321 (0.6)
max: 39321 (0.6)
mean: 39321 (0.6)

Which is a constant image of value gray(60%)!

Am I missing something? Is this a bug? If not, and I am not missing something, can this be easily corrected to give an exact conversion without fudging the fuzz value?

The motivation for this is a script that I am trying to create that will map a range of colors in to some new color, by processing graylevel ranges channel-by-channel. I thought I could take the range of channel graylevels and find the midvalue and half difference both in percent and use the half difference percent as the fuzz value. But this does not convert right now exactly as above. If this will not be an accurate way to compute the fuzz, then I need to look at other approaches for the script. This seemed like the easiest and most efficient way to do this, if the fuzz value can be accurately extracted and be equivalent to the half range difference.

Note the gradient was just a test image to see how well the fuzz worked.

It appears that either the mid value of gray(50%) is not truly midway or a fuzz of 50% does not full cover all graylevels down to zero. It seems that 0 is missed in the fuzz coverage.
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: possible bug or clarification requested for -fuzz

Post by magick »

It appears that either the mid value of gray(50%) is not truly midway
Due to integer rounding, gray(50%) is not truly mid-level (32768 rather than 32767.5 for Q16) unless HRDI is enabled. However, fuzz is a real-value so it is exactly mid-level.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: possible bug or clarification requested for -fuzz

Post by fmw42 »

So if I have an arbitrary range of graylevels from g1 to g2 in percent, how do I compute the midvalue? In this case I had g1=0% and g2=100% and just did midval=0.5*(g1+g2). So how do I correct this formula for any Q to give me the correct midvalue for the specified range of graylevel percents, so that the 50% fuzz will cover the exact range of values?

And do I then presume that fuzz=0.5*abs(g1-g2) where g1 and g2 are percent will then be accurate if I can compute the proper mid value to go between g1 and g2?

Thanks.

Fred
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: possible bug or clarification requested for -fuzz

Post by anthony »

the problem here is not with the numbers. but with the rounding effects of integer values in colors.

50% gray is not perfectly 50% gray when rounded to integers (unless you use HDRI)

And -fuzz is a 50% floating point value so is perfect. The result is that as the center point is not a perfect center of the color range you will just miss either pure black or pure white. In my own test using Q16 IM black gets missed.

Code: Select all

convert -size 256x256 gradient: -fuzz 50% -fill "gray(60%)" -opaque "gray(50%)"  -unique-colors txt:-
# ImageMagick pixel enumeration: 2,1,65535,rgb
0,0: ( 0, 0, 0) #000000000000 black
1,0: (39321,39321,39321) #999999999999 grey60
If on the other hand I use the exact same command on a HDRI version of IM I get a pure grey60 result! (and yes I did do this!)

Expanding the fuzz slightly to accomidate the integer/float rounding effects is probably the best solution.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: possible bug or clarification requested for -fuzz

Post by fmw42 »

Expanding the fuzz slightly to accomidate the integer/float rounding effects is probably the best solution.
But then it may not map the exact range of graylevels I provide -- it may map too many graylevels, ones outside my specified range. That is my concern of getting this exact. If I cannot count on getting exactly the range of graylevels specified (not even off by 1 graylevel), then I probably need to look for another approach. I have one or two in mind, but they are way more complicated.

IM needs a slice function that will take a range of values and map everything within that range to a given value. See my script plm for an example (3rd picture from the left in first row for color slice and second row for graylevel slice). I am trying to do this as potentially up to 3 graylevel slices (channel-by-channel), depending upon what ranges in red, green and blue the user specifies. Sometimes the whole range of values in the channel are desired to be all be mapped to a constant, other times it is unchanged and other times only a non-full range of graylevels may be specified. It is the latter case that is the real problem, that is changing only the exact range of graylevels specified by the user.

Even better would be to duplicate my PLM script and perhaps CURVES script, so that a list of piece-wise linear (or spline interpolated) break point can be provided to generate a lut to map the graylevel values. Suggestion for future enhancement!

I was hoping to avoid replicating the approach used in PLM. But I can also do it with a composite of -black-threshold and -white-threshold. But then it requires creating a composite mask image from these two functions. However, the threshold grayvalue in one or both (not sure yet) needs to be adjusted by 1 graylevel here too
Post Reply