Page 1 of 1
16-bit RGB flooring
Posted: 2012-07-12T13:40:16-07:00
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
Re: 16-bit RGB flooring
Posted: 2012-07-12T13:57:03-07:00
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)
????
Re: 16-bit RGB flooring
Posted: 2012-07-14T08:25:59-07:00
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
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)
Re: 16-bit RGB flooring
Posted: 2012-07-14T10:31:20-07:00
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)
Re: 16-bit RGB flooring
Posted: 2012-07-14T11:55:03-07:00
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
Re: 16-bit RGB flooring
Posted: 2012-07-14T13:04:37-07:00
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?
Re: 16-bit RGB flooring
Posted: 2012-07-14T13:26:09-07:00
by djkprojects
It must be a bug in my version then
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:
0,0: (29812,27242, 8738) #74746A6A2222 srgb(116,106,34)
Re: 16-bit RGB flooring
Posted: 2012-07-21T19:01:48-07:00
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.
Re: 16-bit RGB flooring
Posted: 2012-07-22T03:38:28-07:00
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
Re: 16-bit RGB flooring
Posted: 2012-07-22T11:11:15-07:00
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
Re: 16-bit RGB flooring
Posted: 2012-07-22T16:55:13-07:00
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.
Re: 16-bit RGB flooring
Posted: 2012-08-07T18:39:18-07:00
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.