Color conversion float <-> uint8

Started by
5 comments, last by Alundra 7 years ago

Hi,
I often see this method : static_cast< uint8 >( value * 255.999f )
But another method is to simply do : static_cast< uint8 >( value * 255.0f + 0.5f )
Does the two methods always gives the same accuracy of result ?
Thanks

Advertisement

Simply casting a float to an int truncates the fractional part, which is pretty much the same operation as floor (floor rounds towards negative infinity, truncation rounds towards zero, but both do the same thing to positive values).

The two common ways to do this are:

(int)round( value * 255 )
(int)floor( value * 255 + 0.5f ) aka (int)( value * 255 + 0.5f )

The first version you posted is just wrong :lol: Well, it does work if you assume that the original float only contains 8-bit accurate values, but if it's more precise than that then this version of the code will round incorrectly.
e.g. truncate( (254/255.0) * 255.999 ) == 254, which is right, but truncate( (254.4/255.0) * 255.999 ) == 255, which is incorrectly rounded upwards.

Ok, so if I understand correctly, if the float is from a uint8 converted to float then the first method will always gives good result but if it's not the case, this method is not correct.
We can also say the int( v * 255.0f + 0.5f ) is more clear on what it does.

I'd suggest you work on the problem from the other end. First define how you want floating point values mapped to uint8 values. Then write code that achieves your goal.

Getting code samples from $random websites, and then reverse engineering all the different solutions on what it might or might not do in what situation is much more work.

If you're sufficiently paranoid, you'll also try your conversion with a few critical sample values to check the code for correctness.

All started because I got issue because I simply did : static_cast< uint8 >( 255.0f * value) to convert Linear value to sRGB and then saw it needs a round to be correct.

Getting code samples from $random websites, and then reverse engineering all the different solutions on what it might or might not do in what situation is much more work.

It's always funny to see answer like that which assume things to try to lower the mood of people, I see that often in forums and it shows the closed mind of someone.
It's always better to ask question to understand than stay in the ignorance and also have multiple opinions on things even simple.

It's always funny to see answer like that which assume things to try to lower the mood of people, I see that often in forums and it shows the closed mind of someone.
It's not about having a closed mind, it's about being efficient with your time. Sure you can look for, and examine, all the different way to convert a float to an uint8, but at the end, there aren't that many ways to do it. They mostly differ in a few edge cases, that are not generally visible to the player at all. Time spent there doesn't give you a better game. If you spend that time on the core of the game, you're getting much more results from the invested time.

It's always better to ask question to understand than stay in the ignorance and also have multiple opinions on things even simple.
Asking questions is always good, but you can't do that for everything or you get nowhere, so I am merely suggesting to do that in areas where it counts, rather than in areas where the effect is negligible.

it's very relative on the way you want others do and what you say is just a populare answer to have more points, but it's understandable for the image.
The initial question was not out of sense because you always have to take care of floating point behavior all that so it's more secure to ask when you are not 100% sure of one thing.
The answer from Hodgman was interesting and I learned one thing so we are very far from waste our time here, that shows the danger of the first method.

This topic is closed to new replies.

Advertisement