Combining Alphas

From RMIT Visual Effects
Jump to: navigation, search

It is frequently the case that two alphas need to be combined. This is done using the Min and Max blend mode,

Junk and holdout

A mask is composed of black and white regions. The black region is called the junk component and works to hide the foreground in a masking operation. The white region is called the holdout component and works to reveal the foreground in a masking operation.

Combining two holdout components

To combine two holdout a Max blend mode is used. This blend mode looks at corresponding pixel in two alphas, and selects whichever is the lightest. The annotated script below shows how it works.

Press 'Expand' and select and copy everything below this line, then paste into the Nuke node graph.

set cut_paste_input [stack 0]
version 6.3 v2
Roto {
 inputs 0
 curves {AnimTree: "" {
 Version: 1.2
 Flag: 0
 RootNode: 1
 Node: {
  NodeName: "Root" {
   Flag: 512
   NodeType: 1
   Transform: 0 0 S 0 0 S 0 0 S 0 0 S 0 1 S 0 1 S 0 0 S 0 1024 S 0 778 
   NumOfAttributes: 11
   "vis" S 0 1 "opc" S 0 1 "mbo" S 0 1 "mb" S 0 1 "mbs" S 0 0.5 "fo" S 0 1 "fx" S 0 0 "fy" S 0 0 "ff" S 0 1 "ft" S 0 0 "pt" S 0 0 
  }
  NumOfChildren: 1
  Node: {
   NodeName: "Bezier1" {
    Flag: 512
    NodeType: 3
    CurveGroup: "" {
     Transform: 0 0 S 0 0 S 0 0 S 0 0 S 0 1 S 0 1 S 0 0 S 0 1410.5 S 0 782.5 
     Flag: 0
     NumOfCubicCurves: 2
     CubicCurve: "" {
      Type: 0 Flag: 8192 Dim: 2
      NumOfPoints: 21
      0 S 0 0 S 0 0 0 0 S 0 884 S 0 1136 0 0 S 0 0 S 0 0 0 0 S 0 -2 S 0 0 0 0 S 0 1124 S 0 1242 0 0 S 0 0.319946 S 0 0 0 0 S 0 -30.3375 S 0 14.9832 0 0 S 0 1195.18 S 0 1241.54 0 0 S 0 64.4673 S 0 -31.8392 0 0 S 0 -53.55 S 0 99.96 0 0 S 0 1422 S 0 1044 0 0 S 0 59.85 S 0 -111.72 0 0 S 0 7.85059 S 0 68.5848 0 0 S 0 1488 S 0 714 0 0 S 0 -2.47913 S 0 -21.6584 0 0 S 0 0 S 0 0.47998 0 0 S 0 1460 S 0 674 0 0 S 0 0 S 0 -4 0 0 S 0 -4 S 0 0 0 0 S 0 1160 S 0 670 0 0 S 0 -14 S 0 -36 0 
     }
     CubicCurve: "" {
      Type: 0 Flag: 8192 Dim: 2
      NumOfPoints: 21
      0 S 0 0 S 0 0 0 0 S 0 -44 S 0 20 0 0 S 0 0 S 0 0 0 0 S 0 -2 S 0 0 0 0 S 0 -100 S 0 34 0 0 S 0 0.320068 S 0 0 0 0 S 0 -30.3375 S 0 14.9832 0 0 S 0 0 S 0 0 0 0 S 0 64.4673 S 0 -31.8392 0 0 S 0 -53.55 S 0 99.96 0 0 S 0 0 S 0 0 0 0 S 0 59.85 S 0 -111.72 0 0 S 0 7.85059 S 0 68.5848 0 0 S 0 0 S 0 0 0 0 S 0 -2.47913 S 0 -21.6584 0 0 S 0 0 S 0 0.47998 0 0 S 0 -42 S 0 -104 0 0 S 0 0 S 0 -4 0 0 S 0 -4 S 0 0 0 0 S 0 -75.6881 S 0 -142.294 0 0 S 0 -14 S 0 -36 0 
     }
     NumOfAttributes: 44
     "vis" S 0 1 "r" S 0 1 "g" S 0 1 "b" S 0 1 "a" S 0 1 "ro" S 0 0 "go" S 0 0 "bo" S 0 0 "ao" S 0 0 "opc" S 0 1 "bm" S 0 0 "inv" S 0 0 "mbo" S 0 0 "mb" S 0 1 "mbs" S 0 0.5 "mbsot" S 0 0 "mbso" S 0 0 "fo" S 0 1 "fx" S 0 0 "fy" S 0 0 "ff" S 0 1 "ft" S 0 0 "src" S 0 0 "stx" S 0 0 "sty" S 0 0 "str" S 0 0 "sr" S 0 0 "ssx" S 0 1 "ssy" S 0 1 "ss" S 0 0 "spx" S 0 1024 "spy" S 0 778 "stot" S 0 0 "sto" S 0 0 "sv" S 0 0 "sf" S 0 1 "sb" S 0 1 "nv" S 0 1 "view1" S 0 1 "ltn" S 0 1 "ltm" S 0 1 "ltt" S 0 0 "tt" S 0 4 "pt" S 0 0 
    }
   }
   NumOfChildren: 0
  }
 }
}
}
 toolbox {selectAll {
  { selectAll ssx 1 ssy 1 sf 1 }
  { createBezier ssx 1 ssy 1 sf 1 sb 1 tt 4 }
  { createBSpline ssx 1 ssy 1 sf 1 sb 1 }
  { createEllipse ssx 1 ssy 1 sf 1 sb 1 }
  { createRectangle ssx 1 ssy 1 sf 1 sb 1 }
  { brush ssx 1 ssy 1 sf 1 sb 1 }
  { eraser src 2 ssx 1 ssy 1 sf 1 sb 1 }
  { clone src 1 ssx 1 ssy 1 sf 1 sb 1 }
  { reveal src 3 ssx 1 ssy 1 sf 1 sb 1 }
  { dodge src 1 ssx 1 ssy 1 sf 1 sb 1 }
  { burn src 1 ssx 1 ssy 1 sf 1 sb 1 }
  { blur src 1 ssx 1 ssy 1 sf 1 sb 1 }
  { sharpen src 1 ssx 1 ssy 1 sf 1 sb 1 }
  { smear src 1 ssx 1 ssy 1 sf 1 sb 1 }
} }
 toolbar_brush_hardness 0.200000003
 toolbar_lifetime_type all
 toolbar_source_transform_scale {1 1}
 toolbar_source_transform_center {320 240}
 colorOverlay 0
 lifetime_type "all frames"
 view {}
 motionblur_on true
 motionblur_shutter_offset_type centred
 source_black_outside true
 createNewTrack {{-1} "-1\t(none)\t-1" "1000\tNew Track Layer\t1000"}
 name Roto1
 label "\nThis RGBA represents the Holdout mask "
 note_font "Verdana Bold"
 note_font_color 0xf4ffaaff
 selected true
 xpos -497
 ypos -93
}
push $cut_paste_input
Radial {
 area {516 316 1516 1316}
 softness 0.37
 color {0.8848355412 0.177395761 1 1}
 name Radial1
 tile_color 0xff9455ff
 label "\nThis RGBA feed represents \nthe RGBA output from a Primate"
 note_font "Verdana Bold"
 note_font_color 0x7fff00ff
 selected true
 xpos -228
 ypos -283
}
Merge2 {
 inputs 2
 operation max
 output {-rgba.red -rgba.green -rgba.blue rgba.alpha}
 name Merge1
 label "\nThe blend mode of this Merge is set\nto Max and is intended to combine the\nwhite compoenents of the Radial and\nRoto. Note how the RGB of the output\nhave been unticked. This is to prevent\nthe Max operation from operating on \nanything other than the alpha. "
 note_font "Verdana Bold"
 note_font_color 0x7fff00ff
 selected true
 xpos -228
 ypos -139
}

Combining two junk components

To combine two holdout a Min blend mode is used. This blend mode looks at corresponding pixel in two alphas, and selects whichever is the darkest. The annotated script below shows how it works.

Press 'Expand' and select and copy everything below this line, then paste into the Nuke node graph.

set cut_paste_input [stack 0]
version 6.3 v2
Roto {
 inputs 0
 curves {AnimTree: "" {
 Version: 1.2
 Flag: 0
 RootNode: 1
 Node: {
  NodeName: "Root" {
   Flag: 512
   NodeType: 1
   Transform: 0 0 S 0 0 S 0 0 S 0 0 S 0 1 S 0 1 S 0 0 S 0 1024 S 0 778 
   NumOfAttributes: 11
   "vis" S 0 1 "opc" S 0 1 "mbo" S 0 1 "mb" S 0 1 "mbs" S 0 0.5 "fo" S 0 1 "fx" S 0 0 "fy" S 0 0 "ff" S 0 1 "ft" S 0 0 "pt" S 0 0 
  }
  NumOfChildren: 1
  Node: {
   NodeName: "Bezier1" {
    Flag: 512
    NodeType: 3
    CurveGroup: "" {
     Transform: 0 0 S 0 0 S 0 0 S 0 0 S 0 1 S 0 1 S 0 0 S 0 1459.5 S 0 929.5 
     Flag: 0
     NumOfCubicCurves: 2
     CubicCurve: "" {
      Type: 0 Flag: 8192 Dim: 2
      NumOfPoints: 12
      0 S 0 0 S 0 0 0 0 S 0 1154 S 0 1404 0 0 S 0 0 S 0 0 0 0 S 0 -2 S 0 0 0 0 S 0 1640 S 0 1396 0 0 S 0 2 S 0 0 0 0 S 0 -2 S 0 0 0 0 S 0 1636 S 0 478 0 0 S 0 2 S 0 0 0 0 S 0 0 S 0 0 0 0 S 0 1430 S 0 458 0 0 S 0 0 S 0 0 0 
     }
     CubicCurve: "" {
      Type: 0 Flag: 8192 Dim: 2
      NumOfPoints: 12
      0 S 0 0 S 0 0 0 0 S 0 0 S 0 0 0 0 S 0 0 S 0 0 0 0 S 0 -2 S 0 0 0 0 S 0 0 S 0 0 0 0 S 0 2 S 0 0 0 0 S 0 -2 S 0 0 0 0 S 0 0 S 0 0 0 0 S 0 2 S 0 0 0 0 S 0 0 S 0 0 0 0 S 0 0 S 0 0 0 0 S 0 0 S 0 0 0 
     }
     NumOfAttributes: 44
     "vis" S 0 1 "r" S 0 1 "g" S 0 1 "b" S 0 1 "a" S 0 1 "ro" S 0 0 "go" S 0 0 "bo" S 0 0 "ao" S 0 0 "opc" S 0 1 "bm" S 0 0 "inv" S 0 0 "mbo" S 0 0 "mb" S 0 1 "mbs" S 0 0.5 "mbsot" S 0 0 "mbso" S 0 0 "fo" S 0 1 "fx" S 0 0 "fy" S 0 0 "ff" S 0 1 "ft" S 0 0 "src" S 0 0 "stx" S 0 0 "sty" S 0 0 "str" S 0 0 "sr" S 0 0 "ssx" S 0 1 "ssy" S 0 1 "ss" S 0 0 "spx" S 0 0 "spy" S 0 0 "stot" S 0 0 "sto" S 0 0 "sv" S 0 0 "sf" S 0 1 "sb" S 0 1 "nv" S 0 1 "view1" S 0 1 "ltn" S 0 1 "ltm" S 0 1 "ltt" S 0 0 "tt" S 0 4 "pt" S 0 0 
    }
   }
   NumOfChildren: 0
  }
 }
}
}
 toolbox {selectAll {
  { selectAll ssx 1 ssy 1 sf 1 }
  { createBezier ssx 1 ssy 1 sf 1 sb 1 tt 4 }
  { createBSpline ssx 1 ssy 1 sf 1 sb 1 }
  { createEllipse ssx 1 ssy 1 sf 1 sb 1 }
  { createRectangle ssx 1 ssy 1 sf 1 sb 1 }
  { brush ssx 1 ssy 1 sf 1 sb 1 }
  { eraser src 2 ssx 1 ssy 1 sf 1 sb 1 }
  { clone src 1 ssx 1 ssy 1 sf 1 sb 1 }
  { reveal src 3 ssx 1 ssy 1 sf 1 sb 1 }
  { dodge src 1 ssx 1 ssy 1 sf 1 sb 1 }
  { burn src 1 ssx 1 ssy 1 sf 1 sb 1 }
  { blur src 1 ssx 1 ssy 1 sf 1 sb 1 }
  { sharpen src 1 ssx 1 ssy 1 sf 1 sb 1 }
  { smear src 1 ssx 1 ssy 1 sf 1 sb 1 }
} }
 toolbar_brush_hardness 0.200000003
 toolbar_lifetime_type all
 toolbar_source_transform_scale {1 1}
 toolbar_source_transform_center {320 240}
 colorOverlay 0
 lifetime_type "all frames"
 view {}
 motionblur_on true
 motionblur_shutter_offset_type centred
 source_black_outside true
 createNewTrack {{-1} "-1\t(none)\t-1" "1000\tNew Track Layer\t1000"}
 name Roto2
 label "\nThis RGBA represents the Junk mask "
 note_font "Verdana Bold Bold"
 note_font_color 0xf4ffaaff
 selected true
 xpos 57
 ypos -96
}
Invert {
 name Invert1
 label "\nThis Invert is a quick way of deriving \nblack on white imfortmation from \nwhite on black imformation. "
 note_font "Verdana Bold"
 note_font_color 0xf4ffaaff
 selected true
 xpos 276
 ypos -121
}
push $cut_paste_input
Radial {
 area {516 316 1516 1316}
 softness 0.37
 color {0.8848355412 0.177395761 1 1}
 name Radial2
 tile_color 0xff9455ff
 label "\nThis RGBA feed represents \nthe RGBA output from a Primate"
 note_font "Verdana Bold Bold"
 note_font_color 0x7fff00ff
 selected true
 xpos 488
 ypos -278
}
Merge2 {
 inputs 2
 operation min
 output {-rgba.red -rgba.green -rgba.blue rgba.alpha}
 name Merge2
 label "\nThe blend mode of this Merge is set\nto Min and is intended to combine the\nwhite compoenents of the Radial and\nRoto. Note how the RGB of the output\nhave been unticked. This is to prevent\nthe Min operation from operating on \nanything other than the alpha. "
 note_font "Verdana Bold Bold"
 note_font_color 0x7fff00ff
 selected true
 xpos 488
 ypos -134
}

Combining hard and soft mattes

Problem: a soft key produces mattes the edges of which are nice and soft the insides of which are noisy and full of artifacts. A hard key produces mattes the insides and outsides of which are nice and clean, but the edges of which are too hard.

Solution: combine the two. This is done using the Max and Min techniques already described, plus a little magic with the erode node. The narrative for this solution is this:

  • We make a shrunken version (using an erode node) of the hard matte and use it to 'punch' a white hole into the white of the soft mask. We do this with a Max blend mode.
  • We make an expanded version (using an erode node) of the hard matte and use it to 'punch' a black hole into the black of the soft mask. We do this with a Min blend mode.

The code-snippet for this is:

Press 'Expand' and select and copy everything below this line, then paste into the Nuke node graph.

set cut_paste_input [stack 0]
version 6.3 v2
StickyNote {
 inputs 0
 name StickyNote1
 label "Deactivate the Junk and Holdout \nMerge nodes to see the difference. "
 selected true
 xpos -760
 ypos 249
}
StickyNote {
 inputs 0
 name StickyNote2
 label "Soft 'noisy' matte"
 note_font "Verdana Bold"
 selected true
 xpos -629
 ypos -28
}
StickyNote {
 inputs 0
 name StickyNote3
 label "Hard matte"
 note_font "Verdana Bold Bold"
 selected true
 xpos -250
 ypos -28
}
Group {
 inputs 0
 name Group2
 label "\nThis group represents the clean output from a \nhard keyer. Notice how the black and white \nare both clean. However, the edges are way \ntoo hard."
 note_font "Verdana Bold Bold"
 note_font_color 0x7fff00ff
 selected true
 xpos -246
 ypos 10
}
 Radial {
  inputs 0
  area {516 316 1516 1316}
  softness 0.03
  color {1 0 0 1}
  name Radial4
  tile_color 0xff9455ff
  label "\nThis Radial represents the noisy output from a \nsoft keyer. Notice how the black and white \nare both noisy. However, the edges are nice \nand soft. "
  note_font "Verdana Bold Bold Bold Bold Bold Bold"
  note_font_color 0x7fff00ff
  xpos 391
  ypos -292
 }
 Output {
  name Output1
  xpos 391
  ypos -161
 }
end_group
Dot {
 name Dot1
 selected true
 xpos -212
 ypos 126
}
set N511d710 [stack 0]
Erode {
 size -0.02
 blur 1
 name Erode2
 label "\nThis Erode makes alpha \nfrom the hard key larger"
 selected true
 xpos -177
 ypos 169
}
Blur {
 size 20
 name Blur1
 selected true
 xpos -177
 ypos 275
}
Dot {
 name Dot2
 selected true
 xpos -143
 ypos 323
}
push $N511d710
Erode {
 size 21
 name Erode1
 label "\nThis Erode makes alpha \nfrom the hard key smaller"
 selected true
 xpos -309
 ypos 169
}
Group {
 inputs 0
 name Group1
 label "\nThis group represents the noisy output from a \nsoft keyer. Notice how the black and white \nare both noisy. However, the edges are nice \nand soft. "
 note_font "Verdana Bold Bold"
 note_font_color 0x7fff00ff
 selected true
 xpos -616
 ypos 13
}
 Noise {
  inputs 0
  output {-rgba.red -rgba.green -rgba.blue rgba.alpha}
  size 13.5
  lacunarity 3.6
  gain 0.425
  gamma 0.23
  center {1024 778}
  name Noise1
  xpos 328
  ypos -173
 }
 Radial {
  inputs 0
  area {516 316 1516 1316}
  softness 0.07
  color {1 0 0 1}
  name Radial5
  selected true
  xpos 465
  ypos -216
 }
set N512b020 [stack 0]
 Crop {
  box {0 0 2048 1556}
  name Crop1
  xpos 465
  ypos -192
 }
 ColorLookup {
  inputs 1+1
  lut {master {}
    red {}
    green {}
    blue {}
    alpha {curve C 0.4973039031 0.478431344}}
  name ColorLookup1
  xpos 465
  ypos -168
 }
 Output {
  name Output1
  xpos 465
  ypos -106
 }
push $N512b020
 Viewer {
  input_process false
  name Viewer1
  xpos 599
  ypos -86
 }
end_group
Merge2 {
 inputs 2
 operation max
 output {-rgba.red -rgba.green -rgba.blue rgba.alpha}
 name Merge3
 label "\nThis Max merge performs the \nHoldout masking."
 note_font Verdana
 selected true
 xpos -616
 ypos 160
}
Merge2 {
 inputs 2
 operation min
 output {-rgba.red -rgba.green -rgba.blue rgba.alpha}
 name Merge4
 label "\nThis Min merge performs the \nJunk masking."
 selected true
 xpos -616
 ypos 298
}
Premult {
 name Premult1
 selected true
 xpos -616
 ypos 454
}
CheckerBoard2 {
 inputs 0
 boxsize 100
 color1 {0.8700000048 0.8700000048 0.8700000048 1}
 color3 1
 name CheckerBoard1
 selected true
 xpos -763
 ypos 399
}
Merge2 {
 inputs 2
 name Merge5
 selected true
 xpos -616
 ypos 498
}

Tip: this is not a recipe to be followed blindly. You must check the progress of your matte combine in the alpha of the Viewer.

Combining masks without effecting the RGB

One of the problems of combining alphas using Merge nodes is that the merge operation can effect the RGB of the image as well as the alpha. The cure for this is twofold:

  1. Make sure that the RGB values you wish to preserve are fed in through the 'B' feed.
  2. Untick the 'R', 'G' and 'B' values of the 'output' parameter.

In this way, the RGB of the B feed will pass through the merge node unchanged.