JuliaGraphics / ColorTypes.jl

Basic color definitions and traits
Other
77 stars 35 forks source link

[RFC/WIP] Update README.md #250

Closed kimikage closed 3 months ago

kimikage commented 3 years ago

This is a proposed update based on the changes planned for ColorTypes v0.12. (see PR #251) I think the update should be merged at the final stage of the releasing, since the documentation for ColorTypes (i.e. README.md) is always published in the development. On the other hand, we can apply the parts which are not related to the changes in v0.12 successively.

The important thing is to clarify the default colorspace for YIQ and YCbCr.

xref: https://github.com/JuliaGraphics/Colors.jl/issues/453 xref: https://discourse.julialang.org/t/what-should-the-default-color-space-for-ycbcr-be/60874

Closes #10, Closes #30

codecov[bot] commented 3 years ago

Codecov Report

Merging #250 (07f2c51) into master (238ef06) will not change coverage. The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##           master     #250   +/-   ##
=======================================
  Coverage   82.49%   82.49%           
=======================================
  Files           8        8           
  Lines         737      737           
=======================================
  Hits          608      608           
  Misses        129      129           

Continue to review full report at Codecov.

Legend - Click here to learn more Δ = absolute <relative> (impact), ø = not affected, ? = missing data Powered by Codecov. Last update 238ef06...07f2c51. Read the comment docs.

kimikage commented 3 years ago

Default color space and scaling for YCbCr

The transfer function here refers to the one used in the RGB<-->YCbCr conversions. Note that it does not indicate the property of the RGB colorspace specified by the standards (e.g. ITU-R Recommendation BT.709).

Candidate Color primaries Transfer func. (gamma) Matrix Luma range Chroma range
status quo 8-bit sRGB/Rec.709 - Rec.601 [16, 235] [16, 240]
normalized (a) sRGB/Rec.709 - Rec.601 [0.06, 0.92] [-0.44, 0.44]
normalized (b) sRGB/Rec.709 - Rec.601 [0.06, 0.92] [0.06, 0.94]
JPEG 8-bit sRGB/Rec.709 - Rec.601 [0, 255] [0, 255]
JPEG (a) sRGB/Rec.709 - Rec.601 [0, 1] [-0.5, 0.5]
JPEG (b) sRGB/Rec.709 - Rec.601 [0, 1] [0, 1]
sYCC w/o correction 8-bit sRGB/Rec.709 - Rec.601 [0, 255] [0, 255]
sYCC w/o correction (a) sRGB/Rec.709 - Rec.601 [0, 1] [-0.5, 0.5]
sYCC w/o correction (b) sRGB/Rec.709 - Rec.601 [0, 1] [0, 1]
sYCC w/ correction 8-bit sRGB/Rec.709 w/ measure correction Rec.601 [3.2, 255] [0, 255]
sYCC w/ correction (a) sRGB/Rec.709 w/ measure correction Rec.601 [0.0125, 1] [-0.5, 0.5]
sYCC w/ correction (b) sRGB/Rec.709 w/ measure correction Rec.601 [0.0125, 1] [0, 1]
(linearRGB) Rec.709 8-bit sRGB/Rec.709 - Rec.709 [16, 235] [16, 240]
(linearRGB) Rec.709 (a) sRGB/Rec.709 - Rec.709 [0.06, 0.92] [-0.44, 0.44]
(linearRGB) Rec.709 (b) sRGB/Rec.709 - Rec.709 [0.06, 0.92] [0.06, 0.94]
(sRGB) Rec.709 8-bit sRGB/Rec.709 sRGB (~2.2) Rec.709 [16, 235] [16, 240]
(sRGB) Rec.709 (a) sRGB/Rec.709 sRGB (~2.2) Rec.709 [0.06, 0.92] [-0.44, 0.44]
(sRGB) Rec.709 (b) sRGB/Rec.709 sRGB (~2.2) Rec.709 [0.06, 0.92] [0.06, 0.94]
Rec.709 8-bit sRGB/Rec.709 Rec.709 (~1.9) Rec.709 [16, 235] [16, 240]
Rec.709 (a) sRGB/Rec.709 Rec.709 (~1.9) Rec.709 [0.06, 0.92] [-0.44, 0.44]
Rec.709 (b) sRGB/Rec.709 Rec.709 (~1.9) Rec.709 [0.06, 0.92] [0.06, 0.94]
Rec.1886 10-bit sRGB/Rec.709 Rec.1886 (~2.4) Rec.709 [64, 940] [64, 960]
Rec.1886 (a) sRGB/Rec.709 Rec.1886 (~2.4) Rec.709 [0.06, 0.92] [-0.44, 0.44]
Rec.1886 (b) sRGB/Rec.709 Rec.1886 (~2.4) Rec.709 [0.06, 0.92] [0.06, 0.94]

Other possible candidates are Rec.601 and Rec.2020, but I don't think they are good because their color primaries are different from sRGB. There are also some weird profiles which claim to be "Rec.709" but use the gamma of 2.2. Of course, they only make things worse. :sweat_smile: (The meaning is different from that of "(sRGB) Rec.709" above. The goal is the same, though.)

I also don't like the encoding for 8-bit. It makes sense within UInt8. The relaxation to YCbCr{T <: Fractional} can be done in v0.12, but The relaxation to YCbCr{T <: Real} should wait until v0.13. I recommend keeping the status quo "if" there is no support for scaling changes.

kimikage commented 3 years ago

Default color space for YIQ

Candidate Color primaries Transfer func. (gamma) Setup
status quo sRGB - 0 IRE
sRGB w/o setup sRGB sRGB (~2.2) 0 IRE
sRGB w/ setup sRGB sRGB (~2.2) 7.5 IRE
SMPTE C w/o setup SMPTE 170M SMPTE 170M (~1.9) 0 IRE
NTSC (1953) w/o setup NTSC (1953) NTSC (2.2) 0 IRE
NTSC (1953) w/ setup NTSC (1953) NTSC (2.2) 7.5 IRE

NTSC (1953) is sometimes used as a reference for color gamut coverage, but I don't think it is used in an actual video signal anymore.
SMPTE C (SMPTE 170M) is close to sRGB, so we could either ignore the difference or apply a simple correction.

Adding the setup of 7.5 IRE means that areas where Y < 0.075 will be blacked out in RGB space. Perceptually, the impact of the setup is minor, but this is troubling given that YIQ is used in ImageContrastAdjustment. :confused: xref: https://github.com/JuliaImages/ImageContrastAdjustment.jl/issues/48

Edit: I don't have enough knowledge about SMPTE 170M, but it seems that at least in SMPTE 170M-2004, the setup is applied after the RGB-->YIQ conversion is done. In other words, if SMPTE 170M is selected, no setup is required (i.e. 0 IRE).

Also, if it involves changing color primaries, it does not directly matter what the transfer function is, since the conversion is done in the XYZ space. sRGB --> linearRGB (sRGB) --> XYZ --> linearRGB (NTSC) --> NTSC RGB --> linearRGB (NTSC) --> YIQ

cf. https://github.com/JuliaGraphics/Colors.jl/issues/372#issuecomment-836371606

kimikage commented 3 years ago

As for YIQ, I think there are few situations where the SMPTE 170M compliant conversion is needed, so I'll keep the current "gamma-ignoring" implementation of Colors.jl and clarify the documentations.

This preserves the compatibility in ImageContrastAdjustment.jl. On the other hand, I am unhappy that the gamma is not accurately taken into account. :confused:

galenlynch commented 3 years ago

Is the status quo linear gamma? it's been a bit since I've thought about this, but I thought YCbCr was just a transformation of some RGB color space with a particular color matrix, and since most commonly used RGB color spaces use gamma (e.g. sRGB which I think is what ColorTypes.jl uses?) then that gamma goes along for the ride in a YCbCr representation of that same color space.

kimikage commented 3 years ago

You are right. In fact, I used to indicate "gamma: ~2.2" for them. ~Edit: I changed it back to the original notation. However, it is still not exact either.~ ~However, in the comparison, it is difficult to distinguish whether the transfer function of gamma 2.2 is applied like in sYCC, so I wrote "linear" to mean that the transfer function is not applied.~

kimikage commented 3 years ago

The meaning of the transfer function was clarified, and as a result, the Rec. 709 series was divided into three groups.

kimikage commented 3 months ago

Perhaps we need to come back here, but for once let's forget about it. I think this is no longer the appropriate place to discuss the YCbCr etc.