Page MenuHome

Code cleanup: de-duplicate RGB to Grayscale conversion
AbandonedPublic

Authored by Kévin Dietrich (kevindietrich) on May 8 2014, 9:10 PM.

Details

Summary

I noticed that we have a few formulas for converting from RGB to Grayscale. Two of these formulas, rgb_to_grayscale and rgb_to_luma are actually the same, although the later offers more float precision.

I then noticed Campbell's comment about some "nonsense" with having two functions (rgb_to_grayscale and rgb_to_bw) to do the same thing but with different coefficients.
It is noted that rgb_to_grayscale is used more for compositing whilst it is rgb_to_bw that is used in the compositor! But they were kinda right, and that should be changed.
I am unable to find where the coefficients for the rgb_to_bw function come from, so if someone knows it would be good to share the knowledge. Otherwise, I propose to also remove this function and replace it with rgb_to_luma.

Some notes:

  • rgb_to_luma (and thus rgb_to_grayscale) (Rec 601): the coefficients used properly compute luminance for monitors having phosphors contemporary to the introduction of the NTSC television back in 1953. They are still appropriate for computing video luma. However, they do not accurately compute luminance for contemporary monitors. See Wikipedia article on YCbCr.
  • rgb_to_luma_y (Rec 709): these coefficients compute true CIE luminance from linear rgb and account for human perception of luminosity. The same coefficients may also be used for non-linear rgb.

After these notes/observations, it could be good to do the following:

  • remove rgb_to_bw and rgb_to_grayscale
  • replace their occurrences with rgb_to_luma_y
  • only use rgb_to_luma where the rec. 601 is used (i.e. the YCbCr node)

For now, this patch removes the rgb_to_grayscale function and replaces its occurrences with rgb_to_luma.

Some more on-exhaustive readings (if interested):
http://dcgi.felk.cvut.cz/home/cadikm/color_to_gray_evaluation/
https://en.wikipedia.org/wiki/Luma_(video)
https://en.wikipedia.org/wiki/Grayscale
http://www.rapidtables.com/convert/image/rgb-to-grayscale.htm

Diff Detail

Event Timeline

@Campbell Barton (campbellbarton) assigning you as a reviewer for now, as you made the above mentioned comment.
Also CC-ing the compositing team, just in case this patch needs to evolve.

It actually makes zero sense to use any hard coded values, as they are unique to each and every colorspace. A given OpenColorIO configuration package should override any coefficients to match the reference space.

OpenColorIO has a configuration definition of the luminance coefficients, which are accessed via

void Config::getDefaultLumaCoefs(float* rgb) const
void Config::setDefaultLumaCoefs(const float* rgb)

The luminance values are the most useful, as they yield the correct Y position for any given colorspace, and are in fact merely the Y ratio for each of the R, G, and B channels.

The float values currently in Blender are for the sRGB / 709 set of primaries at D65.

The only issue here is with the unfortunate char format buffers. I cannot be sure, but I suspect the coefficients are idealized for playback as "good enough", given that you can only apply luminance coefficients correctly on linearized RGB values. I seem to recall Poynton making a reference to this somewhere.

I modified the ocio_capi and ocio_impl files to expose the getDefaultLumaCoefs functionality. The only question is one of performance, and where to store the values as a global. Sergey is likely the person we need to chime in here, to make sure that the storage of the global values is in line with his vision of the color management system.

Great to see someone taking this to task.

I pushed a diff that is basically integrating the coefficients function of OCIO.

Untested, as it really needs to know where to store the result.

https://developer.blender.org/differential/diff/1862/#58911057

Adding @Sergey Sharybin (sergey) as reviewer.

The implementation might be trickier. As Blender is written in C, and OCIO in C++, we will most likely need to create some wrapper functions to be able to call the OCIO methods.

Also we would need to change the GLSL code accordingly.

Sergey already wrote the wrapper implementation, and the diff I linked to simply added the respective function. ;)

Damn, so that explains the name ocio-capi.

So, I should probably go to sleep now ;) (No really, it's about 7am here, and I haven't slept through the night...)

@Antonis Ryakiotakis (psy-fi), wouldn't mind having some extra eyes on such a changes.

Mine feedback will come soon.

I've done a little more hunting and can only conclude that the 0.35 red, 0.58 green, and the 0.20 blue belongs to no known primaries that I can find. They appear absolutely arbitrary and entirely out of line with Blender's internally assumed reference space based on the default OpenColorIO configs.

Further, the 601 values are absolutely wrong given the context. The coefficients that land in Blender are already in sRGB. There is no method to get 601 based primaries to the best of my knowledge, and therefore 601 weights should never be offered. Even if one uses the YCbCr node to generate 601 values, they will never land back in RGB.

I spent some time chatting with one of the lead developers of OpenColorIO and the GetLumaCoefs etc. has been depreciated. I mentioned that we require a useful way to get the coefficients and he is in the process of adding the concept of primaries to OpenColorIO.

When this lands, we can gut the Blender code of the unknown BW weights (they should be removed entirely as it stands) and properly introduce weights based on the primaries defined in the OpenColorIO config, which will likely end up being sRGB / 709 for the reference space by default.

Ultimately this patch would be wise to change all of the weights to sRGB / 709, and remove all 601 references. The correct weights for sRGB / 709 are dictated by the Y position of the primaries for each channel under the reference white (D65) are as follows:

     RED       GREEN       BLUE
X 0.4124564  0.3575761  0.1804375
Y 0.2126729  0.7151522  0.0721750
Z 0.0193339  0.1191920  0.9503041

Luminance Coefficients are the Y row being:
RED     0.2126729
GREEN   0.7151522
BLUE    0.0721750

The most prudent path forward is likely:

  1. Remove all instances of the odd BW coefficients. They are functionally wrong and totally incorrect given Blender's current design context.
  2. Remove all instances of the 601 coefficients. They are functionally wrong and totally incorrect given Blender's current design context.
  3. Replace all weights with sRGB / 709. These are currently most appropriate given Blender's current design context.
  4. Re-evaluate this as soon as the primaries support lands in OpenColorIO.

Closing as this is currently handled in a better way by @Troy Sobotka (sobotka) in D1082.