File: //opt/resolve/Developer/Fusion Fuse/Blur Merge.fuse
--[[--
Example Fuse 2
This will Blur the background and Fore ground images and Merge the Foreground over Background.
Copyright (c) 2018-2020, BMD, by SR
This Fuse Demos built in image processing functions in Fusion.
This Uses Fusion internal Image processing operations:
Blur will blur and image from one image to a destination image.
Merge will overlay one image over another.
These Functions have many options and processing types. See inline comments
--]]--
--******************************************************************************************************
-- This Registers the Fuse into Fusion, gives its Name, and Menu location. Location of Help. Can Fuse be edited.
FuRegisterClass("ExampleBlurMerge", CT_Tool, {
REGS_Name = "BlurMerge",
REGS_Category = "Fuses\\Examples",
REGS_OpIconString = "BlrM",
REGS_OpDescription = "Example, using internal Image Processing functions Blur and Merge",
REGS_HelpTopic = "Example Location of Help", --This can be a URL
REGS_URL = "www.blackmagicdesign.com",
--REGS_IconID = "Icons.Tools.Icons.Example",-- This can be Inline as an array of Values
REG_OpNoMask = true,
REG_NoBlendCtrls = true,
REG_NoObjMatCtrls = true,
REG_NoMotionBlurCtrls = true,
REG_NoBlendCtrls = false,
REG_Fuse_NoEdit = false,
REG_Fuse_NoReload = false,
REG_Version = 1,
}) -- End of RegisterClass
--****************************************************************************************************
--Create will define all the controls, like sliders, check boxes, onscreen crosshairs etc, that will show in Inspector Tool control area
function Create()
-- Control Nest will define which controls are nested into a group to compact and organizie the Inspector.
self:BeginControlNest("Blur", "BlurNest", true);
InBlurFilter = self:AddInput("Blur Filter", "BlurFilter", {
LINKID_DataType = "Number",
INPID_InputControl = "ComboControl",
INP_Integer = true,
ICD_Width = 1.0,
CC_LabelPosition = "Horizontal",
INP_Default = 5,
{CCS_AddString = "Box", },
{CCS_AddString = "Soften", },
{CCS_AddString = "Bartlett", },
{CCS_AddString = "Sharpen", },
{CCS_AddString = "Gaussian", },
{CCS_AddString = "FastGaussian", },
{CCS_AddString = "Hilight", },
{CCS_AddString = "Blend", },
{CCS_AddString = "Solarize", },
{CCS_AddString = "Multi-box", },
INP_DoNotifyChanged = true, -- We want to hear about changes on this control
})
InR = self:AddInput("Red", "Red", {
LINKID_DataType = "Number",
INPID_InputControl = "CheckboxControl",
INP_Integer = true,
INP_Default = 1,
ICD_Width = 0.25,
})
InG = self:AddInput("Green", "Green", {
LINKID_DataType = "Number",
INPID_InputControl = "CheckboxControl",
INP_Integer = true,
INP_Default = 1,
ICD_Width = 0.25,
})
InB = self:AddInput("Blue", "Blue", {
LINKID_DataType = "Number",
INPID_InputControl = "CheckboxControl",
INP_Integer = true,
INP_Default = 1,
ICD_Width = 0.25,
})
InA = self:AddInput("Alpha", "Alpha", {
LINKID_DataType = "Number",
INPID_InputControl = "CheckboxControl",
INP_Integer = true,
INP_Default = 1,
ICD_Width = 0.25,
})
InLockXY = self:AddInput("Lock X/Y Blur", "LockXY", {
LINKID_DataType = "Number",
INPID_InputControl = "CheckboxControl",
INP_Integer = true,
INP_Default = 1.0,
INP_DoNotifyChanged = true, -- We want to hear about changes on this control
})
InBlurFg = self:AddInput("X Blur Foreground", "XBlurFg", {
LINKS_Name = "Blur Size",
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_MaxScale = 20.0,
INP_MinScale = 0.0,
INP_Default = 0.0,
})
InBlurFgY = self:AddInput("Y Blur Foreground", "YBlurFg", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_MaxScale = 20.0,
INP_MinScale = 0.0,
INP_Default = 0.0,
IC_Visible = false,
})
InBlurBg = self:AddInput("X Blur Background", "XBlurBg", {
LINKS_Name = "Blur Size",
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_MaxScale = 20.0,
INP_MinScale = 0.0,
INP_Default = 0.0,
})
InBlurBgY = self:AddInput("Y Blur Background", "YBlurBg", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_MaxScale = 20.0,
INP_MinScale = 0.0,
INP_Default = 0.0,
IC_Visible = false,
})
self:EndControlNest()
-- Control Nest will define which controls are nested into a group to compact and organizie the Inspector.
self:BeginControlNest("Merge", "MergeNest", true);
InCenter = self:AddInput("Center", "Center", {
LINKID_DataType = "Point",
INPID_InputControl = "OffsetControl",
INPID_PreviewControl = "CrosshairControl",
INP_DefaultX = 0.5,
INP_DefaultY = 0.5,
})
InSize = self:AddInput("Size", "Size", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_MaxScale = 5.0,
INP_MinScale = 0.0,
ICD_Center = 1, -- this sets the default value to the center of the slider
INP_Default = 1.0,
INP_MinAllowed = 0,
})
InAngle = self:AddInput("Angle", "Angle", {
LINKID_DataType = "Number",
INPID_InputControl = "ScrewControl",
INP_MinScale = 0.0,
INP_MaxScale = 100.0,
INP_Default = 0,
})
InApply = self:AddInput("Merge Apply Mode", "ApplyMode", {
LINKID_DataType = "Number",
INPID_InputControl = "ComboControl",
INP_Default = 0.0,
INP_Integer = true,
--ICD_Width = 0.5,
CC_LabelPosition = "Horizontal",
INP_DoNotifyChanged = true,
{ CCS_AddString = "Normal", },
{ CCID_AddID = "Merge", },
{ CCS_AddString = "Screen", },
{ CCS_AddString = "Dissolve", },
{ CCS_AddSeparator = "", },
{ CCS_AddString = "Darken", },
{ CCS_AddString = "Multiply", },
{ CCS_AddString = "Color Burn", },
{ CCID_AddID = "ColorBurn", },
{ CCS_AddString = "Linear Burn", },
{ CCID_AddID = "LinearBurn", },
{ CCS_AddString = "Darker Color", },
{ CCID_AddID = "DarkerColor", },
{ CCS_AddSeparator = "", },
{ CCS_AddString = "Lighten", },
{ CCS_AddString = "Color Dodge", },
{ CCID_AddID = "ColorDodge", },
{ CCS_AddString = "Linear Dodge", },
{ CCID_AddID = "LinearDodge", },
{ CCS_AddString = "Lighter Color", },
{ CCID_AddID = "LighterColor", },
{ CCS_AddSeparator = "", },
{ CCS_AddString = "Overlay", },
{ CCS_AddString = "Soft Light", },
{ CCID_AddID = "SoftLight", },
{ CCS_AddString = "Hard Light", },
{ CCID_AddID = "HardLight", },
{ CCS_AddString = "Vivid Light", },
{ CCID_AddID = "VividLight", },
{ CCS_AddString = "Linear Light", },
{ CCID_AddID = "LinearLight", },
{ CCS_AddString = "Pin Light", },
{ CCID_AddID = "PinLight", },
{ CCS_AddSeparator = "", },
{ CCS_AddString = "Difference", },
{ CCS_AddString = "Exclusion", },
{ CCS_AddSeparator = "", },
{ CCS_AddString = "Hue", },
{ CCS_AddString = "Saturation", },
{ CCS_AddString = "Color", },
{ CCS_AddString = "Luminosity", },
{ CCS_AddSeparator = "", },
{ CCS_AddString = "Hypotenuse", },
{ CCS_AddString = "Geometric", },
})
InOperation = self:AddInput("Operator", "Operator", {
LINKID_DataType = "Number",
INPID_InputControl = "ComboControl",
INP_Default = 0.0,
INP_Integer = true,
--ICD_Width = 0.5,
CC_LabelPosition = "Horizontal",
{ CCS_AddString = "Over", },
{ CCS_AddString = "In", },
{ CCS_AddString = "Held Out", },
{ CCID_AddID = "HeldOut", },
{ CCS_AddString = "Atop", },
{ CCS_AddString = "XOr", },
{ CCS_AddString = "Conjoint", },
{ CCS_AddString = "Disjoint", },
{ CCS_AddString = "Mask", },
{ CCS_AddString = "Stencil", },
{ CCS_AddString = "Under", },
})
InAdditive = self:AddInput("Subtractive - Additive", "SubtractiveAdditive", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_Default = 1.0,
SLCS_LowName = "Subtractive",
SLCS_HighName = "Additive",
})
InAlpha = self:AddInput("Alpha Gain", "AlphaGain", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_Default = 1.0,
})
InBurn = self:AddInput("Burn In", "BurnIn", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_Default = 0.0,
})
InBlend = self:AddInput("Blend", "Blend", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
-- ICD_Width = 0.5,
ICS_ControlPage = "Controls",
INP_Default = 1.0,
INP_MinAllowed = 0,
INP_MaxAllowed = 1,
})
self:EndControlNest()
-- AddControlPage will create a new Tab in the inxpector for Tool controls
self:AddControlPage("Color")
InGainFR = self:AddInput("Gain Red Fg", "GainRF", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_MaxScale = 2.0,
INP_MinScale = 0.0,
INP_Default = 1.0,
})
InGainFG = self:AddInput("Gain Green Fg", "GainGF", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_MaxScale = 2.0,
INP_MinScale = 0.0,
INP_Default = 1.0,
})
InGainFB = self:AddInput("Gain Blue Fg", "GainBF", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_MaxScale = 2.0,
INP_MinScale = 0.0,
INP_Default = 1.0,
})
InGainFA = self:AddInput("Gain Alpha Fg", "GainAF", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_MaxScale = 2.0,
INP_MinScale = 0.0,
INP_Default = 1.0,
})
InGainBR = self:AddInput("Gain Red Bg", "GainRB", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_MaxScale = 2.0,
INP_MinScale = 0.0,
INP_Default = 1.0,
})
InGainBG = self:AddInput("Gain Green Bg", "GainGB", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_MaxScale = 2.0,
INP_MinScale = 0.0,
INP_Default = 1.0,
})
InGainBB = self:AddInput("Gain Blue Bg", "GainBB", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_MaxScale = 2.0,
INP_MinScale = 0.0,
INP_Default = 1.0,
})
InGainBA = self:AddInput("Gain Alpha Bg", "GainAB", {
LINKID_DataType = "Number",
INPID_InputControl = "SliderControl",
INP_MaxScale = 2.0,
INP_MinScale = 0.0,
INP_Default = 1.0,
})
--***********************************************
-- Image Inputs are used to get images into the Tool
InBackground = self:AddInput("Background", "Background", {
LINKID_DataType = "Image",
INPID_InputControl = "ImageControl",
ICS_ControlPage = "Controls",
LINK_Main = 1,
})
-- The Foreground Image input
InForeground = self:AddInput("Foreground", "Foreground", {
LINKID_DataType = "Image",
INPID_InputControl = "ImageControl",
ICS_ControlPage = "Controls",
LINK_Main = 2,
INP_Required = false,
})
-- The output is an Image
OutImage = self:AddOutput("Output", "Output", {
LINKID_DataType = "Image",
LINK_Main = 1,
})
end -- end of Create()
--***************************************************************************************************
-- Notify Changed is used to Hide or Show controls when options are selected in the Tool's control inspector
function NotifyChanged(inp, param, time)
if inp == InLockXY then -- If Blur Lock X/Y is changed, then rename the Control names and Un/Hide sliders
local locked = (param.Value > 0.5)
if locked then
InBlurFg:SetAttrs({ LINKS_Name = "Blur Foreground" })
InBlurFgY:SetAttrs({ IC_Visible = false })
InBlurBg:SetAttrs({ LINKS_Name = "Blur Background" })
InBlurBgY:SetAttrs({ IC_Visible = false })
else
InBlurFg:SetAttrs({ LINKS_Name = "X Blur Foreground" })
InBlurFgY:SetAttrs({ IC_Visible = true })
InBlurBg:SetAttrs({ LINKS_Name = "X Blur Background" })
InBlurBgY:SetAttrs({ IC_Visible = true })
end
end
if inp == InApply then -- Show/Hide Merge Operator method when set to Normal
local normal = (param.Value )
if normal ==0 then
InOperation:SetAttrs({ IC_Visible = true})
else
InOperation:SetAttrs({ IC_Visible = false})
end
end
end
--*************************************************************************************************************
-- The Process section is the main section where the image processing rendering occurs
function Process(req)
-- Get Values from the Control panel from the Inspector Tool Controls
-- Get Images imputs and create output and temp image like the original.
local bg = InBackground:GetValue(req)
local out = Image({IMG_Like = bg})
local fg = InForeground:GetValue(req)
local tmpimg = Image({IMG_Like = fg})
-- Get Blur values
local blurFgX = InBlurFg:GetValue(req).Value
local blurFgY
local blurBgX = InBlurBg:GetValue(req).Value
local blurBgY
local locked = (InLockXY:GetValue(req).Value > 0.5)
if locked == true then -- IF Lock X\Y is selected make Blur Y the same or Get the Blur Y number
blurFgY = blurFgX
blurBgY = blurBgX
else
blurFgY = InBlurFgY:GetValue(req).Value
blurBgY = InBlurBgY:GetValue(req).Value
end
local blurfilter = InBlurFilter:GetValue(req).Value
local do_r = InR:GetValue(req).Value
local do_g = InG:GetValue(req).Value
local do_b = InB:GetValue(req).Value
local do_a = InA:GetValue(req).Value
local gain_rF = InGainFR:GetValue(req).Value
local gain_gF = InGainFG:GetValue(req).Value
local gain_bF = InGainFB:GetValue(req).Value
local gain_aF = InGainFA:GetValue(req).Value
local gain_rB = InGainBR:GetValue(req).Value
local gain_gB = InGainBG:GetValue(req).Value
local gain_bB = InGainBB:GetValue(req).Value
local gain_aB = InGainBA:GetValue(req).Value
--Do the Blur functions
if fg then -- Only do the Blur if the Foreground image is present
if blurFgX ==0.0 and blurFgY == 0.0 then
out = bg:Copy()
tmpimg=fg
else
out = bg:Copy()
fg:Blur(tmpimg, { -- Blur will blur FG into the result tmpimg
BLUR_Type = blurfilter,
BLUR_Red = do_r == 1 and true or false,
BLUR_Green = do_g == 1 and true or false,
BLUR_Blue = do_b == 1 and true or false,
BLUR_Alpha = do_a == 1 and true or false,
BLUR_XSize = blurFgX/720,
BLUR_YSize = blurFgY/720,
BLUR_Blend = 1.0,
BLUR_Normalize = op==1 and glow or 1.0,
BLUR_Passes = 0.0,
BLUR_RedScale = gain_rF,
BLUR_GreenScale = gain_gF,
BLUR_BlueScale = gain_bF,
BLUR_AlphaScale = gain_aF,
})
end
end
if blurBgX > 0.0 or blurBgY > 0.0 then
bg:Blur(out, { -- Blur will blur BG into the result out
BLUR_Type = blurfilter,
BLUR_Red = do_r == 1 and true or false,
BLUR_Green = do_g == 1 and true or false,
BLUR_Blue = do_b == 1 and true or false,
BLUR_Alpha = do_a == 1 and true or false,
BLUR_XSize = blurBgX/720,
BLUR_YSize = blurBgY/720,
BLUR_Blend = 1.0,
BLUR_Normalize = op==1 and glow or 1.0,
BLUR_Passes = 0.0,
BLUR_RedScale = gain_rB,
BLUR_GreenScale = gain_gB,
BLUR_BlueScale = gain_bB,
BLUR_AlphaScale = gain_aB,
})
end
-- Get the values from the Tool controls from the Inspector for the Merge
local center = InCenter:GetValue(req) -- This has 2 Outputs X & Y
local xsize = InSize:GetValue(req).Value
local ysize = InSize:GetValue(req).Value
local angle = InAngle:GetValue(req).Value
local additive = InAdditive:GetValue(req).Value
local gain_alpha = InAlpha:GetValue(req).Value
local burn = InBurn:GetValue(req).Value
local apply_mode = InApply:GetValue(req).Value + 1
local apply_operator = InOperation:GetValue(req).Value + 1
local blend = InBlend:GetValue(req).Value
local apply_modes = {
"Merge",
"Screen",
"Dissolve",
"Multiply",
"Overlay",
"SoftLight",
"HardLight",
"ColorDodge",
"ColorBurn",
"Darken",
"Lighten",
"Difference",
"Exclusion",
"Hue",
"Saturation",
"Color",
"Luminosity",
}
local apply_operators = { "Over", "In", "Held Out", "Atop", "XOr", }
--Merge will overlay the Foreground( tmpimg) over the copy Background image (out)
if fg then -- Only do the Merge if the Foreground image is present
out:Merge(tmpimg, {
MO_ApplyMode = apply_modes[apply_mode],
MO_ApplyOperator = apply_operators[apply_operator],
MO_XOffset = center.X,
MO_YOffset = center.Y,
MO_XAxis= 0.5,
MO_YAxis =0.5,
MO_XSize = xsize,
MO_YSize = ysize,
MO_Angle = angle,
MO_FgAddSub = additive,
MO_BgAddSub = additive,
MO_BurnIn = burn,
MO_FgRedGain = 1.0,
MO_FgGreenGain = 1.0,
MO_FgBlueGain = 1.0,
MO_FgAlphaGain = gain_alpha,
MO_Invert = 1,
MO_DoZ = false,
})
end
-- Done with processing. Output image.
OutImage:Set(req, out)
end -- end Process()