Test target for CLF processing accuracy tests

In the CLF VWG meeting today we discussed the need for a test image that we will use for validating CLF processing accuracy. Here are some proposed requirements for the target:

  1. Has a good range of colors, probably one or more log spaced grid/cube of some size. In my own targets, I’ve used three grids to cover normal, dark/negative, and super-bright areas separately to avoid having large numbers of extreme values that are not very helpful.
  2. Covers a wide range of values. I will propose distributing them similar to half float values.
  3. Includes +/- Infinity, +/- 0, and NaN.
  4. Includes some shallow gradients to look for banding, both visually and on a waveform monitor.
  5. Includes some solid patches large enough for easy locating/samping with an eye-dropper type tool.
  6. No IP issues, may be contributed to open source / creative commons.
  7. Not too big since it will make it easier to store/share lots of copies of it after processing through multiple CLFs.
  8. Some wide-range ramps in various pure colors (R,G,B,C,M,Y, neutral).

Would anyone like to add any other requirements? Does anyone have any targets that they could propose for this?

I am forming a sub-group to work on this deliverable, if anyone would like to join, please get in touch.


Doug Walker
CLF Implementation VWG chair

I started having a play around with this yesterday.

At this point this is a simply a discussion starter.

My focus has mainly been on the section down the bottom with single pixel high gradients. They are intended to outline the limits of a half float container, keeping in mind that we arent representing any specific colourspace, using ramps of both positive and negative values, allocated half float style (to the best of my understanding).


The sections in the middle are just a 0-1.0 cube, and that same cube reallocated to cover the same range as the ramps. (less developed)

And the top section are positive colour ramps, covering all float values.
y covering -4 -> 15
x covering 0->1023

I’m sure there is plenty wrong here, but I just wanted to get something down.

Thanks for this Alex!

Per the discussion yesterday, the equation for each row (covering all mantissa values for one exponent) is:

2**E x (1 + M/1024)

Where E varies from -14 to +15 and M varies along the row from 0 to 1023.

The denormalized values add an additional row:

2**-24 x M

Thanks again for your help!


OK, I’ve made some updates to the repo.

A per the notes there:
Since the fist CLF inmplementation meeting, a number of features have been added.

  • Subnormal value row in the full float range ramps.

  • Full range float ramps now cover full positive a negative spaces.

  • Cube has been expanded to 64x64, but not covers negative space, so no precision has been gained.

  • WRGBCYM 0.0 -> 1.0 ramps

  • WRGBCYM 0.18 -15 to +15 stops patch ramps

  • Selection of easy to sample patch squares W,R,G,B,C,M,Y,inf,-inf,nan,0,65504. (should probably be expanded on).

Something I notice when playing around with this, is that the current ephasis on covering ALL of the float range means the actual output may be a little misleading sometimes. For instance, when I compare my PureNuke ACES RRT/ODT vs a regular production OCIO version, the results look massivly different almost everywhere in the frame except the lower range ramps, and the middle of the -15 to +15 patch ramp.

And whilst this is true, the two are diverging heavily once values go over 16 or so, the reality is most production imagery will match between them.

You could argue that the whole point of this image is to show where CLFs could be doing damage outside the normal range, but I thought it was worth pointing out.

1 Like

Here is some Python code I have for writing raw half floats into an EXR. It writes them into the leftmost 1024 pixels of the first 64 rows. By my reckoning the whole of the 32nd and 64th rows are “non-numbers”, so 2048 pixels, which means it isn’t possible to have a 1920x1080 image where all the non-numbers are in the top row, and can be easily cropped, as discussed in last night’s meeting.

import numpy as np
from colour import write_image

def uint16_to_half(y):
    y_int = np.copy(np.asarray(y)).astype(np.uint16)

    return np.frombuffer(y_int.tobytes(),
                         dtype=np.float16).reshape( y_int.shape)

img = np.zeros((1080, 1920, 3), dtype=np.uint16)

for y in range(64):
    for x in range(1024):
        h = (y<<10) + x
        img[y][x] = [h, h, h]

write_image (uint16_to_half(img), 'all_half_floats.exr', bit_depth='float16')

I’m using Colour, as I know it better, and it simplifies writing an ndarray to an EXR. But I’m sure it could be done easily using OpenImageIO directly. I’m also sure @Thomas_Mansencal could tell me how to more efficiently write the sequence of uint16s into the ndarray. But as it’s a one-off test image generator, iterating over pixels isn’t really a problem.


I’ve taken another hit, trying to address some of the issues raised in the last meeting.

Biggest change is it now all sits inside 1024x1024

Nick’s spider web ramps have been added, but shrunk down to 1024 wide and 2 lines per stripe.

Inf/NaN values to first row to more easily exclude them, currently just the leftmost 2 pixel. Rest of the line is just black currently.

I’ve only got 1024 samples in the extents cube, rather than the space consuming “all float values” used in the last version. These ramps now outline the border of the cube too, which makes it easier to see where the borders are.

Added Macbeth patches in ACES2065-1 colorspace.
This has been down both with a traditional layout, as as parts of the 0.5 stop patch ramps above the pure colour 0.5 ramps.

All ramps are now horizontal so they read better on waveform monitors

Patch ramps centered around 2^-2.5 and in half stop increments

Cubes now use 65x65 so there is a centre point (0.0).

-1.0 -> 1.0 Linear Cube

-65504 -> 65504 Log allocated Cube

I’ve popped in the two standard ACES test images (DLAD and StillLife). Bit controversial, but worth talking about.

And there are a set of greyscale 0-1.0 ramps. Threw these in at the last minute and haven’t really thought them through.

  • Linear
  • sRGB
  • Gamma 2.2
  • Gamma 2.4
  • Gamma 2.6
  • PQ

Also added some text at the top. Probably needs discussion.


Great work on the updated test image @alexfry!

I notice that when incorporating my “spider web” ramps, you’ve kept the grey ramp in the middle. That’s just a linear 0-1 ramp, which already exists elsewhere in your pattern. I think I stuck it in mine because there was some spare space, and it was another thing to make the pattern more universally useful. But it seems redundant here.

Regarding the Macbeth Chart, you are using the “After November 2014” patches from @Thomas_Mansencal’s colour-science for Nuke. While close, these don’t quite match the ACES reference values on page 11 of S-2016-001. I’m not sure what the derivation of those values is. Perhaps @Alexander_Forsythe or @sdyer can comment.

Yes, I had attempted to email the table to Alex right after last meeting (but I might have sent it to the wrong email address).

I had created this doc where I calculated the ACES values of the Macbeth patches. This matches Annex D of SMPTE ST 2065-1:

(Note: These values differ slightly from ST 2065-1:2012)