C++ Logo

sg13

Advanced search

Re: [SG13] Split color into separate proposal

From: Tony V E <tvaneerd_at_[hidden]>
Date: Fri, 28 Jun 2019 12:18:09 -0400
Yep.

I would separate color from pixel. There are many pixel types, less color types - we could maybe stick with one color. Such as CIE XYZ for example.

I would templatize the pixel types similar to your suggestion. Every pixel processing library I've worked on/with (at Adobe, BlackBerry, Inscriber, etc) eventually templatized the pixels. No one wants to write separate compositing functions‎ for each type. Yet you want to be able to specialize for the common types, making those fast.

Having a singular Color type, however, let's you have the 'common ground' for conversion between pixels (when you don't want to specialize the conversion for speed).

And whenever you have the user pick a colour, or do a colour fill, etc, this can be specified by a common Color _vocabulary type_, instead of a specific pixel template instantiation.

I wouldn't save an image as an array of Colors; I would pick a pixel type, but Color allows you to convert between pixel types you've never encountered before. (probably serving the same purpose as you color space and tranfer concepts, but without needing a priori knowledge of either color space in order to interoperable).

Sent from my BlackBerry portable Babbage Device
  Original Message
From: Lyberta via SG13
Sent: Friday, June 28, 2019 7:45 AM
To: sg13_at_[hidden]
Reply To: sg13_at_[hidden]
Cc: Lyberta
Subject: [SG13] Split color into separate proposal

Hi.

I've recently wanted to work with HDR video and found that most software
is really broken when it comes to color. Surely, I opened p0267r9 to see
how the color is handled and was horrified. It is making the same mistake.

It only specifies color model.
It is fixed to "float".
It doesn't specify color space.
It doesn't specify transfer function.
It doesn't support internal HDR (values outside of [0, 1] range).
It forces integers into range [0, 255].

This makes it pretty useless for professional work and contemporary
consumer video.

I think if we don't get color right (and by that I mean not make API
flexible enough), we'll doom developers into writing their own color
code and effectively ignoring the standard.

Curiously enough, p0267 mentions most properties of the color yet
forgets them when defining the "rgba_color" class.

So, what are those?

Color model
Color space
Transfer function
Bit layout

So, what are the common values of those?

Color model:
RGB
RGBA
CMYK
XYZ
YUV
LAB

Color space:
ITU-R Rec. 709
ITU-R Rec. 2020

Transfer functions:
ITU-R Rec. 709
sRGB
ITU-R Rec. 2020
ITU-R Rec. 2100 PQ (SMPTE ST 2084)
ITU-R Rec. 2100 HLG (ARIB STD-B67)
HDR10+ (SMPTE ST 2094-40)

Bit layouts:
8 bit integer per channel (various forms)
10 bit integer per channel (HDR10, HDR10+, other)
12 bit integer per channel (Rec. 2100)
16 bit integer per channel (Adobe Photoshop internally)
16 bit float per channel (GPUs)
32 bit float per channel (easiest to work with on CPU)

It's simply impossible to cram all this complexity in a simple type. We
need a different design.

It looks like different color models would really need different member
functions so we can start with a different class template for every
color model:

template <BitLayout BL, ColorSpace CS, TransferFunction TF>
class rgba_color;

Now we are getting somewhere. Notice that BitLayout, ColorSpace and
TransferFunction are concepts.

Now imagine something like this:

using srgb_rgba_color = rgba_color<f32f32f32f32, rec_709, srgb>;

This seems to be the closest approximation to rgba_color from p0267.

Now about mixing integers and floats. I've written an audio library that
does bit depth conversion automatically. It's all about providing a
"Sample" type which defines min, max, whether it should clamp and usual
arithmetic operators. It act as a "smart number" that does the right
thing. It also takes storage type and calculation type as template
parameters. It is common to store data as integers but to convert them
to floating point for the same of processing. Otherwise generic DSP
template library is impossible. As I live on the bleeding edge, I've
already conceptified my library to a degree.

So the list would look like this:

concept StorageType
concept CalculationType
concept Sample

template std::dsp::sample (I know that std::sample already exists, hence
bikeshed name, I share the sadness of Guy Davidson over std::vector that
standard library reserving good named for non math stuff).

I think we can (and probably should) base audio proposal on
std::dsp::sample too (and then maybe expose saturation arithmetic that
is required when working with signed integers) but that for another thread.

Now we can do this:

template <std::ForwardIterator I, std::dsp::Gain G>
constexpr void Amplify(I first, I last, G gain)
{
for (; first != last; ++first)
{
*first *= gain;
}
}

On integer audio this will do saturation arithmetic, same can be applied
to ranges of colors (pixels) if they are integers. Or what if iterators
return video frames? We can define operator*= for video frame that will
call operator*= on pixels that will fall back onto color that will fall
back into the sample type that Will Do The Right Thing.

Now we can write a fade in algorithm that automatically works with audio
AND video by just using proper types. For audio that requires iterators
returning frames, that is why I'm very disappointed on the current
std::audio_buffer design, but again, for another thread.

Received on 2019-06-28 11:20:02