AcademySoftwareFoundation / AcademySoftwareFoundation/OpenColorIO

Python API: Override Transform "+" and "-" operators as shorthand for concatenation and inversion

Open
#1,240 1 comment 0 reactions 0 assignees View on GitHub
Feature Request Needs Discussion Python
Dominant language
C++
Stars
2.1k
Forks
503
PR merge metrics
No merged PRs in 30d

Description

# Objective
Override the Transform class addition and subtraction operators to provide a convenient, intuitive, "magical" mechanism for combining and inverting transforms with a syntax similar OCIO's "Look Expression Language"

# Motivation
_Vastly_ improves the API user-experience and code intelligibility. Inspired by a feature written by @rminsk for our in-house OCIO config-authoring library. I'm the only person who knows the feature exists, and it's _really_ nice.

# The Pitch
Say you've got these three Transforms you'd like to string together:

```
lin_to_log = ColorSpaceTransform("scene_linear", "color_timing")
dailies_grade = FileTransform("dailies.ccc", cccid="$SHOT")
show_lut = FileTransform("show_lut_rec709.csp")
```

Right now, there's a **traditional** way of concatenating as a GroupTransform:
```
gt = GroupTransform()

gt.append(lin_to_log)
gt.append(dailies_grade)
gt.append(show_lut)
```

...and a **fancy** way:
```
gt = GroupTransform( [lin_to_log, dailies_grade, show_lut] )
```

Proposed is an **_extra_ fancy** way, via the Transform _addition_ operator:
```
gt = lin_to_log + dailies_grade + show_lut
```

Additionally, the Transform _subtraction_ operator would denote direction inversion:

Currently, inverting a Transform involves first determining what the inverted direction would be:
```
inv_dir = combineTransformDirections(lin_to_log.getDirection(), TRANSFORM_DIRECTION_INVERSE)
log_to_lin = lin_to_log.setDirection(inv_dir)
```
(note: the above example mutates the state of the original "lin_to_log" instance)

Sure would be nice to be able to do the following:
```
log_to_lin = -lin_to_log
```

But like Peter Falk says in Wings of Desire, "To concatenate, to invert... and if you do it together, it's fantastic":
```
# convert to working space, invert neutral grade, apply dailies grade, apply show_lut
inv_neutral_shot_look = lin_to_log - neutral_grade + dailies_grade + show_lut

# concatenate discrete inverse-shaper LUT1Ds and shaped LUT3Ds
lut1d3d = -ColorSpaceTransform("shaper_to_linear") + FileTransform("shaped_lattice.spi3d")
```

# Implementation
I can't publicly share our actual code, but I can show you guys how it works in private, and / or quickly mock up a pure python example. The basic heuristic is very straightforward:

Addition:
1. Create a new GroupTransform that concatenates the left-hand operand followed by the right-hand operand.

Subtraction:
1. Enclose the operand in a new GroupTransform, and set the GroupTransform's direction to TRANSFORM_DIR_INVERSE

In practice, there are a some considerations for reducing unnecessary nested or adjacent GroupTransforms; and "inverted" GroupTransforms are converted to "forward" GroupTransforms by recursively unpacking, "flipping", and re-packing each Transform in the sequence.

In our implementation, when our library is imported, we're actually subclassing PyOpenColorIO.Transform, overriding the operators, and injecting the modified classes back into the PyOpenColorIO namespace, which is certainly one way of going about this... I'm not much for C++, but it seems like this wouldn't take too much time or energy to implement with pybind11. If there's interest in seeing a PR, I'd be more than happy to harass @remia and @michdolan for help.

What do you guys think... too much magic? Not enough magic?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.