Git Product home page Git Product logo

aces-dev's People

Contributors

aforsythe avatar balazer avatar jgoldstone avatar kelsolaar avatar kgboreham avatar nick-shaw avatar scoopxyz avatar scottdyer avatar selfshadow avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aces-dev's Issues

Homebrew's bottled CTL 1.5.2 links against non-current IlmBase (Iex)

Perhaps I'm misunderstanding how brew works, but it appears that the bottled ctl contains compiled libraries that reference obsolete compiled libraries, specifically libIex-2_1.11. Problem and workaround:

57 % brew install ctl
==> Installing dependencies for ctl: ilmbase, openexr
==> Installing ctl dependency: ilmbase
==> Downloading https://homebrew.bintray.com/bottles/ilmbase-2.2.0.yosemite.bottle.tar.gz
Already downloaded: /Library/Caches/Homebrew/ilmbase-2.2.0.yosemite.bottle.tar.gz
==> Pouring ilmbase-2.2.0.yosemite.bottle.tar.gz
🍺 /usr/local/Cellar/ilmbase/2.2.0: 347 files, 6.4M
==> Installing ctl dependency: openexr
==> Downloading https://homebrew.bintray.com/bottles/openexr-2.2.0.yosemite.bottle.tar.gz
Already downloaded: /Library/Caches/Homebrew/openexr-2.2.0.yosemite.bottle.tar.gz
==> Pouring openexr-2.2.0.yosemite.bottle.tar.gz
🍺 /usr/local/Cellar/openexr/2.2.0: 129 files, 12M
==> Installing ctl
==> Downloading https://homebrew.bintray.com/bottles/ctl-1.5.2.yosemite.bottle.tar.gz
Already downloaded: /Library/Caches/Homebrew/ctl-1.5.2.yosemite.bottle.tar.gz
==> Pouring ctl-1.5.2.yosemite.bottle.tar.gz
🍺 /usr/local/Cellar/ctl/1.5.2: 45 files, 3.9M
58 % otool -L /usr/local/lib/libIlmCtl.1.5.0.dylib
/usr/local/lib/libIlmCtl.1.5.0.dylib:
/usr/local/lib/libIlmCtl.1.5.0.dylib (compatibility version 1.5.0, current version 1.5.0)
/usr/local/lib/libIex-2_1.11.dylib (compatibility version 12.0.0, current version 12.0.0)
/usr/local/lib/libIlmThread-2_1.11.dylib (compatibility version 12.0.0, current version 12.0.0)
/usr/local/lib/libHalf.11.dylib (compatibility version 12.0.0, current version 12.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
59 % man brew
60 % brew uninstall ctl
Uninstalling /usr/local/Cellar/ctl/1.5.2... (45 files, 3.9M)
61 % brew install ctl --build-from-source
==> Downloading https://github.com/ampas/CTL/archive/ctl-1.5.2.tar.gz

################################################################## 100.0%

==> cmake .. -DCMAKE_C_FLAGS_RELEASE= -DCMAKE_CXX_FLAGS_RELEASE= -DCMAKE_INSTALL_PREFIX=/usr/local/Cellar/ctl/1.5.2 -DCMAKE_BUILD_TYPE=Release -DCMAKE_FIND_FRAMEWORK=LAST -
==> make
==> make check
==> make install
🍺 /usr/local/Cellar/ctl/1.5.2: 47 files, 3.9M, built in 38 seconds
62 % !otool
otool -L /usr/local/lib/libIlmCtl.1.5.0.dylib
/usr/local/lib/libIlmCtl.1.5.0.dylib:
/usr/local/lib/libIlmCtl.1.5.0.dylib (compatibility version 1.5.0, current version 1.5.0)
/usr/local/lib/libIex-2_2.12.dylib (compatibility version 13.0.0, current version 13.0.0)
/usr/local/lib/libIlmThread-2_2.12.dylib (compatibility version 13.0.0, current version 13.0.0)
/usr/local/lib/libHalf.12.dylib (compatibility version 13.0.0, current version 13.0.0)
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
63 %

ACEScc transforms can produce NaNs

Per Jim Houston:

So I took a look at the acesLog_to_lin function, and it pretty much blows up for any floating point input > 56.0. But also it also generates the maximum ACES half float value at only 1.46799639 as the ‘in’ value. So shouldn’t we have a input clip at one of those two values otherwise numerically it will blow up."

Incorrect matrix in utilities.ctl

Definition of CONERESPMATBRADFORD in utilities.ctl is incorrect.

Matrix should be changed to:

const float CONERESPMATBRADFORD[3][3] = {
    {0.89510, -0.75020, 0.03890},
    {0.26640, 1.71350, -0.06850},
    {-0.16140, 0.03670, 1.02960}
};

NOTE: The erroneous matrix exists only in the dev branch. If you are looking for this in your utilities.ctl you will not see it on the master.

Potential for underflow and negatives in logical tests

At points in both the ODT and RRT code, tests are occasionally performed to avoid divide by zero or negative numbers. For example, in the ODT ratio preserving tonecurve, the function checks for normRGB equal to zero and sets to a small value (1e-12). These tests should check for less than the small value, since numbers between these and zero might underflow (and aren't lifted up to 1e-9 or 1e-12 respectively). As currently written, they also could pass negative numbers.
thus:

if (normRGB = 0.0) normRGB = TINY;

would become:

if (normRGB < TINY) normRGB = TINY;

and so on.

It's also not consistent how each instance is handled currently.

Examples:

if (normRGB <= 0.0) normRGB = TINY;
if (max_chan == 0.0) max_chan = 1e-9;

should be

if (normRGB < TINY) normRGB = TINY;
if (max_chan < 1e-9) max_chan = 1e-9;

Note: This has not manifested any visible errors to date, but should be cleaned up and addressed in a future update to the code to eliminate possible artifacts.

Inconsistency in handling of 10-bit DPX/ADX data

In actual use, both the unbuild and the ACESproxy10-to-ACES CTL files would take 10-bit-integer encoded values.

The unbuild code scales its input:

// Prepare input values based on application bit depth handling 
float adx[3]; 
adx[0] = rIn * 1023.0; 
adx[1] = gIn * 1023.0; 
adx[2] = bIn * 1023.0;

However, the inverse ACESproxy transform does not.

As a result, one can use the supplied unbuild transform with ctlrender and 10-bit integral files as input straightforwardly. Not so with the ACESproxy10 conversion back to ACES.

The ACESproxy10 transform follows the formulae in S-2013-001 exactly and is a reference implementation of that transform, avoiding inclusion of any CTL lines that are application-specific to the behavior of ctlrender. On the other hand, the unbuild transform works well with ctlrender, but includes lines that if ported to another language as written could cause incorrect output because of confusion of being part of the reference transform.

These inconsistencies should be resolved.

Variable incorrectly being classified as non-varying rather than varying

From Doug Walker ...

I think I've encountered a bug in the CTL compiler where a variable is
incorrectly being classified as non-varying rather than varying. I'm
guessing the compiler makes some optimizations on non-varying variables
which are causing the error. I was wondering if you could take a quick look
at the enclosed script and offer any advice you may have? (It's only a page
of code.)

Through trial and error, I found that in order to make the script run
correctly, I need to add zero times a varying variable to another variable.
(I am using the print statement to tell whether the compiler has classified
variables as varying or non-varying.)

In the script invSeqLut.ctl, the variables in0 and in1 definitely need to be
varying but unless I do the aforementioned hack, they are apparently
classified as non-varying and as a result the first pixel evaluated is
correct but subsequent pixels are wrong. (The other script seq_lut.ctl is
just a LUT but I enclose it since the other script imports it.)

http://dl.dropbox.com/u/2184584/github_files/invSeqLut.ctl
http://dl.dropbox.com/u/2184584/github_files/seq_lut.ctl.zip

Here is some example output:

In the first run, do_hack = true. The output is correct.
ctl.eval(tmp[2:4,:])
in0 = [varying (0, 0.0109375) (1, 0.0109375)]
sol = [varying (0, 0.0316226) (1, 0.0562341)]
in0 = [varying (0, 0.0109375) (1, 0.0109375)]
sol = [varying (0, 0.0316227) (1, 0.0562341)]
in0 = [varying (0, 0.0109375) (1, 0.0109375)]
sol = [varying (0, 0.0316228) (1, 0.0562341)]
array([[ 0.0316, 0.0316, 0.0316],
[ 0.0562, 0.0562, 0.0562]], dtype=float32)

In this run, do_hack = false. Only the first value is correct.
ctl.load_module("invSeqLut")
ctl.eval(tmp[2:4,:])
ctl.load_module("invSeqLut")
ctl.eval(tmp[2:4,:])
in0 = 0.0109375
sol = [varying (0, 0.0316226) (1, 0.0502448)]
in0 = 0.0109375
sol = [varying (0, 0.0316227) (1, 0.049379)]
in0 = 0.0109375
sol = [varying (0, 0.0316228) (1, 0.0516209)]
array([[ 0.0316, 0.0316, 0.0316],
[ 0.0502, 0.0494, 0.0516]], dtype=float32)

(In the first run, in0 is the same for both pixels (as is in1) so it is
curious that the result of the second run would be wrong for these pixels,
but in general it is clear that in0 needs to be varying.)

HDR ODTs producing NaNs

The HDR ODTs seem to be producing NaNs. Example images are attached. The command lines used to generate the images are below.

ODT 4000 nits

  1. Convert lutimage to log2 shaper space
    ctlrender -ctl wgr9/aces-dev/transforms/ctl/logShaper/logShaper16i_to_aces_param.ctl -force -input_scale 1.0 -output_scale 1.0 -global_param1 aIn 1.0 -global_param1 middleGrey 0.18 -global_param1 minExposure -6.0 -global_param1 maxExposure 6.5 lutimage_33.uint16.tiff log2shaper.exr
  2. Apply RRT to log2 shaper lut image
    ctlrender -ctl wgr9/aces-dev/transforms/ctl/rrt/RRT.a1.0.0.ctl -force -input_scale 1.0 -output_scale 1.0 -global_param1 aIn 1.0 log2shaper.exr rrt.exr
  3. Apply the ODT to the log2 + RRT image
    ctlrender -ctl wgr9/aces-dev/transforms/ctl/odt/hdr_pq/ODT.Academy.P3D60_4000nits_PQ.a1.0.0.ctl -force -input_scale 1.0 -output_scale 1.0 -global_param1 aIn 1.0 rrt.exr log2Shaper.RRT.a1.0.0.Academy.P3D60_4000nits_PQ.a1.0.0.transformed.odt.exr

Github doesn't seem to like attachments that aren't PNG, Gif, or JPG, so you can grab the example images here:
https://drive.google.com/file/d/0B9y8CcBvBvWoaHJvZ2xMbFBDNTA/view?usp=sharing

HDR ODTs improperly use cinema scaling

The HDR ODTs are using a luminance-to-CV scaling with CINEMA_BLACK and
CINEMA_WHITE. These are parameters for the "cinema" tonescale and should not be used in the HDR ODTs, which use PQ to encode luminance.

Cannot do a local install

On linux, I'm trying to do a local installation, using the --prefix option to 'configure'.

Everything works cleanly, (all building / linking works!), except the final installation script assumes it can write to /ctl/modules. This should be fixed to obey the --prefix option. (probably added as the modules subdir)

make[3]: Entering directory /net/soft_scratch/users/jeremys/git/iif-dev/apps/ctlrender/src/openexr/CtlModules' make[3]: Nothing to be done forinstall-exec-am'.
test -z "/ctl/modules" || /bin/mkdir -p "/ctl/modules"
/bin/mkdir: cannot create directory /ctl': Permission denied

My installation procedure:

`iif-dev/apps/ctlrender/prereqs/ilmbase-1.0.2
./bootstrap
./configure --prefix=/net/homedirs/jeremys/ctl
make
make install

iif-dev/apps/ctlrender/prereqs/openexr-1.7.0
./bootstrap
env PKG_CONFIG_PATH=/net/homedirs/jeremys/ctl/lib/pkgconfig/ ./configure --prefix=/net/homedirs/jeremys/ctl
make
make install

iif-dev/apps/ctlrender/prereqs/jpeg-6b
./configure --prefix=/net/homedirs/jeremys/ctl
make
make install

iif-dev/apps/ctlrender/prereqs/tiff-3.8.2
make
make install`

iif-dev/apps/ctlrender/src
env PKG_CONFIG_PATH=/net/homedirs/jeremys/ctl/lib/pkgconfig/ ./configure --prefix=/net/homedirs/jeremys/ctl

Rec.709 ODT looks incorrect on consumer HDTVs

My apologies if this is a FAQ, but I searched and didn't find it addressed elsewhere.

I'm finding that the output of the ODT.Academy.Rec709_100nits_dim.a1.0.1.ctl, when displayed on a late-model consumer HDTV, is significantly different from the output of ODT.Academy.RGBmonitor_D60sim_100nits_dim.a1.0.1.ctl viewed on a PC monitor. I'm able to make them match very closely if I change the Rec709 ODT to encode using the Rec.709 OETF (item 1.2 in BT.709; also item 1.2 in Appendix 2 of BT.1886) instead of the inverse BT.1886 EOTF.

The attached images (which should be viewed on an sRGB PC monitor) are very good representations of what I'm seeing on the TV.

bt1886_on_tv
rec709_on_tv

Based on this, it seems to me that the Rec709 ODT should be using the Rec709 OETF. I understand that the standards specify a different (non-inverse) EOTF, but perhaps in practice TV manufacturers have adopted an EOTF that is intended to reproduce Rec709-encoded content?

Thanks!

Rename and update acesLog_to_lin and lin_to_acesLog transforms

"acesLog_to_lin" and "lin_to_acesLog" transforms defined in ACESlib.Transform_Common.a1.0.0.ctl and referenced in ACEScsc.ACES_to_ACEScc.a1.0.0.ctl and ACEScsc.ACEScc_to_ACES.a1.0.0.ctl should be renamed "acesCc_to_lin" and "lin_to_acesCc". The transforms should also be updated to use the formula defined in the acesCc document including compression of subnormals.

Should bpc_video_fwd be used with 709 ODT not (bpc_cinema_fwd)?

I'm not following why this line is in the 709 ODT (I was using the "Full" one and noticed it there)

float linearCV[3] = bpc_cinema_fwd( rgbPost);

I would think it would be the video one so the right luminance defaults would be used.
float linearCV[3] = bpc_video_fwd( rgbPost);

Update: April 29, Appears same issue exists with 2020 ODTs. I think should be "bpc_video_fwd" not "bpc_cinema_fwd" so that the 709 or 2020 ODT uses the proper setting for the ODT tone curve.

Best Regards,
Bill M

Method will occasionally fail (apparently at random) with a message like: // ./rrt_shaper_fwd.ctl:74: Array index out of range (index = -1291845632, array size = 8).

// BUG 1:
// Uncommenting the following results in a compilation error of:
//ImportError: Reference-counted pointer assignment failed; the left-hand and right-hand side types are incompatible (PKN3Ctl8RcObjectE, N3Ctl16SimdBinaryOpNodeE).
// const float COEFSX[ 9] = {
//    5.6648,  5.3418,  4.3937,  3.1748,  1.9663,  0.95155,  0.22244, -0.22149, -0.47615
// };
// const float KNOT_DENSX[ 8] = {
//    ( COEFSX[ 0] + COEFSX[ 1]) / 2.,
//    ( COEFSX[ 1] + COEFSX[ 2]) / 2.,
//    ( COEFSX[ 2] + COEFSX[ 3]) / 2.,
//    ( COEFSX[ 3] + COEFSX[ 4]) / 2.,
//    ( COEFSX[ 4] + COEFSX[ 5]) / 2.,
//    ( COEFSX[ 5] + COEFSX[ 6]) / 2.,
//    ( COEFSX[ 6] + COEFSX[ 7]) / 2.,
//    ( COEFSX[ 7] + COEFSX[ 8]) / 2.
// };

const float COEFS0 =  5.6648;
const float COEFS1 =  5.3418;
const float COEFS2 =  4.3937;
const float COEFS3 =  3.1748;
const float COEFS4 =  1.9663;
const float COEFS5 =  0.95155;
const float COEFS6 =  0.22244;
const float COEFS7 = -0.22149;
const float COEFS8 = -0.47615;
const float COEFS[ 9] = { COEFS0, COEFS1, COEFS2, COEFS3, COEFS4, COEFS5, COEFS6,
    COEFS7, COEFS8 };
const float KNOT_DENS[ 8] = {
    ( COEFS0 + COEFS1) / 2.,
    ( COEFS1 + COEFS2) / 2.,
    ( COEFS2 + COEFS3) / 2.,
    ( COEFS3 + COEFS4) / 2.,
    ( COEFS4 + COEFS5) / 2.,
    ( COEFS5 + COEFS6) / 2.,
    ( COEFS6 + COEFS7) / 2.,
    ( COEFS7 + COEFS8) / 2.
};

const float KNOTS[ 8] = { -3., -2.5, -2., -1.5, -1., -0.5, 0., 0.5 };
const float KNOT_DEL = 0.5;
const unsigned int LAST_KNOT = KNOTS.size - 1;
const float INDEX_MAP[ 8] = { 0., 1., 2., 3., 4., 5., 6., 7. };

const float NEG_SLOPE = 0.01;
const float HI_SLOPE = -0.5;
const float LO_SLOPE1 = 0.0254;
const float LO_BREAK1 = LO_SLOPE1 * 1e-5;
const float LO_SLOPE2 = ( -log10( LO_BREAK1) - KNOT_DENS[ 0]) / ( -5 - KNOTS[ 0]);
const float M[ 3][ 3] = {
    {  0.5, -1.0, 0.5 },
    { -1.0,  1.0, 0.0 },
    {  0.5,  0.5, 0.0 }
};

float rrt_shaper_fwd( float x)
{
    float y;
    if ( x <= 0.0)
        y = x * NEG_SLOPE;
    else if ( x <= 1e-5)
        y = x * LO_SLOPE1;
    else {
        float logh = log10( x);
        float dens;

        if ( logh <= KNOTS[ 0])
            dens = KNOT_DENS[ 0] - ( KNOTS[ 0] - logh) * LO_SLOPE2;
        else if ( logh >= KNOTS[ LAST_KNOT])
            dens = KNOT_DENS[ LAST_KNOT] + ( logh - KNOTS[ LAST_KNOT]) * HI_SLOPE;
        else {
            int j;

            // BUG 2:
            // This method will occasionally fail (apparently at random) with a message like:
            // ./rrt_shaper_fwd.ctl:74: Array index out of range (index = -1291845632, array size = 8).
            // but otherwise gives correct results.
            if ( 0) {
                j = 0;
                while ( logh > KNOTS[ j + 1]) {
                    j = j + 1;
                }
            }
            // This theoretically equivalent method always works.
            else {
                j = lookup1D( INDEX_MAP, KNOTS[ 0], KNOTS[ LAST_KNOT], logh);
            }

            float t = ( logh - KNOTS[ j]) / KNOT_DEL;
            float monomials[ 3] = { t * t, t, 1. };
            float coef_vec[ 3] = { COEFS[ j], COEFS[ j + 1], COEFS[ j + 2]};
            dens = dot_f3_f3( coef_vec, mult_f3_f33( monomials, M));
        }
        y = pow10( -dens);
    }
    return y;
}


void main( 
    input varying float rIn, 
    input varying float gIn, 
    input varying float bIn, 
    input varying float aIn, 
    output varying float rOut, 
    output varying float gOut, 
    output varying float bOut, 
    output varying float aOut
) 
{ 
    rOut = rrt_shaper_fwd( rIn);
    gOut = rrt_shaper_fwd( gIn);
    bOut = rrt_shaper_fwd( bIn);
    aOut = aIn;
}

ACES Shaper LMT negative values via OCIO?

Is anyone else getting negative values when rolling 0.0 footage through the ACES LMT Shaper to Linear?

Lowest value in the 1D LUT is 0.000175781256985, yet using ocioconvert on an EXR I see -0.01746?

Add interpolate2D to CtlLookupTable.cpp

The function should interpolate to find ZI, the values of the underlying 2-D function Z at the points XI and YI. Vectors X and Y specify the points at which the data Z is given.
Similarly to interpolate1D, this function should use linear interpolation.

Inputs: X,Y,Z,XI,YI
Outputs: ZI

Here is some rough code that should, I think, do the job. I'm not sure if the declaration, or later the calculation, of the size of the input vectors is valid.

float   
interpolate2D
    (const float X[],
     const float Y[],
     const float Z[],
     float XI,
     float YI)
{

    // Check sizes of inputs
    size_t n = sizeof(X);
    size_t m = sizeof(Y);
    size_t nZ = sizeof(Z[0]);
    size_t mZ = sizeof(Z);

    if (n != nZ)
    return 0;

    if (m != mZ)
    return 0;

    if ( (n < 1) || (m < 1) )
    return 0;

    // Find xLow and xHigh
    float xMin = X[0];      float xMax = X[n-1];
    int xLowIndex;          int xHighIndex;
    float xPercent;

    if (XI > xMin && XI < xMax) // XI is within vector X
    {
        int j = 0;
        while (XI > X[j])
        {
            j = j + 1;
            xLowIndex = j-1;
            xHighIndex = j;
        }
        xPercent = (XI - X[xLowIndex]) / (X[xHighIndex] - X[xLowIndex]);        
    }
    else if (XI <= xMin) // XI is lower than minimum of vector X, use low edge
    {
        xLowIndex = 0;
        xHighIndex = 0; 
        xPercent = 1.0;
    }
    else if (XI >= xMax) // XI higher than maximum of vector X, use high edge
    {
        xLowIndex = n-1;
        xHighIndex = n-1;   
        xPercent = 1.0;
    }
    else // XI is a NaN
    {
        return 0;
    }

    float yMin = Y[0];      float yMax = Y[m-1];
    int yLowIndex;          int yHighIndex;
    float yPercent;

    if (YI > yMin && YI < yMax) // YI is within vector Y
    {
        int j = 0;
        while (YI > Y[j]) 
        {
            j = j + 1;
            yLowIndex = j-1;
            yHighIndex = j;
        }
        yPercent = (YI - Y[yLowIndex]) / (Y[yHighIndex] - Y[yLowIndex]);
    }
    else if (YI <= yMin) // YI is lower than minimum of vector Y, use low edge
    {
        yLowIndex = 0;
        yHighIndex = 0; 
        yPercent = 1.0;
    }
    else if (YI >= yMax) // YI higher than maximum of vector Y, use high edge
    {
        yLowIndex = m-1;
        yHighIndex = m-1;   
        yPercent = 1.0;
    }
    else // YI is a NaN
    {
        return 0;
    }

float val1 = (Z[yLowIndex][xHighIndex] - Z[yLowIndex][xLowIndex]) * xPercent + Z[yLowIndex][xLowIndex];
float val2 = (Z[yHighIndex][xHighIndex] - Z[yHighIndex][xLowIndex]) * xPercent + Z[yHighIndex][xLowIndex];

return (val2 - val1) * yPercent + val1;

}

Integrate code for loading CTL modules directly from memory

Integrate code for loading CTL modules directory from memory.
Code provided by John Hurst.

diff -u -r ctl-1.4.1-orig/IlmCtl/CtlInterpreter.cpp ctl-1.4.1/IlmCtl/CtlInterpreter.cpp
--- ctl-1.4.1-orig/IlmCtl/CtlInterpreter.cpp    2006-12-14 14:43:55.000000000 -0800
+++ ctl-1.4.1/IlmCtl/CtlInterpreter.cpp 2011-11-26 15:42:19.000000000 -0800
@@ -235,17 +235,17 @@


 void
-Interpreter::loadModule (const string &moduleName)
+Interpreter::loadModule (const string &moduleName, const string &fileName, const string &moduleSource)
 {
     debug ("Interpreter::loadModule (moduleName = " << moduleName << ")");

     Lock lock (_data->mutex);
-    loadModuleRecursive (moduleName);
+    loadModuleRecursive (moduleName, fileName, moduleSource);
 }


 void
-Interpreter::loadModuleRecursive (const string &moduleName)
+Interpreter::loadModuleRecursive (const string &moduleName, const string &fileName, const string &moduleSource)
 {
     debug ("Interpreter::loadModuleRecursive "
       "(moduleName = " << moduleName << ")");
@@ -256,25 +256,45 @@
    return;
     }

+    Module *module = 0;
+    LContext *lcontext = 0;
+    istream *input = 0;
+    string realFileName = fileName.empty() ? findModule (moduleName) : fileName;
+
     //
-    // Using the module search path, locate the file that contains the
-    // source code for the module.  Open the file.
+    // set up the source code string for parsing.
     //

-    string fileName = findModule (moduleName);
-    ifstream file (fileName.c_str());
-
-    if (!file)
+    if (!moduleSource.empty())
     {
-   THROW_ERRNO ("Cannot load CTL module \"" << moduleName << "\". "
-            "Opening file \"" << fileName << "\" for reading "
-            "failed (%T).");
+   debug ("\tloading from source");
+
+   stringstream *tmp_strm = new stringstream;
+   (*tmp_strm) << moduleSource;
+   input = tmp_strm;
     }
+    else
+    {
+   //
+   // Using the module search path, locate the file that contains the
+   // source code for the module.  Open the file.
+   //

-    debug ("\tloading from file \"" << fileName << "\"");
+   ifstream *tmp_strm = new ifstream;
+   tmp_strm->open (realFileName.c_str());

-    Module *module = 0;
-    LContext *lcontext = 0;
+   if (!*tmp_strm)
+   {
+       THROW_ERRNO ("Cannot load CTL module \"" << moduleName << "\". "
+                "Opening file \"" << realFileName << "\" for reading "
+                "failed (%T).");
+   }
+
+   debug ("\tloading from file \"" << realFileName << "\"");
+   input = tmp_strm;
+    }
+
+    assert(input);

     try
     {
@@ -282,9 +302,9 @@
    // Create a Module, an Lcontext and a Parser
    //

-   module = newModule (moduleName, fileName);  
+   module = newModule (moduleName, realFileName);  
    _data->moduleSet.addModule (module);
-   lcontext = newLContext (file, module, _data->symtab);
+   lcontext = newLContext (*input, module, _data->symtab);
    Parser parser (*lcontext, *this);

    //
diff -u -r ctl-1.4.1-orig/IlmCtl/CtlInterpreter.h ctl-1.4.1/IlmCtl/CtlInterpreter.h
--- ctl-1.4.1-orig/IlmCtl/CtlInterpreter.h  2006-12-12 14:59:03.000000000 -0800
+++ ctl-1.4.1/IlmCtl/CtlInterpreter.h   2011-11-26 10:18:13.000000000 -0800
@@ -87,7 +87,9 @@
     // Load a module, test if a given module has already been loaded
     //--------------------------------------------------------------

-    void       loadModule (const std::string &moduleName);
+    void       loadModule (const std::string &moduleName,
+                   const std::string &fileName = "",
+                   const std::string &moduleSource = "");
     bool       moduleIsLoaded (const std::string &moduleName) const;


@@ -159,7 +161,9 @@
                     const std::string &moduleName);

     void           loadModuleRecursive
-                   (const std::string &moduleName);
+                                    (const std::string &moduleName,
+                    const std::string &fileName = "",
+                    const std::string &moduleSource = "");

     bool           moduleIsLoadedInternal
                    (const std::string &moduleName) const;

Typo in aces_to_acesProxy10 transform

In the file “aces_to_acesProxy10.ctl” at line 50, it is currently:
aces[1] = CVmin;

but it should almost certainly be instead:
acesProxy[1] = CVmin;

The similar “aces_to_acesProxy12.ctl” file does not have this error.

"Video" ODTs might be using incorrect assumed black luminance

All the video ODTs are using the CINEMA_BLACK and CINEMA_WHITE values in the Y_2_linCV conversion.

It has been suggested that the black value used for the video ODTs should be 0.0048 (for a 10000:1 dynamic range device) instead of the CINEMA_BLACK value of 0.02 (2400:1 dynamic range).

correctness bug in ctl render

ctlrender -ctl rrt_ut11.ctl -ctl p3d60.ctl cmstestpattern_logallocation_input.exr /tmp/output_ncf.exr

There is obvious garbage in the frame, in the lower half of the image. Alex can repeat this issue.

exrimage is 32x32x32 lattice, as written out of nuke (using an inverse lg2 allocation from -8.5 to 5.0 stops)

file format version: 2, flags 0x0
channels (type chlist):
B, 32-bit floating-point, sampling 1 1
G, 32-bit floating-point, sampling 1 1
R, 32-bit floating-point, sampling 1 1
compression (type compression): zip, individual scanlines
dataWindow (type box2i): (0 0) - (1273 1266)
displayWindow (type box2i): (0 0) - (1273 1266)

Canon C300 IDT misunderstanding

I've included Canon's EOS C300 IDT Ver 1.0 for reference:
https://www.dropbox.com/sh/gq9cbwtnwlah36n/HoTRTyKWYo

First of all, I realize that the C300's IDT is not maintained here but I still think it is worth discussing. In both CTLs, after converting the 0-1 RGB input values to RGB IRE values (iR, iG, and iB), they convert the RGB IRE values using some sort of 3x19 matrix that they label ACES conversion matrix1 and then process those values through CanonLog_to_linear(float clog_ire);. The last step is transforming the scene-linear RGB values with ACES conversion matrix2. Does anyone know what is going on with "ACES conversion matrix1" and is this an appropriate label for the matrix?

// CodeValue to IRE, ire = (cv-64)/(940-64)
float iR;
float iG;
float iB;
iR = (rIn*1023 - 64) / 876;
iG = (gIn*1023 - 64) / 876;
iB = (bIn*1023 - 64) / 876;

// ACES conversion matrix1 (3x19)
float pmtx[3];

pmtx[0] =  0.963803004454899    * iR        -0.160722202570655  * iG        +0.196919198115756  * iB 
      +2.03444685639819 * iR*iG     -0.442676931451021  * iG*iB     -0.407983781537509  * iB*iR 
      -0.640703323129254    * iR*iR     -0.860242798247848  * iG*iG     +0.317159977967446  * iB*iB
      -4.80567080102966 * iR*iR*iG  +0.27118370397567   * iR*iR*iB  +5.1069005049557    * iR*iG*iG
      +0.340895816920585    * iR*iG*iB  -0.486941738507862  * iR*iB*iB  -2.23737935753692   * iG*iG*iB +1.96647555251297 * iG*iB*iB
      +1.30204051766243 * iR*iR*iR  -1.06503117628554   * iG*iG*iG  -0.392473022667378  * iB*iB*iB;

pmtx[1] =  -0.0421935892309314  * iR        +1.04845959175183   * iG        -0.00626600252090315    * iB
      -0.106438896887216    * iR*iG     +0.362908621470781  * iG*iB     +0.118070700472261  * iB*iR 
      +0.0193542539838734   * iR*iR     -0.156083029543267  * iG*iG     -0.237811649496433  * iB*iB
      +1.67916420582198 * iR*iR*iG  -0.632835327167897  * iR*iR*iB  -1.95984471387461   * iR*iG*iG
      +0.953221464562814    * iR*iG*iB  +0.0599085176294623 * iR*iB*iB  -1.66452046236246   * iG*iG*iB +1.14041188349761 * iG*iB*iB
      -0.387552623550308    * iR*iR*iR  +1.14820099685512   * iG*iG*iG  -0.336153941411709  * iB*iB*iB;

pmtx[2] = 0.170295033135028 * iR        -0.0682984448537245 * iG        +0.898003411718697  * iB
      +1.22106821992399 * iR*iG     +1.60194865922925   * iG*iB     +0.377599191137124  * iB*iR
      -0.825781428487531    * iR*iR     -1.44590868076749   * iG*iG     -0.928925961035344  * iB*iB
      -0.838548997455852    * iR*iR*iG  +0.75809397217116   * iR*iR*iB  +1.32966795243196   * iR*iG*iG
      -1.20021905668355 * iR*iG*iB  -0.254838995845129  * iR*iB*iB  +2.33232411639308   * iG*iG*iB -1.86381505762773 * iG*iB*iB
      +0.111576038956423    * iR*iR*iR  -1.12593315849766   * iG*iG*iG  +0.751693186157287  * iB*iB*iB;

// Canonlog to linear 
float lin[3];

lin[0] = CanonLog_to_linear( pmtx[0]);
lin[1] = CanonLog_to_linear( pmtx[1]);
lin[2] = CanonLog_to_linear( pmtx[2]);

// ACES conversion matrix2
float aces[3];

aces[0] =  Clip(0.566996399   * lin[0]  +0.365079418 * lin[1] + 0.067924183 * lin[2]);
aces[1] =  Clip(0.070901044   * lin[0]  +0.880331008 * lin[1] + 0.048767948 * lin[2]);
aces[2] =  Clip(0.073013542   * lin[0]  -0.066540862 * lin[1] + 0.99352732  * lin[2]);

rOut = aces[0];
gOut = aces[1];
bOut = aces[2];
aOut = aIn;

DCDM RDT Clips XYZ values incorrectly

rdt_dcdm.ctl currently clips XYZ values to 0-1 range.

// Clip  data to range zero to one
XYZ[0] = clip_0_to_1( XYZ[0] );     
XYZ[1] = clip_0_to_1( XYZ[1] );     
XYZ[2] = clip_0_to_1( XYZ[2] );

This is incorrect as XYZ values should be allowed to range over 1.0.
The XYZ values less than 0 should be clipped to 0.

Rec709 ODT EOTF error

The current Rec709 ODT crushes blacks. The Rec709 ODT was intended to target the recommendation in Appendix 1 of ITU-R BT.1886.

Currently this code reads:

// ITU Proposal EOTF
const float gamma = 2.4;
float aa = pow( 1.0, ( 1.0 / gamma)) - pow( 0.0005, ( 1.0 / gamma));
float bb = pow( 0.0005, ( 1.0 / gamma));

The screen luminance for black should be set to 0.0 to target a CRT with a contrast ratio of ~2000:1. The code is also unclear because screen luminance for black and white are not defined as constants. I recommend the proposed code below:

// Per ITU-R BT.1886 EOTF
const float GAMMA = 2.4;
const float L_B = 0.000;    // screen luminance for black
const float L_W = 1.0;      // screen luminance for white
  // Note: L_B and L_W may be modified to luminance of an actual CRT.
  // Per RECOMMENDATION ITU-R BT.1886 - Appendix 1. L_B has been set to 0.0
  // targeting a CRT with a contrast ratio of 2000:1.   
const float A = pow( pow( L_W, ( 1.0 / GAMMA)) - pow( L_B, ( 1.0 / GAMMA)), GAMMA);
const float B = pow( L_B, ( 1.0 / GAMMA)) / ( pow( L_W, ( 1.0 / GAMMA)) - pow( L_B, (1.0/GAMMA))); 

Segmentation Fault from declaration of a const using values from chromaticities data type

The follow examples cause a segmentation fault


/* ============ CONSTANTS ============ */

const Chromaticities ACESChromaticities =
{
    { 0.73470,  0.26530},
    { 0.00000,  1.00000},
    { 0.00010, -0.07700},
    { 0.32168,  0.33767}
};

// Declare a const - No Seg Fault
// const float WHITE[3] = {0.32168, 0.33767, 1.0};

// Declare a const using values from Chromaticities data type and a float - Seg Fault
const float WHITE[3] = {ACESChromaticities.white[0], ACESChromaticities.white[1], 1.0};

// Declare a const using values pulled from Chromaticities data type without an additional float - Seg Fault
// const float WHITE[2] = {ACESChromaticities.white[0], ACESChromaticities.white[1]};

// Declare a const from floats pulled from Chromaticities placed into a float before the creation of the final array - Seg Fault
// const float WHITE_x = ACESChromaticities.white[0];
// const float WHITE_y = ACESChromaticities.white[1];
// const float WHITE[2] = {WHITE_x, WHITE_y};


/* ============ ODT - Main Algorithm ============ */
void main
(  
    input varying float rIn,
    input varying float gIn,
    input varying float bIn,
    input varying float aIn,
    output varying float rOut,
    output varying float gOut,
    output varying float bOut,
    output varying float aOut)

{
    // Do the same things here and no seg fault
    // float WHITE[3] = {0.32168, 0.33767, 1.0};

    // float WHITE[3] = {ACESChromaticities.white[0], ACESChromaticities.white[1], 1.0};

    // float WHITE[2] = {ACESChromaticities.white[0], ACESChromaticities.white[1]};

    // float WHITE_x = ACESChromaticities.white[0];
    // float WHITE_y = ACESChromaticities.white[1];
    // float WHITE[2] = {WHITE_x, WHITE_y};

    print(WHITE[0], WHITE[1]);

}

CTL version synchronization

The version of CTL used within ctlrender may not be in synchronization with the official CTL libraries. These differences should be reconciled pushing useful new features back to the main CTL source.

ImportError: Reference-counted pointer assignment failed; the left-hand and right-hand side types are incompatible (PKN3Ctl8RcObjectE, N3Ctl16SimdBinaryOpNodeE).

// BUG 1:
// Uncommenting the following results in a compilation error of:
//ImportError: Reference-counted pointer assignment failed; the left-hand and right-hand side types are incompatible (PKN3Ctl8RcObjectE, N3Ctl16SimdBinaryOpNodeE).
// const float COEFSX[ 9] = {
//    5.6648,  5.3418,  4.3937,  3.1748,  1.9663,  0.95155,  0.22244, -0.22149, -0.47615
// };
// const float KNOT_DENSX[ 8] = {
//    ( COEFSX[ 0] + COEFSX[ 1]) / 2.,
//    ( COEFSX[ 1] + COEFSX[ 2]) / 2.,
//    ( COEFSX[ 2] + COEFSX[ 3]) / 2.,
//    ( COEFSX[ 3] + COEFSX[ 4]) / 2.,
//    ( COEFSX[ 4] + COEFSX[ 5]) / 2.,
//    ( COEFSX[ 5] + COEFSX[ 6]) / 2.,
//    ( COEFSX[ 6] + COEFSX[ 7]) / 2.,
//    ( COEFSX[ 7] + COEFSX[ 8]) / 2.
// };

const float COEFS0 =  5.6648;
const float COEFS1 =  5.3418;
const float COEFS2 =  4.3937;
const float COEFS3 =  3.1748;
const float COEFS4 =  1.9663;
const float COEFS5 =  0.95155;
const float COEFS6 =  0.22244;
const float COEFS7 = -0.22149;
const float COEFS8 = -0.47615;
const float COEFS[ 9] = { COEFS0, COEFS1, COEFS2, COEFS3, COEFS4, COEFS5, COEFS6,
    COEFS7, COEFS8 };
const float KNOT_DENS[ 8] = {
    ( COEFS0 + COEFS1) / 2.,
    ( COEFS1 + COEFS2) / 2.,
    ( COEFS2 + COEFS3) / 2.,
    ( COEFS3 + COEFS4) / 2.,
    ( COEFS4 + COEFS5) / 2.,
    ( COEFS5 + COEFS6) / 2.,
    ( COEFS6 + COEFS7) / 2.,
    ( COEFS7 + COEFS8) / 2.
};

const float KNOTS[ 8] = { -3., -2.5, -2., -1.5, -1., -0.5, 0., 0.5 };
const float KNOT_DEL = 0.5;
const unsigned int LAST_KNOT = KNOTS.size - 1;
const float INDEX_MAP[ 8] = { 0., 1., 2., 3., 4., 5., 6., 7. };

const float NEG_SLOPE = 0.01;
const float HI_SLOPE = -0.5;
const float LO_SLOPE1 = 0.0254;
const float LO_BREAK1 = LO_SLOPE1 * 1e-5;
const float LO_SLOPE2 = ( -log10( LO_BREAK1) - KNOT_DENS[ 0]) / ( -5 - KNOTS[ 0]);
const float M[ 3][ 3] = {
    {  0.5, -1.0, 0.5 },
    { -1.0,  1.0, 0.0 },
    {  0.5,  0.5, 0.0 }
};

float rrt_shaper_fwd( float x)
{
    float y;
    if ( x <= 0.0)
        y = x * NEG_SLOPE;
    else if ( x <= 1e-5)
        y = x * LO_SLOPE1;
    else {
        float logh = log10( x);
        float dens;

        if ( logh <= KNOTS[ 0])
            dens = KNOT_DENS[ 0] - ( KNOTS[ 0] - logh) * LO_SLOPE2;
        else if ( logh >= KNOTS[ LAST_KNOT])
            dens = KNOT_DENS[ LAST_KNOT] + ( logh - KNOTS[ LAST_KNOT]) * HI_SLOPE;
        else {
            int j;

            // BUG 2:
            // This method will occasionally fail (apparently at random) with a message like:
            // ./rrt_shaper_fwd.ctl:74: Array index out of range (index = -1291845632, array size = 8).
            // but otherwise gives correct results.
            if ( 0) {
                j = 0;
                while ( logh > KNOTS[ j + 1]) {
                    j = j + 1;
                }
            }
            // This theoretically equivalent method always works.
            else {
                j = lookup1D( INDEX_MAP, KNOTS[ 0], KNOTS[ LAST_KNOT], logh);
            }

            float t = ( logh - KNOTS[ j]) / KNOT_DEL;
            float monomials[ 3] = { t * t, t, 1. };
            float coef_vec[ 3] = { COEFS[ j], COEFS[ j + 1], COEFS[ j + 2]};
            dens = dot_f3_f3( coef_vec, mult_f3_f33( monomials, M));
        }
        y = pow10( -dens);
    }
    return y;
}


void main( 
    input varying float rIn, 
    input varying float gIn, 
    input varying float bIn, 
    input varying float aIn, 
    output varying float rOut, 
    output varying float gOut, 
    output varying float bOut, 
    output varying float aOut
) 
{ 
    rOut = rrt_shaper_fwd( rIn);
    gOut = rrt_shaper_fwd( gIn);
    bOut = rrt_shaper_fwd( bIn);
    aOut = aIn;
}

Rename Sony IDTs

Sony IDTs tagged with the camera name should be renamed as SLog1 SGamut, SLog2 SGamut

Attach ctlrender prereqs to their source using submodules?

It seems like there may be benefit to attaching the source code for ctlrender dependancies to their source repositories. This may be doable with git submodules. We should consider the pros and cons of this approach in implement in appropriate.

License Confirmation?

I'd like to use portions of the Python configuration builders in the OpenColorIO ACES configurations repository, but there is no attached license for this.

Confirmation that the broad license in this parent repository applies to @hpd's ACES official configurations?

Broken relation between aces_to_acesLog16i output and acesLog16i_to_aces input

While playing with some acesLog transformations I found a problem acesLog16i_to_aces and aces_to_acesLog16i ctl files. The last converts aces to logarithmic values in the range of 0.0 to 1.0 which seem reasonable for me when looking at the way 16 bit tiffs are written. However the reverse transform (acesLog16i_to_aces) expects values in the range 0 to 65535 (max for 16 bit integer).

More analysis on this on the Google group: https://groups.google.com/forum/#!topic/academyaces/VD7Yd0Yh7Sg

Reference images folders are lowercase in Dropbox zip file

This is a nitpick, but the reference images zip file that's hosted on Dropbox contains some lowercase folder names: "aces", "lmt", "oces", "odt", "rrt". These don't match the uppercase Dropbox folders, which are also listed in images/README.md.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.