Review: Lut1D optimization


Jeremy Selan <jeremy...@...>
 

On Lut loading, 1D luts are checked to determine if the underlying
transform represents 'identity'. If so, they are skipped during op
generation. This is particularly useful when working with 3D luts
that have shaper luts, which are often left as identity.

This check is added to the lut1d-finalize call, which takes a
'tolerance' as an arg as the underlying file quantization is file
dependent.

Commits:
177bf402f6ff95ba70224aa4466e7773c5a89f96

-- Jeremy


Rod Bogart <bog...@...>
 

Is this semantically correct if the presence of the 1D lut also
triggers clipping to 0-1? Is there now a missing clamp?

RGB

On Wed, Nov 10, 2010 at 1:56 PM, Jeremy Selan <jeremy...@gmail.com> wrote:
On Lut loading, 1D luts are checked to determine if the underlying
transform represents 'identity'.  If so, they are skipped during op
generation.  This is particularly useful when working with 3D luts
that have shaper luts, which are often left as identity.

This check is added to the lut1d-finalize call, which takes a
'tolerance' as an arg as the underlying file quantization is file
dependent.

Commits:
177bf402f6ff95ba70224aa4466e7773c5a89f96

-- Jeremy


Jeremy Selan <jeremy...@...>
 

Man, I can't get anything past you guys! :)

The clamp was omitted on purpose, but I could probably be convinced
either way on this issue.*

If this code were inside a compiler, there would be no discussion -
clamp would be the only correct answer.

But ... in the context of writing a color processing library I would
propose that we have a bit of leeway here. I tend to have a strong
distaste for proactively clamping outputs. Why destroy data if you
don't need to? Who is to say that the extra data (previously
scheduled to be clamped) couldn't prove useful further down the
pipeline in certain circumstances? Clamping is easy to add
downstream if/when needed. I.e., if a subsequent image processing
operation depends on a clamped input in order to produce sensible
results, it can can always do it at that time. And if it's not
needed, even better!

Our implementation of ASC CDL SOP already does this.

// out = clamp( (in * slope) + offset ) ^ power
// Note: the clamping portion of the CDL is only applied if
// a non-identity power is specified.

The same rationale applies. The CDL transformation math strictly
requires a clamp between [0,1], making it useless on HDR data.
However, in practice many portions of the math (gain, sat) work great
on HDR data so it seems unnecessary to always clamp the output. We
thus only clamp if the exponent potion is specified, which was the
intent as specified in the CDL docs).


The downside of this approach (in both the lut1d case, and the cdl
case) is that if someone ends up relying on either of these behaviors,
they are in a semi-precarious position. I.e., their configuration is
sitting with magic numbers at certain values that happen to not
introduce this clamping, and this behavior will probably be
discontinuous (unintuitive?) over the parameter space. Picture an
animating CDL exponent, where it goes from [0.95, 1.05]. For some
portion of the range there will be clamping, then no clamping, then
clamping again.

I agree this is not ideal, and that a sensible individual may prefer
the alternative, but this downside is a price I'm inclined to pay for
the benefit of preserving data in the commoner cases.

-- Jeremy


*(Technically the clamped range is not 0,1 but instead
[lut1d.from_min, lut1d.from_max] but this is inconsequential to the
overall point).

On Wed, Nov 10, 2010 at 3:14 PM, Rod Bogart <bog...@gmail.com> wrote:
Is this semantically correct if the presence of the 1D lut also
triggers clipping to 0-1?  Is there now a missing clamp?

RGB

On Wed, Nov 10, 2010 at 1:56 PM, Jeremy Selan <jeremy...@gmail.com> wrote:
On Lut loading, 1D luts are checked to determine if the underlying
transform represents 'identity'.  If so, they are skipped during op
generation.  This is particularly useful when working with 3D luts
that have shaper luts, which are often left as identity.

This check is added to the lut1d-finalize call, which takes a
'tolerance' as an arg as the underlying file quantization is file
dependent.

Commits:
177bf402f6ff95ba70224aa4466e7773c5a89f96

-- Jeremy


Rod Bogart <bog...@...>
 

I guess my preference would be to allow someone to ask for
optimization or not. In the glorious future when OCIO is involved in
the creation of every pixel in every movie, the animated CTL example
may be rather common, and an option to avoid clever internal
heuristics might be a good debugging and processing tool.

RGB

On Wed, Nov 10, 2010 at 4:15 PM, Jeremy Selan <jeremy...@gmail.com> wrote:
Man, I can't get anything past you guys!   :)

The clamp was omitted on purpose, but I could probably be convinced
either way on this issue.*

If this code were inside a compiler, there would be no discussion -
clamp would be the only correct answer.

But ... in the context of writing a color processing library I would
propose that we have a bit of leeway here.  I tend to have a strong
distaste for proactively clamping outputs. Why destroy data if you
don't need to?  Who is to say that the extra data (previously
scheduled to be clamped) couldn't prove useful further down the
pipeline in certain circumstances?   Clamping is easy to add
downstream if/when needed.  I.e., if a subsequent image processing
operation depends on a clamped input in order to produce sensible
results, it can can always do it at that time.  And if it's not
needed, even better!

Our implementation of ASC CDL SOP already does this.

// out = clamp( (in * slope) + offset ) ^ power
// Note: the clamping portion of the CDL is only applied if
// a non-identity power is specified.

The same rationale applies.   The CDL transformation math strictly
requires a clamp between [0,1], making it useless on HDR data.
However, in practice many portions of the math (gain, sat) work great
on HDR data so it seems unnecessary to always clamp the output.  We
thus only clamp if the exponent potion is specified, which was the
intent as specified in the CDL docs).


The downside of this approach (in both the lut1d case, and the cdl
case) is that if someone ends up relying on either of these behaviors,
they are in a semi-precarious position.  I.e., their configuration is
sitting with magic numbers at certain values that happen to not
introduce this clamping, and this behavior will probably be
discontinuous (unintuitive?) over the parameter space.   Picture an
animating CDL exponent, where it goes from [0.95, 1.05].  For some
portion of the range there will be clamping, then no clamping, then
clamping again.

I agree this is not ideal, and that a sensible individual may prefer
the alternative, but this downside is a price I'm inclined to pay for
the benefit of preserving data in the commoner cases.

-- Jeremy


*(Technically the clamped range is not 0,1 but instead
[lut1d.from_min, lut1d.from_max] but this is inconsequential to the
overall point).


On Wed, Nov 10, 2010 at 3:14 PM, Rod Bogart <bog...@gmail.com> wrote:
Is this semantically correct if the presence of the 1D lut also
triggers clipping to 0-1?  Is there now a missing clamp?

RGB

On Wed, Nov 10, 2010 at 1:56 PM, Jeremy Selan <jeremy...@gmail.com> wrote:
On Lut loading, 1D luts are checked to determine if the underlying
transform represents 'identity'.  If so, they are skipped during op
generation.  This is particularly useful when working with 3D luts
that have shaper luts, which are often left as identity.

This check is added to the lut1d-finalize call, which takes a
'tolerance' as an arg as the underlying file quantization is file
dependent.

Commits:
177bf402f6ff95ba70224aa4466e7773c5a89f96

-- Jeremy


Jeremy Selan <jeremy...@...>
 

That's fair to add it as an option. I'll add it as an official TODO,
and will implement it once we have a few more examples of this type.

I'm not sure if this will be a transform specific option, or a
configuration level setting. (I could forsee if this comes up often
to have an optimization-level hint globally, which other blocks would
obey as well). I think if we're going to allow for customized
optimization levels, having one big switch that controlled all similar
settings would be much simpler to understand.

-- Jeremy

On Thu, Nov 11, 2010 at 3:25 PM, Rod Bogart <bog...@gmail.com> wrote:
I guess my preference would be to allow someone to ask for
optimization or not.  In the glorious future when OCIO is involved in
the creation of every pixel in every movie, the animated CTL example
may be rather common, and an option to avoid clever internal
heuristics might be a good debugging and processing tool.

RGB

On Wed, Nov 10, 2010 at 4:15 PM, Jeremy Selan <jeremy...@gmail.com> wrote:
Man, I can't get anything past you guys!   :)

The clamp was omitted on purpose, but I could probably be convinced
either way on this issue.*

If this code were inside a compiler, there would be no discussion -
clamp would be the only correct answer.

But ... in the context of writing a color processing library I would
propose that we have a bit of leeway here.  I tend to have a strong
distaste for proactively clamping outputs. Why destroy data if you
don't need to?  Who is to say that the extra data (previously
scheduled to be clamped) couldn't prove useful further down the
pipeline in certain circumstances?   Clamping is easy to add
downstream if/when needed.  I.e., if a subsequent image processing
operation depends on a clamped input in order to produce sensible
results, it can can always do it at that time.  And if it's not
needed, even better!

Our implementation of ASC CDL SOP already does this.

// out = clamp( (in * slope) + offset ) ^ power
// Note: the clamping portion of the CDL is only applied if
// a non-identity power is specified.

The same rationale applies.   The CDL transformation math strictly
requires a clamp between [0,1], making it useless on HDR data.
However, in practice many portions of the math (gain, sat) work great
on HDR data so it seems unnecessary to always clamp the output.  We
thus only clamp if the exponent potion is specified, which was the
intent as specified in the CDL docs).


The downside of this approach (in both the lut1d case, and the cdl
case) is that if someone ends up relying on either of these behaviors,
they are in a semi-precarious position.  I.e., their configuration is
sitting with magic numbers at certain values that happen to not
introduce this clamping, and this behavior will probably be
discontinuous (unintuitive?) over the parameter space.   Picture an
animating CDL exponent, where it goes from [0.95, 1.05].  For some
portion of the range there will be clamping, then no clamping, then
clamping again.

I agree this is not ideal, and that a sensible individual may prefer
the alternative, but this downside is a price I'm inclined to pay for
the benefit of preserving data in the commoner cases.

-- Jeremy


*(Technically the clamped range is not 0,1 but instead
[lut1d.from_min, lut1d.from_max] but this is inconsequential to the
overall point).


On Wed, Nov 10, 2010 at 3:14 PM, Rod Bogart <bog...@gmail.com> wrote:
Is this semantically correct if the presence of the 1D lut also
triggers clipping to 0-1?  Is there now a missing clamp?

RGB

On Wed, Nov 10, 2010 at 1:56 PM, Jeremy Selan <jeremy...@gmail.com> wrote:
On Lut loading, 1D luts are checked to determine if the underlying
transform represents 'identity'.  If so, they are skipped during op
generation.  This is particularly useful when working with 3D luts
that have shaper luts, which are often left as identity.

This check is added to the lut1d-finalize call, which takes a
'tolerance' as an arg as the underlying file quantization is file
dependent.

Commits:
177bf402f6ff95ba70224aa4466e7773c5a89f96

-- Jeremy