Nuke Templates

Luminance


In [ ]:
import colour

EXPRESSION_TEMPLATE = """
Expression {{
 inputs 0
 expr0 "{0}"
 expr1 "{0}"
 expr2 "{0}"
 name {1}_luminance_Expression
 selected true
 xpos {2}
 ypos 0
}}"""[1:-1]

SWITCH_TEMPLATE = """
Switch {{
 inputs {0}
 which {{{{colourspace_Pulldown_Choice}}}}
 name colourspace_Switch
 selected true
 xpos 0
 ypos 100
 addUserKnob {{20 User}}
 addUserKnob {{4 colourspace_Pulldown_Choice l Colourspace M {1}}}
}}
"""[1:-1]


def luminance_expression(colourspace):
    equation = colour.RGB_luminance_equation(
        colourspace.primaries, colourspace.whitepoint).split('=')[1]
    equation = equation.strip().lower().replace('(', ' * ').replace(')', '')

    return equation


EXPRESSIONS = []
RGB_COLOURSPACES = []
for i, (name, colourspace) in enumerate(
        sorted(colour.RGB_COLOURSPACES.items())):
    if name in ('aces', 'adobe1998', 'prophoto'):
        continue

    EXPRESSIONS.append(EXPRESSION_TEMPLATE.format(
        luminance_expression(colourspace), name.replace(' ', '_'), i * 150))
    RGB_COLOURSPACES.append('"{0}"'.format(name))

for expression in reversed(EXPRESSIONS):
    print(expression)

print(SWITCH_TEMPLATE.format(len(RGB_COLOURSPACES),
                             '{{{0}}}'.format(' '.join(RGB_COLOURSPACES))))

Macbeth Samples


In [ ]:
import numpy as np
import colour

SAMPLE_TEMPLATE = """
Group {{
 inputs 0
 name "{0}"
 selected true
 xpos {1}
 ypos {2}
 postage_stamp true
 addUserKnob {{20 sample_Tab l Sample}}
 addUserKnob {{20 parameters_Group l Parameters n 1}}
 addUserKnob {{19 colour_RGBA_Color_Knob l Colour}}
 colour_RGBA_Color_Knob {{{3} 1}}
 addUserKnob {{6 colour_RGBA_Color_Knob_panelDropped l "panel dropped state" -STARTLINE +HIDDEN}}
 addUserKnob {{1 name_Text_Knob l Name}}
 name_Text_Knob "{4}"
 addUserKnob {{1 index_Text_Knob l Index}}
 index_Text_Knob {5}
 addUserKnob {{18 label_colour_RGB_Color_Knob l "Label Colour"}}
 label_colour_RGB_Color_Knob 1
 addUserKnob {{6 label_colour_RGB_Color_Knob_panelDropped l "panel dropped state" -STARTLINE +HIDDEN}}
 addUserKnob {{7 label_opacity_Floating_Point_Slider l "Label Opacity"}}
 label_opacity_Floating_Point_Slider {{{{parent.label_opacity_Floating_Point_Slider}}}}
 addUserKnob {{20 endGroup n -1}}
}}
 Constant {{
  inputs 0
  color {{{{parent.colour_RGBA_Color_Knob.r}} {{parent.colour_RGBA_Color_Knob.g}} {{parent.colour_RGBA_Color_Knob.b}} {{parent.colour_RGBA_Color_Knob.a}}}}
  format "512 512 0 0 512 512 1 square_512"
  name Constant
  xpos 262
  ypos 53
 }}
 Text {{
  opacity {{{{parent.label_opacity_Floating_Point_Slider}}}}
  message "\[knob parent.name_Text_Knob]"
  font "\[python nuke.defaultFontPathname()]"
  xjustify center
  yjustify bottom
  Transform 1
  box {{0 0 512 512}}
  scale 1.15
  center {{256 -256}}
  color {{{{parent.label_colour_RGB_Color_Knob.r}} {{parent.label_colour_RGB_Color_Knob.g}} {{parent.label_colour_RGB_Color_Knob.b}} 1}}
  name name_Text
  xpos 262
  ypos 125
 }}
 Text {{
  opacity {{{{parent.label_opacity_Floating_Point_Slider}}}}
  message "\[knob parent.index_Text_Knob]"
  font "\[python nuke.defaultFontPathname()]"
  xjustify center
  yjustify center
  Transform 1
  box {{0 0 512 512}}
  scale 3
  center {{256 256}}
  color {{{{parent.label_colour_RGB_Color_Knob.r}} {{parent.label_colour_RGB_Color_Knob.g}} {{parent.label_colour_RGB_Color_Knob.b}} 1}}
  name index_Text
  xpos 262
  ypos 149
 }}
 Output {{
  name Output
  xpos 262
  ypos 173
 }}
end_group
"""[1:-1]


name, data, illuminant = colour.COLOURCHECKERS['ColorChecker24 - After November 2014']

x_pos = y_pos = 0
for i, (name, xyY) in enumerate(data.items()):
    XYZ = colour.xyY_to_XYZ(xyY)
    print(SAMPLE_TEMPLATE.format(name.replace(' ', '_'), 
                                 x_pos, 
                                 y_pos, 
                                 '{0} {1} {2}'.format(*XYZ), 
                                 name, 
                                 i + 1))
    x_pos += 100

RGB Values


In [ ]:
import numpy as np
import colour

name, data, illuminant = colour.COLOURCHECKERS['ColorChecker 2005']
for name, xyY in data.items():
    RGB = colour.XYZ_to_RGB(
        colour.xyY_to_XYZ(xyY),
        illuminant,
        colour.ILLUMINANTS[
            'CIE 1931 2 Degree Standard Observer']['D60'],
        colour.ACES_2065_1_COLOURSPACE.XYZ_to_RGB_matrix,
        'CAT02')

    print('"{0}": {1}'.format(name, RGB))

Matrices


In [ ]:
import numpy as np
import colour

ACES_ENCODINGS = {
    'ACES2065-1': colour.RGB_COLOURSPACES['ACES2065-1'],
    'ACEScc': colour.RGB_COLOURSPACES['ACEScc'],
    'ACEScg': colour.RGB_COLOURSPACES['ACEScg'],
    'ACESproxy': colour.RGB_COLOURSPACES['ACESproxy']}

NUKE_TEMPLATE = """
    ColorMatrix {{
     inputs 0
     matrix {{
         {0}
       }}
     name "{1}"
     selected true
     xpos {2}
     ypos 100
    }}
"""[1:-1]

SWITCH_TEMPLATE = """
Switch {{
 inputs {0}
 which {{{{colourspace_Pulldown_Choice}}}}
 name colourspace_Switch
 selected true
 addUserKnob {{20 User}}
 addUserKnob {{4 colourspace_Pulldown_Choice l Colourspace M {1}}}
}}
"""[1:-1]


def ACES_to_RGB(colourspace,
                encoding='ACES2065-1',
                transform='CAT02'):
    encoding = ACES_ENCODINGS[encoding]
    cat = colour.adaptation.chromatic_adaptation_matrix_VonKries(
        colour.xy_to_XYZ(encoding.whitepoint),
        colour.xy_to_XYZ(colourspace.whitepoint),
        transform)

    return (np.dot(colourspace.XYZ_to_RGB_matrix,
                   np.dot(cat, encoding.RGB_to_XYZ_matrix)))


def nk_format_matrix(M, precision=7):
    pretty = lambda x: ' '.join(
        map('{{:0.{}f}}'.format(precision).format, x))

    nk = '{{{0}}}\n'.format(pretty(M[0]))
    nk += '\t {{{0}}}\n'.format(pretty(M[1]))
    nk += '\t {{{0}}}'.format(pretty(M[2]))
    return nk

MATRICES = []
RGB_COLOURSPACES = []
for i, (name, colourspace) in enumerate(
sorted(colour.RGB_COLOURSPACES.items())):
    if name in ('aces', 'adobe1998', 'prophoto'):
        continue

    M = ACES_to_RGB(colourspace)
    MATRICES.append(NUKE_TEMPLATE.format(nk_format_matrix(M),
                               'ACES2065-1_to_{0}_ColorMatrix'.format(name.replace(' ', '_')),
                               i * 150))
    RGB_COLOURSPACES.append('"{0}"'.format(name))

for matrices in reversed(MATRICES):
    print(matrices)

print(SWITCH_TEMPLATE.format(len(RGB_COLOURSPACES),
                             '{{{0}}}'.format(' '.join(RGB_COLOURSPACES))))

In [ ]:
import numpy as np
import colour


NUKE_OUTER_GROUP_INPUT_TEMPLATE = """
Group {{
 name XYZ_D50_to_RGB
 selected true
 xpos 0
 ypos 0
 addUserKnob {{20 XYZ_D50_to_RGB_Tab l "XYZ D50 to RGB"}}
 addUserKnob {{20 colourspace_parameters_Begin_Group l "Colourspace Parameters" n 1}}
 addUserKnob {{4 colourspace_Pulldown_Choice l Colourspace M {0}}}
 addUserKnob {{20 parameters_endGroup l endGroup n -1}}
 addUserKnob {{20 about_Tab l About}}
 addUserKnob {{26 description_Text l "" +STARTLINE T "XYZ D50 to RGB v0.1.3\\n\\ncolour-science.org - November 25, 2018\\n\\nThis Gizmo / Group tranforms from CIE XYZ D50 tristimulus values to RGB colourspace using CAT02 chromatic adaptation transform."}}
}}
 Input {{
  inputs 0
  name Input
  xpos 0
  ypos -150
 }}
"""[1:-1]

NUKE_OUTER_GROUP_OUTPUT_TEMPLATE = """
 Output {
  name Output
  xpos 0
  ypos 150
 }
end_group
"""[1:-1]

NUKE_INNER_GROUP_TEMPLATE = """
Group {{
 name XYZ_D50_to_{0}
 selected true
 xpos {1}
 ypos {2}
  addUserKnob {{20 XYZ_D50_to_RGB_Tab l "XYZ D50 to {0}"}}
 addUserKnob {{20 parameters_endGroup l endGroup n -1}}
 addUserKnob {{20 about_Tab l About}}
 addUserKnob {{26 description_Text l "" +STARTLINE T "XYZ D50 to {0} v0.1.3\\n\\ncolour-science.org - November 25, 2018\\n\\nThis Gizmo / Group transforms from CIE XYZ D50 tristimulus values to {0} colourspace using CAT02 chromatic adaptation transform."}}
}}
 Input {{
  inputs 0
  name Input
  xpos 0
  ypos -150
 }}
 ColorMatrix {{
  matrix {{
      {3}
    }}
  name {4}_to_{5}_CAT02_ColorMatrix
  xpos 0
  ypos -125
 }}
 ColorMatrix {{
  matrix {{
      {6}
    }}
  name XYZ_to_{0}_ColorMatrix
  xpos 0
  ypos -100
 }}
 Output {{
  name Output
  xpos 0
  ypos -75
 }}
end_group
"""[1:-1]

SWITCH_TEMPLATE = """
Switch {{
 inputs {0}
 xpos 0
 ypos 200
 which {{{{parent.colourspace_Pulldown_Choice}}}}
 name colourspace_Switch
 selected true
 addUserKnob {{20 User}}
 addUserKnob {{4 colourspace_Pulldown_Choice l Colourspace M {1}}}
}}
"""[1:-1]


def nk_format_matrix(M, precision=7):
    pretty = lambda x: ' '.join(map('{{:0.{}f}}'.format(precision).format, x))

    nk = '{{{0}}}\n'.format(pretty(M[0]))
    nk += '\t {{{0}}}\n'.format(pretty(M[1]))
    nk += '\t {{{0}}}'.format(pretty(M[2]))
    return nk


GROUPS = []
RGB_COLOURSPACES = []
for i, (name, colourspace) in enumerate(
        sorted(colour.RGB_COLOURSPACES.items())):
    if name in ('aces', 'adobe1998', 'prophoto'):
        continue

    M = colour.chromatic_adaptation_matrix_VonKries(
        colour.xy_to_XYZ(colour.ILLUMINANTS['cie_2_1931']['D50']),
        colour.xy_to_XYZ(colourspace.whitepoint),
        transform='CAT02')

    GROUPS.append(
        NUKE_INNER_GROUP_TEMPLATE.format(
            name.replace(' ', '_'), i * 150, 0, nk_format_matrix(M), 'D50',
            colourspace.illuminant,
            nk_format_matrix(colourspace.XYZ_to_RGB_matrix)))

    RGB_COLOURSPACES.append('"{0}"'.format(name))

print(NUKE_OUTER_GROUP_INPUT_TEMPLATE.format('{{{0}}}'.format(' '.join(RGB_COLOURSPACES)), len(RGB_COLOURSPACES)))
print('set f3716e02 [stack 0]')
for i, group in enumerate(reversed(GROUPS)):
    print(group)
    if i == len(GROUPS) - 1:
        break

    print('push $f3716e02')

print(SWITCH_TEMPLATE.format(
    len(RGB_COLOURSPACES), '{{{0}}}'.format(' '.join(RGB_COLOURSPACES))))

print(NUKE_OUTER_GROUP_OUTPUT_TEMPLATE)

CAT


In [ ]:
import numpy as np
import colour

NUKE_TEMPLATE = """
    ColorMatrix {{
     inputs 0
     matrix {{
         {0}
       }}
     name "{1}"
     selected true
     xpos {2}
     ypos 100
    }}
"""[1:-1]

SWITCH_TEMPLATE = """
Switch {{
 inputs {0}
 which {{{{colourspace_Pulldown_Choice}}}}
 name colourspace_Switch
 selected true
 addUserKnob {{20 User}}
 addUserKnob {{4 colourspace_Pulldown_Choice l Colourspace M {1}}}
}}
"""[1:-1]

def nk_format_matrix(M, precision=7):
    pretty = lambda x: ' '.join(
        map('{{:0.{}f}}'.format(precision).format, x))

    nk = '{{{0}}}\n'.format(pretty(M[0]))
    nk += '\t {{{0}}}\n'.format(pretty(M[1]))
    nk += '\t {{{0}}}'.format(pretty(M[2]))
    return nk

MATRICES = []
RGB_COLOURSPACES = []
for i, (name, colourspace) in enumerate(
sorted(colour.RGB_COLOURSPACES.items())):
    if name in ('aces', 'adobe1998', 'prophoto'):
        continue

    M = colour.chromatic_adaptation_matrix_VonKries(
        colour.xy_to_XYZ(colour.ILLUMINANTS['cie_2_1931']['D50']),
        colour.xy_to_XYZ(colourspace.whitepoint),
        transform='CAT02')
    print(NUKE_TEMPLATE.format(nk_format_matrix(M),
                               'D50_to_{0}_CAT02_ColorMatrix'.format(colourspace.illuminant),
                               i * 150))
    
    print(NUKE_TEMPLATE.format(nk_format_matrix(colourspace.XYZ_to_RGB_matrix),
                               'XYZ_to_{0}_CAT02_ColorMatrix'.format(name.replace(' ', '_')),
                               i * 150))
    break
    
#     MATRICES.append(NUKE_TEMPLATE.format(nk_format_matrix(M),
#                                'D50_to_{0}_CAT02_ColorMatrix'.format(colourspace.illuminant),
#                                i * 150))

#     RGB_COLOURSPACES.append('"{0}"'.format(name))

for matrices in reversed(MATRICES):
    print(matrices)

# print(SWITCH_TEMPLATE.format(len(RGB_COLOURSPACES),
#                              '{{{0}}}'.format(' '.join(RGB_COLOURSPACES))))

In [ ]:
DIRECTORY = '/Users/kelsolaar/Documents/Development/colour-science/colour-nuke/colour_nuke/resources/images/TMP'

def sanitise(string):
    return string.replace('/', '_').replace(' ', '_')

cc =  nuke.toNode('Colour_Rendition_Chart')
for value in cc.knob('colourspace_Pulldown_Choice').values():
    cc.knob('colourspace_Pulldown_Choice').setValue(value)
    cc.knob('label_opacity_Floating_Point_Slider').setValue(0)
    write = nuke.toNode('Write')
    filename = os.path.join(DIRECTORY, '{0}_ColorChecker2005.exr'.format(sanitise(value)))
    write.knob('file').setValue(filename)
    nuke.execute(write, 1, 1, 1)
    
    cc.knob('label_opacity_Floating_Point_Slider').setValue(1)
    filename = os.path.join(DIRECTORY, '{0}_Labels_ColorChecker2005.exr'.format(sanitise(value)))
    write.knob('file').setValue(filename)
    nuke.execute(write, 1, 1, 1)