16-bit RGB flooring

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
djkprojects
Posts: 21
Joined: 2012-07-06T04:44:48-07:00
Authentication code: 13

16-bit RGB flooring

Post by djkprojects »

Hello,

At first I thought it would be a trivial task but after spending two evenings trying i give up and hope somebody can help. I want to apply 3 simple operations to each pixel i.e.:

1. divide each channel value by a floating number
2. floor the result
3. multiply by a floating number

In 8 bit mode this works alright however the results in 16 bit are completely different:

Example:

The pixel in Q8 is (116, 106, 34)

Step 1. Divide each value by 64 -> (1.8125, 1.65625, 0.53125)
Step 2. Floor each value --> (1,1,0)
Step 3. Multiply each value by 85.333 --> (85.33333333333333, 85.33333333333333, 0) --> Final result (86, 86, 0)

Now in Q16 this operation obviously is not that straight forward and I can't figure out what I'm doing wrong or whether it's IM that rounds up values somewhere

I've tried scaling Q16 values down to 8bit but still getting different results:

The pixel in Q16 is (29812, 27242, 8738)

Step 1.

Code: Select all

-evaluate divide 16448 -evaluate multiply 257 --> (2, 2, 0)
The 16448 is 257 * 64

I can't understand why the B in the above result is still 0. Is IM rounding up all the values after each evaluate ?

Somebody might ask what a big deal it's only 1 level difference? Well if the channel value after flooring is equal 0 then whatever it's multiplied by it still will be 0 right?

Can somebody please advise how to can I implement these 3 steps in one command (ideally without using -fx operator)

Thanks
djkprojects
Posts: 21
Joined: 2012-07-06T04:44:48-07:00
Authentication code: 13

Re: 16-bit RGB flooring

Post by djkprojects »

OK,

I'm certainly missing something here as :

Code: Select all

-evaluate divide 16448 -evaluate multiply 16448
on RGB(116,106,34) gives RGB(128, 129, 63)

????
djkprojects
Posts: 21
Joined: 2012-07-06T04:44:48-07:00
Authentication code: 13

Re: 16-bit RGB flooring

Post by djkprojects »

Hello,

The solution to my question is:

Code: Select all

-evaluate divide 64 -fx "trunc(p*255)/255" -evaluate multiply 85.333
All this command does is 4th level posterization. The only problem with it is -fx (to floor the values) which is slow. The reason why I'm not using the built-in "-posterize" is purely the results which are not quite right to my eye 8)

I'd be curious to know if there is any other (i.e. fast) way to achieve the above

Thanks

BTW - the above command gives results identical to PS CS5 (at least in sRGB colorspace)
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: 16-bit RGB flooring

Post by fmw42 »

I believe you have to do the math on the 16-bit values and round after each step since it does not support floats only integers (unless in HDRI mode)


convert -size 1x1 xc:"rgb(116,106,34)" txt:
0,0: (29812,27242, 8738) #74746A6A2222 srgb(116,106,34)


then

convert 1color1.miff -evaluate divide 16448 -evaluate multiply 257 txt:
0,0: ( 514, 514, 257) #020202020101 srgb(2,2,1)

Now lets do the math for the Red

29812/16448=1.81 rounded to 2, then 2*257=514

But since you are doing a divide and a multiply, just combine them as a product 257/16448=0.015625

convert -size 1x1 xc:"rgb(116,106,34)" -evaluate multiply 0.015625 txt:
0,0: ( 466, 426, 137) #01D201AA0089 srgb(0.71107%,0.650034%,0.209049%)

now rounding the percents to integers we get (1,1,0)
djkprojects
Posts: 21
Joined: 2012-07-06T04:44:48-07:00
Authentication code: 13

Re: 16-bit RGB flooring

Post by djkprojects »

Hello fmw42,

Yes, I did all that - the problem is that there doesn't seem to be an easy and fast way of flooring pixel values in IM without using -fx.

It would be good if -evaluate offered more operations like those available with -fx e.g. ceil, floor, int, abs etc.

[EDIT]
BTW 've just found out that txt: is not as reliable as I thought:

When I do:

Code: Select all

convert image.jpg[1x1+0+0] -evaluate divide 16448 -evaluate multiply 257 txt:
I get:

Code: Select all

0,0: (  2,  2,  1)  #020201  srgb(2,2,1)
which is correct. Now:

Code: Select all

convert image.jpg -evaluate divide 16448 -evaluate multiply 257 image2.jpg
convert image2.jpg[1x1+0+0] txt:
gives:

Code: Select all

0,0: (  2,  2,  0)  #020200  srgb(2,2,0)
Notice the difference for B value
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: 16-bit RGB flooring

Post by fmw42 »

You need to upgrade your version of IM. On IM 6.7.8.2 Q16 Mac OSX Snow Leopard, it works consistently for me and I get

convert -size 1x1 xc:"rgb(116,106,34)" 1color1.miff
convert 1color1.miff -evaluate divide 16448 -evaluate multiply 257 1color2.miff
convert 1color2.miff txt:
# ImageMagick pixel enumeration: 1,1,65535,srgb
0,0: ( 514, 514, 257) #020202020101 srgb(2,2,1)

convert 1color2.miff[1x1+0+0] txt:
# ImageMagick pixel enumeration: 1,1,65535,srgb
0,0: ( 514, 514, 257) #020202020101 srgb(2,2,1)

From your post,

0,0: ( 2, 2, 1) #020201 srgb(2,2,1)

it looks like you are working in Q8?
djkprojects
Posts: 21
Joined: 2012-07-06T04:44:48-07:00
Authentication code: 13

Re: 16-bit RGB flooring

Post by djkprojects »

It must be a bug in my version then

Code: Select all

convert -version
Version: ImageMagick 6.7.7-2 2012-07-07 Q16 http://www.imagemagick.org

Code: Select all

convert -depth 16 image.jpg[1x1+0+0] txt:
# ImageMagick pixel enumeration: 1,1,65535,srgb
0,0: (29812,27242, 8738) #74746A6A2222 srgb(116,106,34)

I'm pretty sure that by default my IM works in Q16 as I'm not getting correct results when for example using -level with 8bit values so I need to convert them to 16b first.

Might be another issue with my version

Regardless of this I still can't figure out how to do fast flooring in IM :(

EDIT: just updated to 6.7.8 but still having same issue :?

EDIT: it appears that it's not IM version that determines in what format will be pixel values shown when doing txt but the image format itself. Just converted my jpg to 16bit tiff and values are now showing in 16bit range:

Code: Select all

convert image.tif[1x1+0+0] txt:
0,0: (29812,27242, 8738) #74746A6A2222 srgb(116,106,34)
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: 16-bit RGB flooring

Post by fmw42 »

All IM processing in Q8, Q16, Q32 without HDRI will already be integers coming from the functions. So there is no way to effectively floor them since they are already integers. So it makes no sense without HDRI to have -evaluate floor or things like that as far as I understand things.
djkprojects
Posts: 21
Joined: 2012-07-06T04:44:48-07:00
Authentication code: 13

Re: 16-bit RGB flooring

Post by djkprojects »

Well, I actually think that's just "-evaluate" (and some other operators) that rounds up results to the nearest integer after the operation otherwise it would be silly trying to guess what value should be pixel channel divided or multipled by to get an integer result and for example -fx works with floating numbers e.g.

1. Let's take a pixel value of 148 in 0-255 range as an input and scale it to Q16 ---> 38036 (R value)

Code: Select all

convert -depth 16 /WWW/html5/bird.jpg[1x1+0+0] txt:

# ImageMagick pixel enumeration: 1,1,65535,srgb
0,0: (38036,33924,25443)  #949484846363  srgb(148,132,99)
2. Divide it by 100:

Code: Select all

convert -depth 16 /WWW/html5/bird.jpg[1x1+0+0] -evaluate divide 100 txt:

# ImageMagick pixel enumeration: 1,1,65535,srgb
0,0: (  380,  339,  254)  #017C015300FE  srgb(0.579843%,0.517281%,0.387579%)
3. Let's add -fx:

Code: Select all

convert -depth 16 /WWW/html5/bird.jpg[1x1+0+0] -evaluate divide 100 -fx "p*255/255" txt:

# ImageMagick pixel enumeration: 1,1,65535,srgb
0,0: (  380,  339,  254)  #017C015300FE  srgb(0.579843%,0.517281%,0.387579%)
Nothing's changed here as all we did is multiplying and dividing by the same value so we basically multiply by 1

4. Now let's add trunc() to the fx:

Code: Select all

convert -depth 16 /WWW/html5/bird.jpg[1x1+0+0] -evaluate divide 100 -fx "trunc(p*255)/255" txt

# ImageMagick pixel enumeration: 1,1,65535,srgb
0,0: (  257,  257,    0)  #010101010000  srgb(1,1,0)
What's happened here is 380 has been scaled to 0-1 within -fx ---> 0.0057984283207446, multiplied by 255 ---> 1.4785992217899 then truncated to 1
and divided by 255 to stay in the 0-1 scale --> 0.003921568627451

If you now scale the result back to Q16 range you will get 257

And I do not have HDR enabled:

Code: Select all

identify -version

Version: ImageMagick 6.7.8-0 2012-07-14 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2012 ImageMagick Studio LLC
Features: OpenMP OpenCL
As -fx is very slow even with such a simple operation it would be good to have some fast version of it
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: 16-bit RGB flooring

Post by fmw42 »

As -fx is very slow even with such a simple operation it would be good to have some fast version of it
Agreed. But that has been on the wish list almost forever. I know, since I have had previous discussions with the IM developers. It is not as easy to do as you might think in a general way with something as user programmable and flexible as fx. However, IM is open source and you or any other programmer are free to contribute new features.

One other suggestion. I don't know if this is pertinent. But you may be able to use -function polynomial and adjust the constant term to effect something like a trunc.

see
http://www.imagemagick.org/Usage/transf ... polynomial
djkprojects
Posts: 21
Joined: 2012-07-06T04:44:48-07:00
Authentication code: 13

Re: 16-bit RGB flooring

Post by djkprojects »

Hello fmw42,

Yes, I'm aware of the way -fx operator works and that's why I think it would be easier for IM developers to extend evaluate or function operators or even create a new one that would perform basic mathematical operations like floor, trunc, abs, mod etc. without having to parse expressions like -fx does.

It also would be nice to be able to have access to other values that -fx has to e.g. lightness, brightness, saturation - this could be done using -evaluate set I suppose.

As for help - I really wouldn't mind helping in IM development - the only problem is that I don't write in C so I'm not very familiar with the language :?

Thanks for the polynomial suggestion :) It sounds like a good idea... I'll give it a try.
User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: 16-bit RGB flooring

Post by anthony »

djkprojects wrote:It also would be nice to be able to have access to other values that -fx has to e.g. lightness, brightness, saturation
Typically you convert images to HSL (or as appropriate) then use evaluate to do things with those values. Afterwards either convert back, or just -set colorspace sRGB without changing the values.
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/
Post Reply