Hi there,
this is the first of a series of gizmos that I’m developing right now. This one is an enhanced Keyer gizmo that apart from having the usual Nuke’s keyer operations and options, it has some more keying operations and options that can help in keying process. In the following lines, I will explain in more detail these improvements and I will finish this post by sharing the code of the gizmo. However, if you prefer, you could download it from Nukepedia and start trying it. Please, I will really appreciate your feedback.
As you can see, the first additional option is ‘Enable Lin>Log preprocess’. This checkbox activates and deactivates a Lig2Log node that expands the mid tones range which can help (in some situations) to key a certain element better.
When selecting ‘Luminance Key’ operation, a checkbox and some sliders appear. The checkbox allows creating a custom luminance algorithm defining how much influence do R, G and B channels have in the luminance. The sum of the three amounts must be 1. I have tried to force the node to help users to achieve that result automatically, but as I’m a Python beginner user, the code is not perfect. Sometimes it can be possible to channel amounts to achieve negative values. Don’t worry, the error is usually really small and I have placed clamp nodes to prevent negative and over 1 values getting into the equation.
Chrominance operation lets you sample a color from the image. That color’s RGB values are mapped to 0,0,0 XYZ values and a matte image is generated calculating the distance in 3d space between the sampled values and the rest of the pixels.
As soon as you select Difference Key another input appears in the gizmo. You can connect your cleanplate to in or just a solid color and a matte of the difference between both of them will be created.
The last operation is Bump Keyer. It is useful to generate a matte of the bump details of the image. ‘Blur size’ is a kind of threshold to decide what should the keyer consider as bump detail. ‘Bum Subtraction’ helps to define better that detail. ‘Alternative Method’ sometimes can provide a better result.
Finally, you can clamp the output alpha using the ‘Clamp alpha’ checkbox.
I hope you find this gizmo useful. I would really appreciate if you could spend some minutes giving me feedback about it 🙂 As promised, here is the code:
set cut_paste_input [stack 0] version 11.1 v2 push $cut_paste_input Group { name xa_Keyer1 knobChanged "\nn=nuke.thisNode()\nk=nuke.thisKnob()\nif k.name() == \"keyerOp\":\n keyerOperation = n\['keyerOp'].getValue()\n\n if keyerOperation == 6:\n n\['customLum'].setVisible(True)\n n\['rMult'].setVisible(True)\n n\['gMult'].setVisible(True)\n n\['bMult'].setVisible(True)\n n\['chroCol'].setVisible(False)\n n\['bumpBlur'].setVisible(False)\n n\['bumpSub'].setVisible(False)\n n\['bumpA'].setVisible(False)\n with n:\n nuke.delete(nuke.toNode('cleanplate'))\n\n elif keyerOperation == 10:\n n\['chroCol'].setVisible(True)\n n\['customLum'].setVisible(False)\n n\['rMult'].setVisible(False)\n n\['gMult'].setVisible(False)\n n\['bMult'].setVisible(False)\n n\['bumpBlur'].setVisible(False)\n n\['bumpSub'].setVisible(False)\n n\['bumpA'].setVisible(False)\n with n:\n nuke.delete(nuke.toNode('cleanplate')) \n\n elif keyerOperation == 11:\n n\['chroCol'].setVisible(False)\n n\['customLum'].setVisible(False)\n n\['rMult'].setVisible(False)\n n\['gMult'].setVisible(False)\n n\['bMult'].setVisible(False)\n n\['bumpBlur'].setVisible(False)\n n\['bumpSub'].setVisible(False)\n n\['bumpA'].setVisible(False)\n with n:\n iN = nuke.nodes.Input()\n iN\['xpos'].setValue(-1140)\n iN\['ypos'].setValue(221)\n iN.setName('cleanplate')\n nuke.toNode('Dot14').setInput(0, iN)\n\n elif keyerOperation == 12:\n n\['bumpBlur'].setVisible(True)\n n\['bumpSub'].setVisible(True)\n n\['bumpA'].setVisible(True)\n n\['chroCol'].setVisible(False)\n n\['customLum'].setVisible(False)\n n\['rMult'].setVisible(False)\n n\['gMult'].setVisible(False)\n n\['bMult'].setVisible(False)\n with n:\n nuke.delete(nuke.toNode('cleanplate'))\n\n else:\n n\['customLum'].setValue(False)\n n\['customLum'].setVisible(False)\n n\['rMult'].setVisible(False)\n n\['gMult'].setVisible(False)\n n\['bMult'].setVisible(False)\n n\['chroCol'].setVisible(False)\n n\['bumpBlur'].setVisible(False)\n n\['bumpSub'].setVisible(False)\n n\['bumpA'].setVisible(False)\n with n:\n nuke.delete(nuke.toNode('cleanplate'))\n\n if keyerOperation > 9:\n with n:\n cN = nuke.toNode('Keyer1')\n cN\['operation'].setValue(8)\n\n else:\n with n:\n cN = nuke.toNode('Keyer1')\n cN\['operation'].setValue(int(keyerOperation))\n\n\nelif k.name() == \"rMult\" or k.name() == \"gMult\" or k.name() == \"bMult\":\n rValue = n\['rMult'].getValue()\n gValue = n\['gMult'].getValue()\n bValue = n\['bMult'].getValue()\n lumValue = rValue+ gValue + bValue\n if lumValue != 1:\n if k.name() == 'rMult':\n n\['gMult'].setValue(n\['gMult'].getValue()-((lumValue-1)/2))\n n\['bMult'].setValue(n\['bMult'].getValue()-((lumValue-1)/2))\n gValue = n\['gMult'].getValue()\n bValue = n\['bMult'].getValue()\n if gValue < 0:\n n\['gMult'].setValue(0)\n n\['rMult'].setValue(n\['rMult'].getValue()-(abs(gValue)/2))\n n\['bMult'].setValue(n\['bMult'].getValue()-(abs(gValue)/2))\n if bValue < 0:\n n\['bMult'].setValue(0)\n n\['rMult'].setValue(n\['rMult'].getValue()-(abs(bValue)/2))\n n\['gMult'].setValue(n\['gMult'].getValue()-(abs(bValue)/2))\n elif k.name() == 'gMult':\n n\['rMult'].setValue(n\['rMult'].getValue()-((lumValue-1)/2))\n n\['bMult'].setValue(n\['bMult'].getValue()-((lumValue-1)/2))\n\n if rValue < 0:\n n\['rMult'].setValue(0)\n n\['gMult'].setValue(n\['gMult'].getValue()-(abs(rValue)/2))\n n\['bMult'].setValue(n\['bMult'].getValue()-(abs(rValue)/2))\n if bValue < 0:\n n\['bMult'].setValue(0)\n n\['rMult'].setValue(n\['rMult'].getValue()-(abs(bValue)/2))\n n\['gMult'].setValue(n\['gMult'].getValue()-(abs(bValue)/2))\n\n else:\n n\['rMult'].setValue(n\['rMult'].getValue()-((lumValue-1)/2))\n n\['gMult'].setValue(n\['gMult'].getValue()-((lumValue-1)/2))\n\n if gValue < 0:\n n\['gMult'].setValue(0)\n n\['rMult'].setValue(n\['rMult'].getValue()-(abs(gValue)/2))\n n\['bMult'].setValue(n\['bMult'].getValue()-(abs(gValue)/2))\n if rValue < 0:\n n\['rMult'].setValue(0)\n n\['rMult'].setValue(n\['rMult'].getValue()-(abs(rValue)/2))\n n\['gMult'].setValue(n\['gMult'].getValue()-(abs(rValue)/2))\n" tile_color 0xff00ff label "\[value keyerOp]" selected true xpos 67 ypos -110 addUserKnob {20 keyerTab l Keyer} addUserKnob {41 in l Input t "Which channels to calculate the key from" T Shuffle8.in} addUserKnob {6 lin2log l "Enable Lin>Log preprocess" t "Converts the input from linear to log giving more space to mid tones in order to improve the chances of keying specific areas" +STARTLINE} addUserKnob {4 keyerOp l Operation t "red, green, blue = use that channel\nscreen = subtract that channel from others\nluminance = use CIE luminance value\nsaturation = use color saturation\nmax, min = max or min of red,green,blue\nchrominance = sets picked color in the origin of 3d space and calculates the distance from ofther pixels to it\ndifference = compares the input with the cleanplate\nbump = generates a matte for bump details" M {"Red Keyer" "Green Keyer" "Blue Keyer" Redscreen Greenscreen Bluescreen "Luminance Key" "Saturation Key" "Max Keyer" "Min Keyer" "Chrominance Key" "Difference Key" "Bump Keyer" "" "" "" "" ""}} keyerOp "Luminance Key" addUserKnob {6 customLum l "Enable Custom Luminance" t "Enables the possibility to generate a custom luminance deciding how much influence R, G and B channels are going to have on it. The sum of R, G and B must be equal to 1. " +STARTLINE} addUserKnob {7 rMult l "Red Amount"} rMult 0.3 addUserKnob {7 gMult l "Green Amount"} gMult 0.59 addUserKnob {7 bMult l "Blue Amount"} bMult 0.11 addUserKnob {18 chroCol l color t "Set this value as origin to calculate the distance between other pixel values" +HIDDEN} chroCol {0 0 0} addUserKnob {6 chroCol_panelDropped l "panel dropped state" -STARTLINE +HIDDEN} addUserKnob {6 chroCol_panelDropped_1 l "panel dropped state" -STARTLINE +HIDDEN} addUserKnob {6 chroCol_panelDropped_1_1 l "panel dropped state" -STARTLINE +HIDDEN} addUserKnob {6 chroCol_panelDropped_1_1_1 l "panel dropped state" -STARTLINE +HIDDEN} addUserKnob {6 chroCol_panelDropped_1_1_1_1 l "panel dropped state" -STARTLINE +HIDDEN} addUserKnob {7 bumpBlur l "Blur Size" t "Modify this value to decide what should be consider as bump. To pick tiny details, use a low value." +HIDDEN R 0 100} bumpBlur 14.5 addUserKnob {7 bumpSub l "Bump Subtraction" t "Helps to filter details" +HIDDEN R 0 0.5} bumpSub 0.05 addUserKnob {6 bumpA l "Alternative Method" t "Sometimes it helps to improve the chances of succesful keying" +HIDDEN +STARTLINE} addUserKnob {26 ""} addUserKnob {41 keyerRange l Threshold t "Specify the trapezoid used to key. Goes linearly from (A,0) to (B,1), and then from (C,1) to (D,0). If C and D are the same it will map everything >C to 1." T Keyer1.range} addUserKnob {6 clamp l "Clamp Alpha" t "Clamp the output alpha to keep values between 0 and 1" +STARTLINE} clamp true addUserKnob {26 ""} addUserKnob {26 about l "" +STARTLINE T "Developed by Xabier Arrieta.\nhttps://arrieta.me"} } BackdropNode { inputs 0 name BackdropNode1 tile_color 0xbababa01 label "<center>Custom Luminance" note_font_size 50 xpos -292 ypos -5 bdwidth 454 bdheight 485 } BackdropNode { inputs 0 name BackdropNode2 tile_color 0xbababa01 label <center>Keyer note_font_size 50 xpos 209 ypos 874 bdwidth 243 bdheight 197 } BackdropNode { inputs 0 name BackdropNode3 tile_color 0xbababa01 label "<center>Recover Original RGB" note_font_size 50 xpos 188 ypos 1927 bdwidth 284 bdheight 274 } BackdropNode { inputs 0 name BackdropNode4 tile_color 0xbababa01 label "<center>Chrominance Key" note_font_size 50 xpos -724 ypos -11 bdwidth 357 bdheight 366 } BackdropNode { inputs 0 name BackdropNode5 tile_color 0xbababa01 label "<center>Difference Key" note_font_size 50 xpos -1206 ypos -15 bdwidth 441 bdheight 624 } BackdropNode { inputs 0 name BackdropNode6 tile_color 0xbababa01 label "<center>Bump Keyer" note_font_size 50 xpos -504 ypos 1060 bdwidth 572 bdheight 740 } Input { inputs 0 name input xpos 290 ypos -274 } Shuffle { name Shuffle8 label "\[string toupper \[value in]]\[if \{\[value out]==\"rgba\"\} \{return\} else \{return \" to \"\}]\[if \{\[value out]==\"rgba\"\} \{return\} else \{return \[string toupper \[value out]]\}]" xpos 290 ypos -208 } Dot { name Dot8 xpos 324 ypos -102 } set Nd04b4000 [stack 0] Dot { name Dot9 xpos -1436 ypos -102 } Dot { name Dot10 xpos -1437 ypos 2149 } Dot { inputs 0 name Dot14 xpos -1106 ypos 283 } push $Nd04b4000 Log2Lin { operation lin2log black 4e-05 white 665 name Log2Lin1 label "\[if \{\[value operation]==\"lin2log\"\} \{return \"LIN > LOG\"\} else \{return \"LOG > LIN\"\}]" xpos 290 ypos -23 disable {{!parent.lin2log}} } Dot { name Dot6 xpos 324 ypos 152 } set Nd04efc00 [stack 0] Dot { name Dot1 xpos 34 ypos 152 } set Nd0498380 [stack 0] Dot { name Dot2 xpos -84 ypos 152 } set N89364380 [stack 0] Dot { name Dot3 xpos -204 ypos 152 } set Nd04c2e00 [stack 0] Dot { name Dot11 xpos -552 ypos 152 } set Nd04bea80 [stack 0] Dot { name Dot13 xpos -957 ypos 152 } add_layer {cleanplate cleanplate.r cleanplate.g cleanplate.b} Copy { inputs 2 from0 rgba.red to0 cleanplate.r from1 rgba.green to1 cleanplate.g from2 rgba.blue to2 cleanplate.b name Copy2 xpos -991 ypos 260 } Expression { expr0 abs(r-cleanplate.r) expr1 abs(g-cleanplate.g) expr2 abs(b-cleanplate.b) name Expression2 label DIFFERENCE xpos -991 ypos 344 } Remove { channels cleanplate name Remove1 xpos -991 ypos 396 } Expression { expr3 r+g+b name Expression3 label "A = R+G+B" xpos -991 ypos 450 } Shuffle { red alpha green alpha blue alpha name Shuffle5 label "RGB = A" xpos -991 ypos 503 } Dot { name Dot15 xpos -957 ypos 714 } push $Nd04bea80 Expression { expr3 ((parent.chroCol.r-r)**2+(parent.chroCol.g-g)**2+(parent.chroCol.b-b)**2)**(1/2.0) name Expression1 label "DISTANCE MAP" xpos -586 ypos 210 } Shuffle { red alpha green alpha blue alpha name Shuffle4 label "RGB = A" xpos -586 ypos 276 } Dot { name Dot12 xpos -552 ypos 598 } push $Nd04c2e00 Shuffle { green red blue red alpha black name Shuffle3 label R xpos -238 ypos 212 } Multiply { channels rgb value {{parent.rMult}} name Multiply3 label "\[value parent.rMult]" xpos -238 ypos 268 } Clamp { name Clamp1 xpos -238 ypos 316 } Dot { name Dot5 xpos -204 ypos 378 } push 0 push $N89364380 Shuffle { red green blue green alpha black name Shuffle2 label G xpos -118 ypos 212 } Multiply { channels rgb value {{parent.gMult}} name Multiply2 label "\[value parent.gMult]" xpos -118 ypos 268 } Clamp { name Clamp2 xpos -118 ypos 318 } Dot { name Dot4 xpos -84 ypos 378 } push $Nd0498380 Shuffle { red blue green blue alpha black name Shuffle1 label B xpos 0 ypos 212 } Multiply { channels rgb value {{parent.bMult}} name Multiply1 label "\[value parent.bMult]" xpos 0 ypos 268 } Clamp { name Clamp3 xpos 0 ypos 318 } Merge2 { inputs 3+1 operation plus name Merge1 xpos 0 ypos 426 } Dot { name Dot7 xpos 34 ypos 511 } push $Nd04efc00 Switch { inputs 2 which {{parent.customLum}} name Switch1 xpos 290 ypos 507 } Switch { inputs 2 which {{"\[if \{\[value parent.keyerOp]==\"Chrominance Key\"\} \{return 1\} else \{return 0\}]"}} name Switch2 xpos 290 ypos 590 } Switch { inputs 2 which {{"\[if \{\[value parent.keyerOp]==\"Difference Key\"\} \{return 1\} else \{return 0\}]"}} name Switch3 xpos 290 ypos 710 } Keyer { operation "luminance key" name Keyer1 xpos 289 ypos 981 } Dot { name Dot16 xpos 323 ypos 1194 } set N90a4d880 [stack 0] Dot { name Dot17 xpos -116 ypos 1190 } Shuffle { red alpha green alpha blue alpha name Shuffle6 label "RGB = A" xpos -150 ypos 1252 } Dot { name Dot18 xpos -116 ypos 1338 } set N8c643880 [stack 0] Dot { name Dot19 xpos -264 ypos 1338 } set N579a700 [stack 0] Dot { name Dot21 xpos -404 ypos 1338 } Shuffle { red white green white blue white alpha white name Shuffle7 label "RGBA = 1" xpos -438 ypos 1382 } Multiply { value {{parent.bumpSub}} name Multiply4 label "\[value parent.bumpSub]" xpos -438 ypos 1437 } Dot { name Dot22 xpos -404 ypos 1506 } push $N579a700 Blur { size {{parent.bumpBlur}} name Blur1 label "\[value parent.bumpBlur]" xpos -298 ypos 1376 } Merge2 { inputs 2 operation from name Merge3 xpos -298 ypos 1502 } Expression { expr3 abs(a) name Expression4 label ABS(A) xpos -298 ypos 1550 disable {{!parent.bumpA}} } Dot { name Dot20 xpos -264 ypos 1615 } push $N8c643880 Merge2 { inputs 2 operation from name Merge2 xpos -150 ypos 1670 } Dot { name Dot23 xpos -116 ypos 1742 } push $N90a4d880 Switch { inputs 2 which {{"\[if \{\[value parent.keyerOp]==\"Bump Keyer\"\} \{return 1\} else \{return 0\}]"}} name Switch4 selected true xpos 289 ypos 1742 } Copy { inputs 2 from0 rgba.red to0 rgba.red from1 rgba.green to1 rgba.green from2 rgba.blue to2 rgba.blue name Copy1 xpos 289 ypos 2126 disable {{curve}} } Clamp { channels alpha name Clamp4 xpos 290 ypos 2327 disable {{!parent.clamp}} } Output { name Output1 xpos 289 ypos 2470 } end_group