set cut_paste_input [stack 0] version 13.1 v3 push $cut_paste_input Group { name GamutConvert_live tile_color 0xcc804eff label "" selected true xpos 357 ypos -180 addUserKnob {20 Params} addUserKnob {35 presets_src l src M {"gamut/ACES AP0" "knobs this \{src_name \"ACES AP0\" src \"0.7347 0.2653 0.0 1.0 0.0001 -0.077 0.32168 0.33767\"\}" "gamut/ACES AP1" "knobs this \{src_name \"ACES AP1\" src \"0.713 0.293 0.165 0.83 0.128 0.044 0.32168 0.33767\"\}" "gamut/Filmlight E-Gamut" "knobs this \{src_name \"Filmlight E-Gamut\" src \"0.8 0.3177 0.18 0.9 0.065 -0.0805 0.3127 0.329\"\}" "gamut/DaVinci Wide Gamut" "knobs this \{src_name \"DaVinci Wide Gamut\" src \"0.8 0.313 0.1682 0.9877 0.079 -0.1155 0.3127 0.329\"\}" gamut/Rec709 "knobs this \{src_name \"Rec709\" src \"0.64 0.33 0.3 0.6 0.15 0.06 0.3127 0.329\"\}" gamut/Rec2020 "knobs this \{src_name \"Rec2020\" src \"0.708 0.292 0.17 0.797 0.131 0.046 0.3127 0.329\"\}" gamut/P3D60 "knobs this \{src_name \"P3D60\" src \"0.68 0.32 0.265 0.69 0.15 0.06 0.321626 0.337737\"\}" gamut/P3D65 "knobs this \{src_name \"P3D65\" src \"0.68 0.32 0.265 0.69 0.15 0.06 0.3127 0.329\"\}" gamut/P3DCI "knobs this \{src_name \"P3DCI\" src \"0.68 0.32 0.265 0.69 0.15 0.06 0.314 0.351\"\}" "gamut/Arri Alexa Wide Gamut v3" "knobs this \{src_name \"Arri Alexa Wide Gamut v3\" src \"0.684 0.313 0.221 0.848 0.0861 -0.102 0.3127 0.329\"\}" "gamut/Arri Alexa Wide Gamut v4" "knobs this \{src_name \"Arri Alexa Wide Gamut v4\" src \"0.7347 0.2653 0.1424 0.8576 0.0991 -0.0308 0.3127 0.329\"\}" "gamut/RED Wide Gamut RGB" "knobs this \{src_name \"RED Wide Gamut RGB\" src \"0.780308 0.304253 0.121595 1.493994 0.095612 -0.084589 0.3127 0.329\"\}" "gamut/GoPro Protune Native" "knobs this \{src_name \"GoPro Protune Native\" src \"0.69848046 0.19302645 0.32955538 1.02459662 0.10844263 -0.03467857 0.3127 0.329\"\}" "gamut/Canon Cinema Gamut" "knobs this \{src_name \"Canon Cinema Gamut\" src \"0.74 0.27 0.17 1.14 0.08 -0.1 0.3127 0.329\"\}" "gamut/Sony SGamut3" "knobs this \{src_name \"Sony SGamut3\" src \"0.73 0.28 0.14 0.855 0.1 -0.05 0.3127 0.329\"\}" "gamut/Sony SGamut3.Cine" "knobs this \{src_name \"Sony SGamut3.Cine\" src \"0.766 0.275 0.225 0.8 0.089 -0.087 0.3127 0.329\"\}" "gamut/Panasonic V-Gamut" "knobs this \{src_name \"Panasonic V-Gamut\" src \"0.73 0.28 0.165 0.84 0.1 -0.03 0.3127 0.329\"\}" "gamut/DJI D-Gamut" "knobs this \{src_name \"DJI D-Gamut\" src \"0.71 0.31 0.21 0.88 0.09 -0.08 0.3127 0.329\"\}" "gamut/Fujifilm F-Gamut" "knobs this \{src_name \"Fujifilm F-Gamut\" src \"0.708 0.292 0.17 0.797 0.131 0.046 0.3127 0.329\"\}" "gamut/Nikon N-Gamut" "knobs this \{src_name \"Nikon N-Gamut\" src \"0.708 0.292 0.17 0.797 0.131 0.046 0.3127 0.329\"\}" "gamut/Blackmagic Wide Gamut" "knobs this \{src_name \"Blackmagic Wide Gamut\" src \"0.7177215 0.3171181 0.228041 0.861569 0.1005841 -0.0820452 0.3127 0.329\"\}" "gamut/Adobe RGB" "knobs this \{src_name \"Adobe RGB\" src \"0.64 0.33 0.21 0.71 0.15 0.06 0.3127 0.329\"\}" "gamut/Adobe WideGamutRGB" "knobs this \{src_name \"Adobe WideGamutRGB\" src \"0.7347 0.2653 0.1152 0.8264 0.1566 0.0177 0.3457 0.3585\"\}" gamut/ProPhotoRGB "knobs this \{src_name \"ProPhotoRGB\" src \"0.734699 0.265301 0.159597 0.840403 0.036598 0.000105 0.345704 0.358540\"\}" "" "" "" "" "" ""}} addUserKnob {1 src_name l "" -STARTLINE} addUserKnob {41 src l " " T _knobchanged_.src} addUserKnob {35 presets_dst l dst M {gamut/XYZ "knobs this \{dst_name \"XYZ\" dst \"\"\}" "gamut/XYZ D65" "knobs this \{dst_name \"XYZ D65\" dst \"1 0 0 1 0 0 0.3127 0.329\"\}" "gamut/ACES AP0" "knobs this \{dst_name \"ACES AP0\" dst \"0.7347 0.2653 0.0 1.0 0.0001 -0.077 0.32168 0.33767\"\}" "gamut/ACES AP1" "knobs this \{dst_name \"ACES AP1\" dst \"0.713 0.293 0.165 0.83 0.128 0.044 0.32168 0.33767\"\}" "gamut/Filmlight E-Gamut" "knobs this \{dst_name \"Filmlight E-Gamut\" dst \"0.8 0.3177 0.18 0.9 0.065 -0.0805 0.3127 0.329\"\}" "gamut/DaVinci Wide Gamut" "knobs this \{dst_name \"DaVinci Wide Gamut\" dst \"0.8 0.313 0.1682 0.9877 0.079 -0.1155 0.3127 0.329\"\}" gamut/Rec709 "knobs this \{dst_name \"Rec709\" dst \"0.64 0.33 0.3 0.6 0.15 0.06 0.3127 0.329\"\}" gamut/Rec2020 "knobs this \{dst_name \"Rec2020\" dst \"0.708 0.292 0.17 0.797 0.131 0.046 0.3127 0.329\"\}" gamut/P3D60 "knobs this \{dst_name \"P3D60\" dst \"0.68 0.32 0.265 0.69 0.15 0.06 0.321626 0.337737\"\}" gamut/P3D65 "knobs this \{dst_name \"P3D65\" dst \"0.68 0.32 0.265 0.69 0.15 0.06 0.3127 0.329\"\}" gamut/P3DCI "knobs this \{dst_name \"P3DCI\" dst \"0.68 0.32 0.265 0.69 0.15 0.06 0.314 0.351\"\}" "gamut/Arri Alexa Wide Gamut v3" "knobs this \{dst_name \"Arri Alexa Wide Gamut v3\" dst \"0.684 0.313 0.221 0.848 0.0861 -0.102 0.3127 0.329\"\}" "gamut/Arri Alexa Wide Gamut v4" "knobs this \{dst_name \"Arri Alexa Wide Gamut v4\" dst \"0.7347 0.2653 0.1424 0.8576 0.0991 -0.0308 0.3127 0.329\"\}" "gamut/RED Wide Gamut RGB" "knobs this \{dst_name \"RED Wide Gamut RGB\" dst \"0.780308 0.304253 0.121595 1.493994 0.095612 -0.084589 0.3127 0.329\"\}" "gamut/GoPro Protune Native" "knobs this \{dst_name \"GoPro Protune Native\" dst \"0.69848046 0.19302645 0.32955538 1.02459662 0.10844263 -0.03467857 0.3127 0.329\"\}" "gamut/Canon Cinema Gamut" "knobs this \{dst_name \"Canon Cinema Gamut\" dst \"0.74 0.27 0.17 1.14 0.08 -0.1 0.3127 0.329\"\}" "gamut/Sony SGamut3" "knobs this \{dst_name \"Sony SGamut3\" dst \"0.73 0.28 0.14 0.855 0.1 -0.05 0.3127 0.329\"\}" "gamut/Sony SGamut3.Cine" "knobs this \{dst_name \"Sony SGamut3.Cine\" dst \"0.766 0.275 0.225 0.8 0.089 -0.087 0.3127 0.329\"\}" "gamut/Panasonic V-Gamut" "knobs this \{dst_name \"Panasonic V-Gamut\" dst \"0.73 0.28 0.165 0.84 0.1 -0.03 0.3127 0.329\"\}" "gamut/DJI D-Gamut" "knobs this \{dst_name \"DJI D-Gamut\" dst \"0.71 0.31 0.21 0.88 0.09 -0.08 0.3127 0.329\"\}" "gamut/Fujifilm F-Gamut" "knobs this \{dst_name \"Fujifilm F-Gamut\" dst \"0.708 0.292 0.17 0.797 0.131 0.046 0.3127 0.329\"\}" "gamut/Nikon N-Gamut" "knobs this \{dst_name \"Nikon N-Gamut\" dst \"0.708 0.292 0.17 0.797 0.131 0.046 0.3127 0.329\"\}" "gamut/Blackmagic Wide Gamut" "knobs this \{dst_name \"Blackmagic Wide Gamut\" dst \"0.7177215 0.3171181 0.228041 0.861569 0.1005841 -0.0820452 0.3127 0.329\"\}" "gamut/Adobe RGB" "knobs this \{dst_name \"Adobe RGB\" dst \"0.64 0.33 0.21 0.71 0.15 0.06 0.3127 0.329\"\}" "gamut/Adobe WideGamutRGB" "knobs this \{dst_name \"Adobe WideGamutRGB\" dst \"0.7347 0.2653 0.1152 0.8264 0.1566 0.0177 0.3457 0.3585\"\}" gamut/ProPhotoRGB "knobs this \{dst_name \"ProPhotoRGB\" dst \"0.734699 0.265301 0.159597 0.840403 0.036598 0.000105 0.345704 0.358540\"\}" "" "" "" "" ""}} addUserKnob {1 dst_name l "" -STARTLINE} addUserKnob {41 dst l " " T _knobchanged_.dst} addUserKnob {41 cat T _knobchanged_.cat} addUserKnob {26 ""} addUserKnob {41 invert T _knobchanged_.invert} addUserKnob {6 print_mtx l print t "print a few useful representations of the matrix ni the script editor, for OCIO MatrixTransforms, spimtx files, etc" -STARTLINE} addUserKnob {41 matrix T ColorMatrix.matrix} addUserKnob {22 create_colormatrix l "Create ColorMatrix" t "create ColorMatrix node using calculated 3x3 matrix" -STARTLINE T "from __future__ import with_statement\nnode = nuke.thisNode()\nwith nuke.root():\n nukescripts.clear_selection_recursive()\n m = nuke.createNode('ColorMatrix')\n m.setXYpos(node.xpos()-120, node.ypos())\n m\['matrix'].setValue(node\['matrix'].getValue())\n m\['label'].setValue(node\['label'].getValue())"} } Input { inputs 0 name Input xpos -40 ypos 206 } Dot { name _knobchanged_ knobChanged "import nuke\n\ndef matmul(m0, m1):\n # multiply two square matrices\n return \[\[sum(a*b for a,b in zip(r, c)) for c in zip(*m1)] for r in m0]\n\ndef vdot(m, v):\n # multiply AxA matrix by Ax1 vector\n return \[sum(x*y for x,y in zip(r,v)) for r in m]\n\ndef transpose(m):\n # transpose matrix m by swapping rows and cols\n return \[list(r) for r in zip(*m)]\n\ndef zeros(l):\n # create square matrix of size l\n return \[\[0.0]*l for i in range(l)]\n\ndef diag(m, v):\n # set diagonal row of matrix m to vector v or float v\n if isinstance(v, float): \n v = \[v]*len(m)\n for p in range(len(m)):\n m\[p]\[p] = v\[p]\n return m\n\ndef identity(l):\n # return identity matrix of size l\n return diag(zeros(3), 1.0)\n\ndef det(m):\n # calculate determinant of 3x3 matrix m\n return m\[0]\[0]*(m\[1]\[1]*m\[2]\[2]-m\[2]\[1]*m\[1]\[2])-m\[0]\[1]*(m\[1]\[0]*m\[2]\[2]-m\[1]\[2]*m\[2]\[0])+m\[0]\[2]*(m\[1]\[0]*m\[2]\[1]-m\[1]\[1]*m\[2]\[0])\n\ndef inv(m):\n # invert 3x3 matrix m\n d = det(m)\n if d == 0.0:\n return m\n i = zeros(3)\n i\[0]\[0] = (m\[1]\[1]*m\[2]\[2]-m\[2]\[1]*m\[1]\[2])/d\n i\[0]\[1] = (m\[0]\[2]*m\[2]\[1]-m\[0]\[1]*m\[2]\[2])/d\n i\[0]\[2] = (m\[0]\[1]*m\[1]\[2]-m\[0]\[2]*m\[1]\[1])/d\n i\[1]\[0] = (m\[1]\[2]*m\[2]\[0]-m\[1]\[0]*m\[2]\[2])/d\n i\[1]\[1] = (m\[0]\[0]*m\[2]\[2]-m\[0]\[2]*m\[2]\[0])/d\n i\[1]\[2] = (m\[1]\[0]*m\[0]\[2]-m\[0]\[0]*m\[1]\[2])/d\n i\[2]\[0] = (m\[1]\[0]*m\[2]\[1]-m\[2]\[0]*m\[1]\[1])/d\n i\[2]\[1] = (m\[2]\[0]*m\[0]\[1]-m\[0]\[0]*m\[2]\[1])/d\n i\[2]\[2] = (m\[0]\[0]*m\[1]\[1]-m\[1]\[0]*m\[0]\[1])/d\n return i\n\ndef flatten(l):\n # flatten multidimensional list into one dimensional list\n return sum(l, \[])\n\ndef npm(ch):\n # Calculate the Normalized Primaries Matrix for the specified chromaticities\n # Adapted from SMPTE Recommended Practice - Derivation of Basic Television Color Equations\n # http://doi.org/10.5594/S9781614821915\n if len(ch) == 8: # handle flat list\n ch = \[\[ch\[0], ch\[1]], \[ch\[2], ch\[3]], \[ch\[4], ch\[5]], \[ch\[6], ch\[7]]]\n for c in ch:\n c.append(1.0-c\[0]-c\[1]) \n P = transpose(\[ch\[0], ch\[1], ch\[2]])\n W = \[ch\[3]\[0] / ch\[3]\[1], 1.0, ch\[3]\[2] / ch\[3]\[1]]\n C = vdot(inv(P), W)\n C = diag(zeros(3), C)\n return matmul(P, C)\n\ndef cat(ws, wd, method='bradford'):\n # Calculate a von Kries style chromatic adaptation transform matrix given xy chromaticities for src and dst white\n # Source: Mark D. Fairchild - 2013 - Color Appearance Models Third Edition p. 181-186\n # Source: Bruce Lindbloom - Chromatic Adaptation - http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html\n if ws == wd: # src and dst are equal, nothing to do\n return identity(3)\n if method == 'bradford':\n mcat = \[\[0.8951, 0.2664, -0.1614], \[-0.7502, 1.7135, 0.0367], \[0.0389, -0.0685, 1.0296]]\n elif method == 'cat02':\n mcat = \[\[0.7328, 0.4296, -0.1624], \[-0.7036, 1.6975, 0.0061], \[0.003, 0.0136, 0.9834]]\n else:\n mcat = identity(3)\n \n def xy_to_XYZ(xy):\n # convert xy chromaticity to XYZ tristimulus with Y=1.0\n return \[xy\[0]/xy\[1], 1.0, (1.0-xy\[0]-xy\[1])/xy\[1]]\n \n sXYZ = xy_to_XYZ(ws)\n dXYZ = xy_to_XYZ(wd)\n \n s_cone_mtx = vdot(mcat, sXYZ)\n d_cone_mtx = vdot(mcat, dXYZ)\n \n smat = diag(zeros(3), \[a/b for a,b in zip(d_cone_mtx, s_cone_mtx)])\n nmtx = matmul(inv(mcat), smat)\n return matmul(nmtx, mcat)\n\ndef wp(ch):\n # return whitepoint of chromaticities array\n return ch\[-2:]\n\ndef is_xyz(ch):\n # test if ch is XYZ\n prims = ch\[:-2]\n return True if prims == \[1, 0, 0, 1, 0, 0] else False\n\ndef calc_mtx(ch0, ch1, method='bradford'):\n # calculate 3x3 matrix to convert gamut ch0 to ch1, with cat\n if not ch1:\n return npm(ch0)\n rgb0_to_xyz = identity(3) if is_xyz(ch0) else npm(ch0)\n rgb1_to_xyz = identity(3) if is_xyz(ch1) else npm(ch1)\n xyz_to_cat = cat(wp(ch0), wp(ch1), method=method)\n rgb0_to_cat = matmul(xyz_to_cat, rgb0_to_xyz)\n rgb0_to_rgb1 = matmul(inv(rgb1_to_xyz), rgb0_to_cat)\n return rgb0_to_rgb1\n\n\n\nnode = nuke.thisParent()\n\ndef get_ch(k):\n # get chromaticities from knob name k\n ch_str = node\[k].getValue()\n if ' ' in ch_str:\n chs = ch_str.split(' ')\n if not len(chs) == 8:\n print('Error: need 8 space-separated float xy coordinates for RGBW')\n return None\n else:\n ch = list()\n for c in chs:\n try:\n ch.append(float(c))\n except ValueError:\n print('Error: could not convert \{0\} to float'.format(c))\n return None\n return ch\n else:\n return None\n\ndef print_mtx(mtx):\n label = node\['label'].getValue()\n \n # round to 12 digits of precision\n mtx_str = \[format(round(v, 12), '.12g') for v in flatten(mtx)]\n \n # print some useful representations of the matrix\n # an ocio matrixtransform\n mtx_str_pad = mtx_str\[0:3]+\['0']+mtx_str\[3:6]+\['0']+mtx_str\[6:9]+\['0']*4+\['1']\n mtx_string = ', '.join(map(str, mtx_str_pad))\n ocio_matrixtransform_string = '! \{\{matrix: \[\{0\}]\}\}'.format(mtx_string)\n print('\{0\} - OCIO MatrixTransform\\n\{1\}\\n'.format(label, ocio_matrixtransform_string))\n \n # an spimtx file\n spimtx_string = '\{0\} 0\\n\{1\} 0\\n\{2\} 0'.format(\n ' '.join(mtx_str\[0:3]),\n ' '.join(mtx_str\[3:6]),\n ' '.join(mtx_str\[6:9]),\n )\n print('\{0\}.spimtx\\n\{1\}\\n'.format(label, spimtx_string))\n\ndef reset():\n # reset matrix\n node\['matrix'].setValue(flatten(identity(3)))\n \ndef calc():\n # gather node info\n src_ch = get_ch('src')\n if not src_ch:\n reset()\n return\n dst_ch = get_ch('dst')\n cat_method = node\['cat'].value()\n mtx = calc_mtx(src_ch, dst_ch, method=cat_method)\n if node\['invert'].getValue():\n mtx = inv(mtx)\n node\['matrix'].setValue(flatten(mtx))\n label = '\{1\} to \{0\}' if node\['invert'].getValue() else '\{0\} to \{1\}'\n label = label.format(node\['src_name'].getValue(), node\['dst_name'].getValue())\n node\['label'].setValue(label)\n if node\['print_mtx'].getValue():\n print_mtx(mtx)\n \ncalc()" tile_color 0xc1490000 note_font "Helvetica Bold" note_font_size 24 note_font_color 0xff xpos -6 ypos 234 addUserKnob {20 Params} addUserKnob {1 src l " " t "source gamut chromaticities: rgbw"} addUserKnob {1 dst l " " t "destination gamut chromaticities: rgbw"} addUserKnob {83 cat M {bradford cat02 none}} cat cat02 addUserKnob {6 invert t "invert matrix direction" +STARTLINE} } ColorMatrix { matrix { {1 0 0} {0 1 0} {0 0 1} } name ColorMatrix note_font Helvetica xpos -40 ypos 255 } Output { name Output xpos -40 ypos 302 } end_group