CCT and negative values

What I found myself and found confirmation by the Siggraph Video of John Daro on the official ACES YouTube channel ( is, that negative values do strange artifacts with certain operations. For example a Gaussian blur in Aftereffects can make big black splotches which (when measured by the colorpicker) are negative values. So I took John’s advice to convert to cct before such operations. And that sometimes works. But now I wonder:

Why does that help? I suppose because the negative values get clipped by the transformation to cct. So as a consequence they are lost.

So far I haven’t seen a visual problem with that, but given that the negative values where a correct result of the transform (because there where values outside the gamut of the new colorspace) the will not come back when going back from cct to linear/AP0.

So can someone shed some light upon that topic?



Converting to either ACEScc or ACEScct, which are both log based spaces, means that negative values are clipped. You cannot have values below 0 in log space. Yes you are right, they will not come back when going the other way. Though if you go into another color space smaller than ACES, you can then get negative values (outside the gamut) colors again. But that is only if you went to work in a smaller space.
Some operations also create negative numbers because of the position of the blue primary with a negative y value in XYZ. This only happens rarely though and depends on whether you had to convert between color spaces (like hue selection), this latter effect is most likely to show up as some noise in the blue channel rather than being a ‘strange artifact’.

While it is correct that a pure logarithmic function cannot code negative values, neither ACEScc nor ACEScct are pure log functions.

*ACEScc can code linear values down to about -0.00003, although it uses negative ACEScc values to do so – ACEScc zero represents a positive value approximately 7.25 stops below mid grey. The linear portion of ACEScct means that it can code any negative value, and even the 0-1 ACEScct range includes linear negatives – ACEScct zero represents approximately linear -0.007.

In an unclamped float implementation, negatives should not be clamped by a transform to and from ACEScct.

The fact that a positive ACEScct value can represent a small negative excursion in linear is the reason that performing some operations in ACEScct can reduce the likelihood of the artefacts which can result from negative values.

*I was wrong when I originally said that ACEScc can code small negative values. While the ACEScc decoding function can produce values down to -0.00003, the encoding function explicitly clamps negative values. Without the clamp, the main ACEScc function would be able to encode small negative excursions in linear. It can encode zero, which a pure log function cannot do.

In fact the ACEScc documentation (S-2014-003) says in Appendix A:

So there is some discrepancy between the document’s encoding function, which clamps, and the implementation advice to avoid clamping.

Hi Nick,

You are pointing out the right things in general. (thanks for catching mistakes yourself) I was trying to keep my answer short so the comment is just about the log spaces mentioned. They may have been encoded with negatives from ACES linear as you point out. This was purposeful. For ACEScc, all values in ACES that are negative are assigned a constant value including ‘0’.

The 7.25 stops below mid-grey figure is an effective black chosen for ACESproxy.

The ‘made lossless’ was an aspirational comment by the committee and it would be nice, however, it creates a substantial burden on implementors and depending on method chosen, there could still be problems.

The log space asked about in the original post is ACEScct, which absolutely does preserve negative values. I added my comment (which subsequently turned out to be incorrect) about ACEScc for completeness, and because you mentioned it.

I have not completely understood how negative values are preserved but i take your word that it is the way it is. :slight_smile:

Otherwise it would be a real problem as cct itself is AP1 if I remember right. And that can always produce nevative values when you come from AP0 with out of gamut (for AP1) values, right?

But what would then be a practical way to get rid of nevative values if we see artifacts while compositing?
I once tried to add an offset to the whole image, but that didn’t make a difference when applying a blur. Maybe a wrong approach.