Skip to main content
Participating Frequently
November 23, 2019
Answered

Batch Median Noise Reduction

  • November 23, 2019
  • 5 replies
  • 5411 views

Hi,

I have a night timelapse consisting of single images where the foreground is very noisy. What I want to do is open three images, create a smartobject and then use the stackmode median to reduce noise. Then photoshop should move foreward one image and yet again open three images. Is there a way to automate this using actions and the batch editing? I didn't find a way to open more than one image automatically...

 

Thanks for your help!

Jakob

This topic has been closed for replies.
Correct answer Stephen Marsh

It would be best to use scriptListener and record stacking the images using mean, then replace the code for median, in the last function in the above script. 


As suggested by Chuck, here is the modified script for mean blending:

 

 

/* 
https://community.adobe.com/t5/photoshop/batch-median-noise-reduction/m-p/10758011?page=1#M285346
Batch Median Noise Reduction
*/

#target photoshop
var srcFolder = new Folder('~/desktop/source/');
var doneFolder = new Folder(srcFolder + '/done/');
if (!doneFolder.exists) {
    doneFolder.create()
};

var jpgOptions = new JPEGSaveOptions();
jpgOptions.quality = 8
var mask = '*.jpg'
var fList = srcFolder.getFiles(mask);

for (var i = 0; i < fList.length; i++) {
    try {
        open(fList[i])
    } catch (e) { };
    try {
        open(fList[i - 1])
    } catch (e) { };
    try {
        open(fList[i + 1])
    } catch (e) { };

    var base = activeDocument = app.documents[0];
    base.flatten();
    base.layers[0].isBackgroundLayer = false;
    var docNum = app.documents.length;
    for (var j = 1; j < docNum; j++) {
        var nextDoc = activeDocument = app.documents[1];
        nextDoc.flatten();
        nextDoc.activeLayer.duplicate(base.layers[0], ElementPlacement.PLACEBEFORE);
        nextDoc.close(SaveOptions.DONOTSAVECHANGES);
    }

    base.layers[base.layers.length - 1].isBackgroundLayer = false;
    selectAllLayers();
    makeSO();
    makeMean();
    base.flatten();
    var fName = base.name.split('.')[0];
    base.saveAs(new File(doneFolder + '/Median-' + fName + '.jpg'), jpgOptions);
    base.close(SaveOptions.DONOTSAVECHANGES);
}; //end loop

function selectAllLayers() {
    var idselectAllLayers = stringIDToTypeID("selectAllLayers");
    var desc3 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref1 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idTrgt = charIDToTypeID("Trgt");
    ref1.putEnumerated(idLyr, idOrdn, idTrgt);
    desc3.putReference(idnull, ref1);
    executeAction(idselectAllLayers, desc3, DialogModes.NO);
}

function makeSO() {
    var idnewPlacedLayer = stringIDToTypeID("newPlacedLayer");
    executeAction(idnewPlacedLayer, undefined, DialogModes.NO);
}

function makeMean() {
    var idapplyImageStackPluginRenderer = stringIDToTypeID("applyImageStackPluginRenderer");
    var desc252 = new ActionDescriptor();
    var idimageStackPlugin = stringIDToTypeID("imageStackPlugin");
    var idavrg = charIDToTypeID("avrg");
    desc252.putClass(idimageStackPlugin, idavrg);
    var idNm = charIDToTypeID("Nm  ");
    desc252.putString(idNm, """Mean""");
    executeAction(idapplyImageStackPluginRenderer, desc252, DialogModes.NO);
}

 

5 replies

Stephen Marsh
Community Expert
Community Expert
April 11, 2021

@Seta666 

 

Try the following code and let me know how it goes. It will combine files into sets of 4 and merge into a smart object stack with median blend mode.  A new directory will be created within the input folder where the files are saved.  File names are based off either the 4th, 8th etc file name in each set of 4 – or it is easily modified to use the 1st, 5th name etc.

 

Filenames are expected to be in correct alpha/numeric sorting order.

 

 

 

/* 

Stack Sets of 4 Images with Median Blend.jsx

Stephen Marsh - 17th April 2021

This script is based around alpha/numeric sorting files

Batch Median Noise Reduction
https://community.adobe.com/t5/photoshop/batch-median-noise-reduction/m-p/11960956#M529922

*/

#target photoshop

if (app.documents.length === 0) {

    try {

        // Save and disable dialogs
        var restoreDialogMode = app.displayDialogs;
        app.displayDialogs = DialogModes.NO;

        batchSetProcessing();

        function batchSetProcessing() {

            // Select the input folder
            inputFolder = Folder.selectDialog('Please select the folder with files to process');
            if (inputFolder === null) return;

            // Create the output sub-directory
            var outputFolder = Folder(decodeURI(inputFolder + '/Output Sets Folder'));
            if (!outputFolder.exists) outputFolder.create();

            // Limit the file format input
            var fileList = inputFolder.getFiles(/\.(tif|tiff)$/i);

            // Force alpha-numeric list sort
            // Use .reverse() for the first filename in the merged file
            // Remove .reverse() for the last filename in the merged file
            fileList.sort().reverse();

            // Images per set
            var setQty = 4;

            // Validate the input count vs. output count
            var inputCount = fileList.length;
            // Thanks to Kukurykus for the advice to test using % modulus
            var cancelScript = !(inputCount % setQty);
            alert(inputCount + ' input files stacked into sets of ' + setQty + ' will produce ' + inputCount / setQty + ' file sets.');
            // Test if false, then terminate the script
            if (cancelScript === false) {
                alert('Script cancelled as the quantity of input files are not evenly divisible by the set quantity.');
                return;
            }

            // Loop through and open the file sets
            while (fileList.length) {
                // Sets of N files
                for (var a = 0; a < setQty; a++) {
                    try {
                        app.open(fileList.pop());
                    } catch (e) { }
                }

                processOpenImages();

            }

            // End of script notification
            var outputList = outputFolder.getFiles(/\.(tif|tiff)$/i);
            alert('Script completed!' + '\n' + outputList.length + ' combined files saved to:' + '\n' + outputFolder.fsName);

            // Restore saved dialogs
            app.displayDialogs = restoreDialogMode;

            function processOpenImages() {

                try {

                    app.activeDocument = documents[0];
                    docNameToLayerName();

                    // Combine open docs to base doc
                    while (app.documents.length) {
                        app.activeDocument = documents[1];
                        docNameToLayerName();
                        app.activeDocument.activeLayer.duplicate(documents[0]);
                        app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
                    }

                    app.activeDocument.flatten();

                    function docNameToLayerName() {
                        var layerName = app.activeDocument.name.replace(/\.[^\.]+$/, '');
                        app.activeDocument.activeLayer.name = layerName;
                    }

                } catch (e) { }

                // Select all layers
                app.runMenuItem(stringIDToTypeID("selectAllLayers"));

                // Create a smart object from all selected layers
                makeSO();

                // Smart object median stack blend mode
                makeMedian();

                // Save name+suffix & save path
                var Name = app.activeDocument.name.replace(/\.[^\.]+$/, '');
                var saveFile = File(outputFolder + '/' + Name + '_MedianBlend' + '.tif');

                // Call the save function
                saveTIFF(saveFile);

                // Close all open files without saving
                while (app.documents.length) {
                    app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
                }

                // Functions

                function makeSO() {
                    var idnewPlacedLayer = stringIDToTypeID("newPlacedLayer");
                    executeAction(idnewPlacedLayer, undefined, DialogModes.NO);
                }

                function makeMedian() {
                    var idapplyImageStackPluginRenderer = stringIDToTypeID("applyImageStackPluginRenderer");
                    var desc6 = new ActionDescriptor();
                    var idimageStackPlugin = stringIDToTypeID("imageStackPlugin");
                    var idmedn = charIDToTypeID("medn");
                    desc6.putClass(idimageStackPlugin, idmedn);
                    var idNm = charIDToTypeID("Nm  ");
                    desc6.putString(idNm, """Median""");
                    executeAction(idapplyImageStackPluginRenderer, desc6, DialogModes.NO);
                }

                function saveTIFF(saveFile) {
                    tiffSaveOptions = new TiffSaveOptions();
                    tiffSaveOptions.embedColorProfile = true;
                    tiffSaveOptions.byteOrder = ByteOrder.IBM;
                    tiffSaveOptions.transparency = true;
                    // Change .layers to true to preserve layers
                    tiffSaveOptions.layers = false;
                    tiffSaveOptions.layerCompression = LayerCompression.ZIP;
                    tiffSaveOptions.interleaveChannels = true;
                    tiffSaveOptions.alphaChannels = true;
                    tiffSaveOptions.annotations = true;
                    tiffSaveOptions.spotColors = true;
                    tiffSaveOptions.saveImagePyramid = false;
                    // Image compression = NONE | JPEG | TIFFLZW | TIFFZIP
                    tiffSaveOptions.imageCompression = TIFFEncoding.TIFFLZW;
                    // Save as
                    app.activeDocument.saveAs(saveFile, tiffSaveOptions, true, Extension.LOWERCASE);
                }
            }
        }

    } catch (e) {
        // Restore saved dialogs
        app.displayDialogs = restoreDialogMode;
    }

} else {
    alert('Please close all open documents before running this script!');
}

 

 

 

Participating Frequently
April 11, 2021

@Stephen Marsh 

 

Thank you so much!! I will try it tomorrow and let you know

 

I want to use it macro shots with focus stacking, hopping to get lower noise/better DR as noise is treated by stacking software as detail. Kind of pseudo high resolution mode some modern cameras have.

 

 

Participating Frequently
April 11, 2021

I may sound dumb but how I convert this text to a script file photoshop recognizes? I  have not used this feature before..

Chuck Uebele
Community Expert
Community Expert
November 26, 2019

So, I'm curious how the end video looked by combining the layers in this way? No odd artifacts from ghosting images?

Participating Frequently
December 1, 2019

Sorry for the late reply... So I didn't apply this technique to the shot I intended to, but I used it for the shot at 0:14 https://youtu.be/Nqcr3E8KZHE

Most of the planes are gone, just one looking a bit odd and I added a satellite back in with After Effects. I did however change your script to work with tif files and I stacked 5 images. I think it looks awesome and I would use this technique again.

Participating Frequently
April 10, 2021

Thanks guys! I tried "mean" as the charID, but that didn't work, "avrg" it is 😄

 


Hi, 

I am new here. I was looking for a simmilar script in google and found this.  

I would like to open 4 16 bit TIFF files at the time, do median and save as 16 bit TIFF (no layers); then move to the next 4 files until done. 

Can someone please edit this script to do so?

Thanks in advance

Chuck Uebele
Community Expert
Community Expert
November 24, 2019

Try this script. It will pull the files from a folder on your desktop called "source," but you can change the folder by editing the path in the code. It will save to a subfolder, called done, in the same folder. It will append the files with "median" so files don't get over written. It will also save the files as jpgs, and only open jpgs. You can change the file type by changing the extension in the line: 

var mask = '*.jpg'

 

#target photoshop
var srcFolder = new Folder('~/desktop/source/');
var doneFolder = new Folder(srcFolder + '/done/');
if(!doneFolder.exists){doneFolder.create()};

var jpgOptions = new JPEGSaveOptions();
jpgOptions.quality = 8
var mask = '*.jpg'
var fList = srcFolder.getFiles (mask);

for(var i=0;i<fList.length;i++){
    try{
        open(fList[i])
        }
    catch(e){};
    try{
        open(fList[i -1])
        }
    catch(e){};
    try{
        open(fList[i +1])
        }
    catch(e){};
    
    var base = activeDocument = app.documents[0];
    base.flatten();
    base.layers[0].isBackgroundLayer = false;
    var docNum = app.documents.length;
    for(var j=1;j<docNum;j++){
        var nextDoc = activeDocument = app.documents[1];
        nextDoc.flatten();
        nextDoc.activeLayer.duplicate (base.layers[0], ElementPlacement.PLACEBEFORE);
        nextDoc.close(SaveOptions.DONOTSAVECHANGES);
        }
    
    base.layers[base.layers.length -1].isBackgroundLayer = false;
    selectAllLayers ();
    makeSO ();
    makeMedian ();
    base.flatten();
    var fName = base.name.split('.')[0];
    base.saveAs (new File(doneFolder + '/Median-' + fName + '.jpg'), jpgOptions);
    base.close(SaveOptions.DONOTSAVECHANGES);
    };//end loop

function selectAllLayers(){
    var idselectAllLayers = stringIDToTypeID( "selectAllLayers" );
        var desc3 = new ActionDescriptor();
        var idnull = charIDToTypeID( "null" );
            var ref1 = new ActionReference();
            var idLyr = charIDToTypeID( "Lyr " );
            var idOrdn = charIDToTypeID( "Ordn" );
            var idTrgt = charIDToTypeID( "Trgt" );
            ref1.putEnumerated( idLyr, idOrdn, idTrgt );
        desc3.putReference( idnull, ref1 );
    executeAction( idselectAllLayers, desc3, DialogModes.NO );
    }

function makeSO(){
    var idnewPlacedLayer = stringIDToTypeID( "newPlacedLayer" );
    executeAction( idnewPlacedLayer, undefined, DialogModes.NO );    
    }

function makeMedian(){
    var idapplyImageStackPluginRenderer = stringIDToTypeID( "applyImageStackPluginRenderer" );
        var desc6 = new ActionDescriptor();
        var idimageStackPlugin = stringIDToTypeID( "imageStackPlugin" );
        var idmedn = charIDToTypeID( "medn" );
        desc6.putClass( idimageStackPlugin, idmedn );
        var idNm = charIDToTypeID( "Nm  " );
        desc6.putString( idNm, """Median""" );
    executeAction( idapplyImageStackPluginRenderer, desc6, DialogModes.NO );    
    }

 

 

Participating Frequently
November 24, 2019

Wow, thank you so much! It works perfectly.

Bojan Živković11378569
Community Expert
Community Expert
November 23, 2019

"I didn't find a way to open more than one image automatically..."

File > Scripts > Load Files into Stack command can open multiple files and position them one above another in the Layers panel if I understand what you want to ask.

Participating Frequently
November 23, 2019

Yes, that's what I want, but automated. So Photoshop should open file 1, 2 and 3 then create a Smartobject with these three layers, use stack mode median and save the image. Then I want to open files 2, 3 and 4 and do the same, then 3, 4 and 5 and so on... I have about 350 frames so it would take ages if I had to do it manually... I'm sorry if my explanation is a bit hard to understand, but English isn't my first language.

Chuck Uebele
Community Expert
Community Expert
November 23, 2019

Did you shoot three shots for each frame, or are you wanting to combing the two frames before and after the selected frame?

Participating Frequently
November 23, 2019

Yes, I want to combine them with the one before and after the selected frame