diff --git a/Filter/DePepper/DePepper.png b/Filter/DePepper/DePepper.png new file mode 100644 index 0000000..c26009e Binary files /dev/null and b/Filter/DePepper/DePepper.png differ diff --git a/Filter/DePepper/DePepper.py b/Filter/DePepper/DePepper.py new file mode 100644 index 0000000..df3b6d4 --- /dev/null +++ b/Filter/DePepper/DePepper.py @@ -0,0 +1,383 @@ +# -*- coding: utf-8 -*- +# DO NOT EDIT THIS FILE +# This file was automatically generated by Natron PyPlug exporter version 10. + +# Hand-written code should be added in a separate file named DePepperExt.py +# See http://natron.readthedocs.org/en/master/groups.html#adding-hand-written-code-callbacks-etc +# Note that Viewers are never exported + +import NatronEngine +import sys + +# Try to import the extensions file where callbacks and hand-written code should be located. +try: + from DePepperExt import * +except ImportError: + pass + +def getPluginID(): + return "natron.community.plugins.DePepper" + +def getLabel(): + return "DePepper" + +def getVersion(): + return 1 + +def getIconPath(): + return "DePepper.png" + +def getGrouping(): + return "Filter" + +def getPluginDescription(): + return "Remove Salt and Pepper Noise\nTest images can be found at http://www.fit.vutbr.cz/~vasicek/imagedb/23 \nNote: of course, if would be better to use the median of neighbor values rather than the average to replace the color. \nIf the noise covers several neighboring pixels, apply it two times." + +def createInstance(app,group): + # Create all nodes in the group + + # Create the parameters of the group node the same way we did for all internal nodes + lastNode = group + + # Create the user parameters + lastNode.userNatron = lastNode.createPageParam("userNatron", "Controls") + param = lastNode.createDoubleParam("DePepperparamValueFloat0", "Threshold for pepper detection") + param.setMinimum(1, 0) + param.setMaximum(2, 0) + param.setDisplayMinimum(1, 0) + param.setDisplayMaximum(2, 0) + param.setDefaultValue(1.070000052452087, 0) + param.restoreDefaultValue(0) + + # Add the param to the page + lastNode.userNatron.addParam(param) + + # Set param properties + param.setAddNewLine(True) + param.setAnimationEnabled(True) + param.setValue(1.1, 0) + lastNode.DePepperparamValueFloat0 = param + del param + + param = lastNode.createDoubleParam("DePepperparamValueFloat1", "Gamma value") + param.setMinimum(1, 0) + param.setMaximum(3, 0) + param.setDisplayMinimum(1, 0) + param.setDisplayMaximum(3, 0) + param.setDefaultValue(2.200000047683716, 0) + param.restoreDefaultValue(0) + + # Add the param to the page + lastNode.userNatron.addParam(param) + + # Set param properties + param.setAddNewLine(True) + param.setAnimationEnabled(True) + param.setValue(1, 0) + lastNode.DePepperparamValueFloat1 = param + del param + + param = lastNode.createSeparatorParam("sep", "") + + # Add the param to the page + lastNode.userNatron.addParam(param) + + # Set param properties + param.setHelp("") + param.setAddNewLine(True) + param.setPersistent(False) + param.setEvaluateOnChange(False) + lastNode.sep = param + del param + + param = lastNode.createBooleanParam("MaskenableMask_Mask", "Mask") + + # Add the param to the page + lastNode.userNatron.addParam(param) + + # Set param properties + param.setAddNewLine(True) + param.setAnimationEnabled(False) + lastNode.MaskenableMask_Mask = param + del param + + param = lastNode.createChoiceParam("MaskmaskChannel_Mask", "") + param.setDefaultValue(4) + param.restoreDefaultValue() + + # Add the param to the page + lastNode.userNatron.addParam(param) + + # Set param properties + param.setAddNewLine(False) + param.setAnimationEnabled(False) + lastNode.MaskmaskChannel_Mask = param + del param + + param = lastNode.createBooleanParam("MaskmaskInvert", "Invert Mask") + + # Add the param to the page + lastNode.userNatron.addParam(param) + + # Set param properties + param.setAddNewLine(False) + param.setAnimationEnabled(False) + lastNode.MaskmaskInvert = param + del param + + param = lastNode.createDoubleParam("Maskmix", "Mix") + param.setMinimum(0, 0) + param.setMaximum(1, 0) + param.setDisplayMinimum(0, 0) + param.setDisplayMaximum(1, 0) + param.setDefaultValue(1, 0) + param.restoreDefaultValue(0) + + # Add the param to the page + lastNode.userNatron.addParam(param) + + # Set param properties + param.setAddNewLine(True) + param.setAnimationEnabled(True) + lastNode.Maskmix = param + del param + + # Refresh the GUI with the newly created parameters + lastNode.setPagesOrder(['userNatron', 'Node']) + lastNode.refreshUserParamsGUI() + del lastNode + + # Start of node "DePepper" + lastNode = app.createNode("net.sf.openfx.Shadertoy", 1, group) + lastNode.setScriptName("DePepper") + lastNode.setLabel("DePepper") + lastNode.setPosition(1192, -873) + lastNode.setSize(80, 43) + lastNode.setColor(0.3, 0.5, 0.2) + groupDePepper = lastNode + + param = lastNode.getParam("paramValueFloat0") + if param is not None: + param.setValue(1.1, 0) + del param + + param = lastNode.getParam("paramValueFloat1") + if param is not None: + param.setValue(1, 0) + del param + + param = lastNode.getParam("imageShaderSource") + if param is not None: + param.setValue("// DePepper filter (remove salt-and-pepper noise)\n// iChannel0: Source, filter=nearest, wrap=clamp\n// Bbox: iChannel0\n\nuniform float scale = 1.07; // Threshold for pepper detection, min=1., max=2.\nuniform float gamma = 2.2; // Gamma value, min=1., max=3.\n\nconst vec2 iRenderScale = vec2(1.,1.);\n\nfloat max3 (vec3 v) {\n return max (max (v.x, v.y), v.z);\n}\n\nfloat min3 (vec3 v) {\n return min (min (v.x, v.y), v.z);\n}\n\nvec3 delinearize(vec3 rgb) {\n return pow(rgb, vec3(1.0/gamma));\n}\n\nvec3 linearize(vec3 rgb) {\n return pow(rgb, vec3(gamma));\n}\n\nvoid mainImage( out vec4 fragColor, in vec2 fragCoord )\n{\n vec3 d1avg = (texture2D(iChannel0, (fragCoord + vec2(-1,-1)) / iResolution.xy).xyz +\n + texture2D(iChannel0, (fragCoord + vec2(+1,+1)) / iResolution.xy).xyz)/2.; //Diagonal Average X\n vec3 d2avg = (texture2D(iChannel0, (fragCoord + vec2(-1,+1)) / iResolution.xy).xyz +\n + texture2D(iChannel0, (fragCoord + vec2(+1,-1)) / iResolution.xy).xyz)/2.;\n vec3 chavg = (texture2D(iChannel0, (fragCoord + vec2(-1,0)) / iResolution.xy).xyz +\n + texture2D(iChannel0, (fragCoord + vec2(+1,0)) / iResolution.xy).xyz)/2.;\n vec3 cvavg = (texture2D(iChannel0, (fragCoord + vec2(0,-1)) / iResolution.xy).xyz +\n + texture2D(iChannel0, (fragCoord + vec2(0,+1)) / iResolution.xy).xyz) /2.;\n \n float invscale = 1/scale;\n vec4 curlin = texture2D(iChannel0, fragCoord / iResolution.xy);\n vec3 curp1 = delinearize(curlin.xyz)+vec3(1.0);\n vec3 chratio = curp1/(delinearize(chavg)+vec3(1.0)); //Cross Ratio, is in the region 0.5..2\n vec3 cvratio = curp1/(delinearize(cvavg)+vec3(1.0)); //Cross Ratio, is in the region 0.5..2\n vec3 d1ratio = curp1/(delinearize(d1avg)+vec3(1.0)); //Diagonal Ratio\n vec3 d2ratio = curp1/(delinearize(d2avg)+vec3(1.0)); //Diagonal Ratio\n \n if( ((max3(chratio) > scale) && (max3(cvratio) > scale) && (max3(d1ratio) > scale) && (max3(d2ratio) > scale)) ||\n ((min3(chratio) < invscale) && (min3(cvratio) < invscale) && (min3(d1ratio) < invscale) && (min3(d2ratio) < invscale)) ) {\n //only replace if boththe four ratios are off, meaning the pixel is different than his neighborhoods\n fragColor = vec4((chavg + cvavg + (d1avg+d2avg)/2)/3.0, curlin.w);\n } else {\n fragColor = curlin; // vec4(1., 0., 0., curlin.w);\n }\n}") + del param + + param = lastNode.getParam("mipmap0") + if param is not None: + param.set("Nearest") + del param + + param = lastNode.getParam("inputLabel0") + if param is not None: + param.setValue("Source") + del param + + param = lastNode.getParam("inputEnable1") + if param is not None: + param.setValue(False) + del param + + param = lastNode.getParam("inputEnable2") + if param is not None: + param.setValue(False) + del param + + param = lastNode.getParam("inputEnable3") + if param is not None: + param.setValue(False) + del param + + param = lastNode.getParam("bbox") + if param is not None: + param.set("iChannel0") + del param + + param = lastNode.getParam("NatronParamFormatChoice") + if param is not None: + param.set("PC_Video 640x480") + del param + + param = lastNode.getParam("mouseParams") + if param is not None: + param.setValue(False) + del param + + param = lastNode.getParam("paramCount") + if param is not None: + param.setValue(2, 0) + del param + + param = lastNode.getParam("paramType0") + if param is not None: + param.set("float") + del param + + param = lastNode.getParam("paramName0") + if param is not None: + param.setValue("scale") + del param + + param = lastNode.getParam("paramLabel0") + if param is not None: + param.setValue("Threshold for pepper detection") + del param + + param = lastNode.getParam("paramDefaultFloat0") + if param is not None: + param.setValue(1.070000052452087, 0) + del param + + param = lastNode.getParam("paramMinFloat0") + if param is not None: + param.setValue(1, 0) + del param + + param = lastNode.getParam("paramMaxFloat0") + if param is not None: + param.setValue(2, 0) + del param + + param = lastNode.getParam("paramType1") + if param is not None: + param.set("float") + del param + + param = lastNode.getParam("paramName1") + if param is not None: + param.setValue("gamma") + del param + + param = lastNode.getParam("paramLabel1") + if param is not None: + param.setValue("Gamma value") + del param + + param = lastNode.getParam("paramDefaultFloat1") + if param is not None: + param.setValue(2.200000047683716, 0) + del param + + param = lastNode.getParam("paramMinFloat1") + if param is not None: + param.setValue(1, 0) + del param + + param = lastNode.getParam("paramMaxFloat1") + if param is not None: + param.setValue(3, 0) + del param + + del lastNode + # End of node "DePepper" + + # Start of node "Source" + lastNode = app.createNode("fr.inria.built-in.Input", 1, group) + lastNode.setScriptName("Source") + lastNode.setLabel("Source") + lastNode.setPosition(1180, -1070) + lastNode.setSize(104, 43) + lastNode.setColor(0.3, 0.5, 0.2) + groupSource = lastNode + + del lastNode + # End of node "Source" + + # Start of node "Output1" + lastNode = app.createNode("fr.inria.built-in.Output", 1, group) + lastNode.setLabel("Output1") + lastNode.setPosition(1609, -617) + lastNode.setSize(104, 30) + lastNode.setColor(0.7, 0.7, 0.7) + groupOutput1 = lastNode + + del lastNode + # End of node "Output1" + + # Start of node "Mask" + lastNode = app.createNode("net.sf.openfx.MergePlugin", 1, group) + lastNode.setScriptName("Mask") + lastNode.setLabel("Mask") + lastNode.setPosition(1345, -885) + lastNode.setSize(104, 66) + lastNode.setColor(0.3, 0.37, 0.776) + groupMask = lastNode + + del lastNode + # End of node "Mask" + + # Start of node "Dot1" + lastNode = app.createNode("fr.inria.built-in.Dot", 1, group) + lastNode.setScriptName("Dot1") + lastNode.setLabel("Dot1") + lastNode.setPosition(1225, -945) + lastNode.setSize(15, 15) + lastNode.setColor(0.7, 0.7, 0.7) + groupDot1 = lastNode + + del lastNode + # End of node "Dot1" + + # Start of node "Source_2" + lastNode = app.createNode("fr.inria.built-in.Input", 1, group) + lastNode.setScriptName("Source_2") + lastNode.setLabel("Mask") + lastNode.setPosition(1551, -885) + lastNode.setSize(104, 43) + lastNode.setColor(0.3, 0.5, 0.2) + groupSource_2 = lastNode + + param = lastNode.getParam("optional") + if param is not None: + param.setValue(True) + del param + + param = lastNode.getParam("isMask") + if param is not None: + param.setValue(True) + del param + + del lastNode + # End of node "Source_2" + + # Now that all nodes are created we can connect them together, restore expressions + groupDePepper.connectInput(0, groupDot1) + groupOutput1.connectInput(0, groupMask) + groupMask.connectInput(0, groupDot1) + groupMask.connectInput(1, groupDePepper) + groupMask.connectInput(2, groupSource_2) + groupDot1.connectInput(0, groupSource) + + param = groupDePepper.getParam("paramValueFloat0") + group.getParam("DePepperparamValueFloat0").setAsAlias(param) + del param + param = groupDePepper.getParam("paramValueFloat1") + group.getParam("DePepperparamValueFloat1").setAsAlias(param) + del param + param = groupMask.getParam("maskInvert") + group.getParam("MaskmaskInvert").setAsAlias(param) + del param + param = groupMask.getParam("mix") + group.getParam("Maskmix").setAsAlias(param) + del param + param = groupMask.getParam("enableMask_Mask") + group.getParam("MaskenableMask_Mask").setAsAlias(param) + del param + param = groupMask.getParam("maskChannel_Mask") + group.getParam("MaskmaskChannel_Mask").setAsAlias(param) + del param + + try: + extModule = sys.modules["DePepperExt"] + except KeyError: + extModule = None + if extModule is not None and hasattr(extModule ,"createInstanceExt") and hasattr(extModule.createInstanceExt,"__call__"): + extModule.createInstanceExt(app,group) diff --git a/Filter/DePepper/DePepper.xml b/Filter/DePepper/DePepper.xml new file mode 100644 index 0000000..78de7fa --- /dev/null +++ b/Filter/DePepper/DePepper.xml @@ -0,0 +1,10 @@ + + + DePepper + Remove Salt and Pepper noise + 1.0 + @DATE@ + natron.community.plugins.DePepper + script + + diff --git a/Filter/DePepper/README.md b/Filter/DePepper/README.md new file mode 100644 index 0000000..2cc6e46 --- /dev/null +++ b/Filter/DePepper/README.md @@ -0,0 +1,11 @@ +# DePepper + +Remove Salt and Pepper noise. + +Test images can be found at http://www.fit.vutbr.cz/~vasicek/imagedb/23 + +Note: of course, if would be better to use the median of neighbor values rather than the average to replace the color. + +If the noise covers several neighboring pixels, apply it two times. + +Original Shader by Frederic Devernay.