set cut_paste_input [stack 0] version 12.2 v5 push $cut_paste_input Group { name BalanceGrade3 tile_color 0x6c9de1ff selected true xpos -641 ypos 75 addUserKnob {20 BalanceGrade} addUserKnob {26 ColorMatrix_label l "@b;ColorMatrix" T " "} addUserKnob {41 matrix T ColorMatrix.matrix} addUserKnob {22 reset_mtx l Reset T "nuke.thisNode()\['matrix'].setValue(\[1,0,0,0,1,0,0,0,1])" +STARTLINE} addUserKnob {26 ""} addUserKnob {26 match_label l "@b;Match" T ""} addUserKnob {18 matchsrc l "src color"} matchsrc 0.18 addUserKnob {6 matchsrc_panelDropped l "panel dropped state" -STARTLINE +HIDDEN} addUserKnob {18 matchdst l "dst color"} matchdst 0.18 addUserKnob {6 matchdst_panelDropped l "panel dropped state" -STARTLINE +HIDDEN} addUserKnob {18 blackpoint t "this value will be subtracted from the offset"} blackpoint {0 0 0} addUserKnob {6 blackpoint_panelDropped l "panel dropped state" -STARTLINE +HIDDEN} addUserKnob {22 set_blackpoint l "Set Blackpoint" t "Set blackpoint based on selected region in the viewer. If preserve luminance is checked, the rgb will be balanced but the overall luminance will not be changed." T "node = nuke.thisNode()\nblackpoint_preserve_luminance = node\['blackpoint_preserve_luminance'].getValue()\nnuke.root().begin()\n\n# Get viewer and connected node to calculate format resolution\nviewer = nuke.activeViewer().node()\nif viewer.input(0):\n viewed_node = viewer.input(0)\n if not nuke.selectedNodes():\n viewed_node.setSelected(1)\nelse:\n viewed_node = nuke.activeViewer().node()\n\n# Get selected sample area\nbboxinfo = nuke.activeViewer().node()\['colour_sample_bbox'].value()\naspect = float(viewed_node.width() * viewed_node.pixelAspect()) / float(viewed_node.height())\ncornerA = \[(bboxinfo\[0]*0.5+0.5) * viewed_node.width(), (((bboxinfo\[1] * 0.5) + (0.5/aspect)) * aspect) * viewed_node.height()]\ncornerB = \[(bboxinfo\[2]*0.5+0.5) * viewed_node.width(), (((bboxinfo\[3] * 0.5) + (0.5/aspect)) * aspect) * viewed_node.height()]\narea = \[cornerB\[0] - cornerA\[0], cornerB\[1] - cornerA\[1]]\ncenter = \[cornerA\[0] + (area\[0]/2), cornerA\[1] + (area\[1] / 2)]\n\n# Reset blackpoint and add knob\nnode\['blackpoint'].setValue(\[0, 0, 0])\nadd_value = node\['add'].getValue()\nnode\['add'].setValue(\[0, 0, 0])\n\n# Sample input colors within box\ncolor_sample = \[node.sample('rgba.red', center\[0], center\[1], area\[0], area\[1]), node.sample('rgba.green', center\[0], center\[1], area\[0], area\[1]), node.sample('rgba.blue', center\[0], center\[1], area\[0], area\[1])]\n\nif blackpoint_preserve_luminance:\n # calculate average luminance with rec709 weighting\n average_luminance = color_sample\[0]*0.2126 + color_sample\[1]*0.7152 + color_sample\[2]*0.0722\n color_sample = \[v - average_luminance for v in color_sample]\n\n# Set blackpoint to sampled value\nnode\['blackpoint'].setValue(color_sample)\nnode\['add'].setValue(add_value)\n" +STARTLINE} addUserKnob {6 blackpoint_preserve_luminance l "preserve luminance" t "Try not to shift luminance of the blackpoint when sampling, only shift the color to be neutral." -STARTLINE} blackpoint_preserve_luminance true addUserKnob {22 reset_match l Reset T "n = nuke.thisNode()\nn\['blackpoint'].setValue(\[0, 0, 0])\nn\['add'].setValue(\[0, 0, 0])\nn\['matchsrc'].setValue(0.18)\nn\['matchdst'].setValue(0.18)" +STARTLINE} addUserKnob {26 grade_label l "@b; Grade" T " "} addUserKnob {7 exposure t "Adjust exposure in stops" R -4 4} addUserKnob {6 exposure_panelDropped l "panel dropped state" -STARTLINE +HIDDEN} addUserKnob {18 multiply R 0 4} multiply {1 1 1} addUserKnob {6 multiply_panelDropped l "panel dropped state" -STARTLINE +HIDDEN} addUserKnob {18 add R -0.25 0.25} add {0 0 0} addUserKnob {6 add_panelDropped l "panel dropped state" -STARTLINE +HIDDEN} addUserKnob {22 reset_grade l Reset T "n = nuke.thisNode()\nn\['exposure'].setValue(0)\nn\['multiply'].setValue(\[1, 1, 1])\nn\['add'].setValue(\[0, 0, 0])" +STARTLINE} addUserKnob {26 ""} addUserKnob {6 invert t "Invert the color transform." +STARTLINE} addUserKnob {41 export_cc l "Export CC" T OCIOCDLTransform.export_cc} addUserKnob {22 export_spimtx l "Export spimtx" t "Export spimtx format describing the balancegrade.\n\nSupports saturation, primaries multiply, offset." T "from __future__ import print_function\nfrom __future__ import with_statement\nimport nuke\n\ndef mtx_mult(a, b):\n # multiply two 3x3 matrices and return the result\n a = \[a\[0:3], a\[3:6], a\[6:9]]\n b = \[b\[0:3], b\[3:6], b\[6:9]]\n c = \[\[sum(a * b for a, b in zip(a_row, b_col)) for b_col in zip(*b)] for a_row in a]\n return c\[0] + c\[1] + c\[2]\n\ndef export_spimtx(output_path=None):\n # export an spimtx file given the color transformations specified on the balancegrade node.\n node = nuke.thisNode()\n nuke.root().begin()\n spimtx_calibration_only = node\['spimtx_calibration_only'].getValue()\n\n if not output_path:\n output_path = nuke.getFilename('output_path')\n if not output_path:\n print('Error: no output path specified. Exiting...')\n return\n\n with node:\n cdltransform = nuke.toNode('OCIOCDLTransform')\n \n mtx = node\['matrix'].getValue()\n\n if spimtx_calibration_only:\n dst_mtx = mtx\n offset = \[0, 0, 0]\n slope = \[1, 1, 1]\n else:\n offset = cdltransform\['offset'].getValue()\n slope = cdltransform\['slope'].getValue()\n mult_mtx = \[slope\[0], 0, 0, 0, slope\[1], 0, 0, 0, slope\[2]]\n dst_mtx = mtx_mult(mult_mtx, mtx)\n\n output_spimtx_string = '\{0\} \{1\} \{2\} \{3\} \{4\} \{5\} \{6\} \{7\} \{8\} \{9\} \{10\} \{11\}'.format(\n dst_mtx\[0],\n dst_mtx\[1],\n dst_mtx\[2],\n int(round(offset\[0] * 65535)),\n dst_mtx\[3],\n dst_mtx\[4],\n dst_mtx\[5],\n int(round(offset\[1] * 65535)),\n dst_mtx\[6],\n dst_mtx\[7],\n dst_mtx\[8],\n int(round(offset\[2] * 65535))\n )\n\n # Create spimtx file\n spimtx_file = open(output_path, 'w+')\n spimtx_file.write(output_spimtx_string)\n spimtx_file.close()\n\n\nif __name__=='__main__':\n export_spimtx()" +STARTLINE} addUserKnob {6 spimtx_calibration_only l "calibration only" t "only export the colormatrix calibration to the spimtx file. \n\notherwise export the entire balancegrade to the spimtx file." -STARTLINE} } Input { inputs 0 name Input xpos -370 ypos -562 } Dot { name Dot1 label " " note_font "Helvetica Bold" note_font_size 24 note_font_color 0xa5a5a501 xpos -336 ypos -486 } set N55320800 [stack 0] OCIOCDLTransform { slope {{parent.OCIOCDLTransform.slope} {parent.OCIOCDLTransform.slope} {parent.OCIOCDLTransform.slope}} offset {{parent.OCIOCDLTransform.offset} {parent.OCIOCDLTransform.offset} {parent.OCIOCDLTransform.offset}} direction inverse working_space scene_linear name OCIOCDLTransform_inverse xpos -260 ypos -442 } ColorMatrix { matrix { {{parent.ColorMatrix.matrix} {parent.ColorMatrix.matrix} {parent.ColorMatrix.matrix}} {{parent.ColorMatrix.matrix} {parent.ColorMatrix.matrix} {parent.ColorMatrix.matrix}} {{parent.ColorMatrix.matrix} {parent.ColorMatrix.matrix} {parent.ColorMatrix.matrix}} } invert true name ColorMatrix_invert xpos -260 ypos -370 } push $N55320800 ColorMatrix { matrix { {1 0 0} {0 1 0} {0 0 1} } name ColorMatrix xpos -370 ypos -442 } OCIOCDLTransform { slope {{"matchdst/matchsrc*pow(2, exposure)*multiply"} {"matchdst/matchsrc*pow(2, exposure)*multiply"} {"matchdst/matchsrc*pow(2, exposure)*multiply"}} offset {{"parent.add - parent.blackpoint"} {"parent.add - parent.blackpoint"} {"parent.add - parent.blackpoint"}} working_space scene_linear name OCIOCDLTransform xpos -370 ypos -370 } Switch { inputs 2 which {{parent.invert}} name Switch_inverse xpos -370 ypos -274 } Output { name Output xpos -370 ypos -202 } end_group # Creation Time=Mon Jun 28 09:30:30 2021 # Creator=Martin