Skip to main content
Inspiring
March 7, 2024
Answered

Updated Frequency Separation Action for PS 2024?

  • March 7, 2024
  • 5 replies
  • 17897 views

The better existing FS Actions need to be updated. From what I know, the best FS actions offer the option of FS for 8Bit or 16bit -and they will not have the same structure.

FS can work better with Median Filter applied instead of Gauss Blur. And there shuld be a built in PAUSE to allow user to set the level of Median applied. Fully automatic FS actions won't work on every image.

There are plenty of free FS actions that really are either too basic or not full featured.

THe better FS actions also create preview toggle layers that allow quick before/after comparison.

I'm an experienced retoucher, but not the uptimate expert on FS Actions, so there may well be features that I'm not aware of. 

I'd be OK payong for a quality FS action, but not a big proprietary plugin.

Of course Free is always best if anyone has a link to a quality FS action with the above features.

Any other FS wisdom to share with experiened retouchers?

Correct answer davescm

There is no need to buy anything. The steps for frequency separation are simple and you can record an action for each of 8 bit and 16 bit and a version to use either median and gaussian blur.

https://helpx.adobe.com/uk/photoshop/using/creating-actions.html

 

The steps in manual frequency separation are:

1. Make 2 duplicates of your image layer (Ctrl+J twice)
Name the lower - "Low frequency"
Name the Higher - "High Frequency"

2. Select the Low frequency layer and use Filter Gaussian Blur (around 6.0) or use Median if you prefer

3. Select the High frequency layer
Go to menu Image > Apply Image
Set the source layer to Low Frequency
Set the blending mode to Subtract
Set Scale to 2 *
Set offset to 128 *
Click OK
4. Change the blending mode of the high frequency layer to Linear Light






* Note - the above steps are for 8 bit/channel images. For 16 bit/channel step 3 changes slightly

3. Select the High frequency layer
Go to menu Image > Apply Image
Set the source layer to Low Frequency
Check "Invert" next to channel

Set the blending mode to Add
Set Scale to 2
Set Offset to 0
Click OK

Now carry on with step 4 above

 

That is it - just take a few minutes to record those steps into an action, or set of actions, and you are ready to click and  go.

 

Dave

 

5 replies

Stephen Marsh
Community Expert
Community Expert
March 10, 2024

The following script may also be of interest:

 

// MultiDecomp
// ver. 0.5
// Decomposes an image into as many layer slices as the user would like, based on the techniques in the 'HighPass Sucks' thread.
// by *THAT* HP Guy.

// *** USE AT YOUR OWN RISK ***

// Version Changes:
// 0.2 --
//    Introduced sanity checks
//    Check bit depth and use modes as appropriate
//    Verify # of layers at outset and copy / copy merged as appropriate
// 0.3 --
//    Improved layout
// 0.4 --
//	Included Clipped Curves adjustment layers option
// 0.5 --
//	Fixed Curves bug
//	Round display values for layer names

// To Do:
// 1.0 --
//    Improve accuracy / investigate multilayer recomposition from source in 8bit
//    Ideas?



var startRulerUnits = app.preferences.rulerUnits;
var startTypeUnits = app.preferences.typeUnits;
var startDisplayDialogs = app.displayDialogs;
app.preferences.rulerUnits = Units.PIXELS;
app.preferences.typeUnits = TypeUnits.PIXELS;
app.displayDialogs = DialogModes.NO;

var sep = new Window("dialog { \
			alignChildren:'fill', \
			text:'Frequency Separator', \
			vals: Panel { text: 'Values', orientation: 'column', alignChildren:'right', \
				sm: Group { orientation: 'row',\
					smLabel:StaticText { text:'Starting radius:'},\
					smallest:EditText {text:'1', characters: 6}\
				},\
				lg: Group { orientation: 'row',\
					lgLabel:StaticText { text:'Ending radius:'},\
					largest:EditText{text:'100', characters: 6,}\
				},\
				stps: Group { orientation: 'row',\
					stepsLabel:StaticText { text:'Steps between:'},\
					steps:EditText{text:'4', characters: 6}\
				}\
			}, \
			curves: Checkbox { alignment:'right', text:'Clipped Curves Adjustments?', value:false},\
			buttons: Group {orientation: 'row', \
				okButton:Button{text:'OK' },\
				cancelButton:Button{text:'Cancel' }\
			} \
	}");

sep.buttons.okButton.onClick = function(){
	goAhead = true;
	sep.close();
};

sep.buttons.cancelButton.onClick = function(){
	sep.close();
};

sep.vals.lg.largest.onChange = function(){
	if ((Number(sep.vals.lg.largest.text) < 0.1) || (Number(sep.vals.lg.largest.text) > 250)) {
		sep.vals.lg.largest.text = "1.0";
		alert ("Radii must fall between 0.1 and 250.0 pixels.");
	}
}

sep.vals.sm.smallest.onChange = function(){
	if ((Number(sep.vals.sm.smallest.text) < 0.1) || (Number(sep.vals.sm.smallest.text) > 250)) {
		sep.vals.sm.smallest.text = "1.0";
		alert ("Radii must fall between 0.1 and 250.0 pixels.");
	}
}

addCurves = function() {
	var id29 = charIDToTypeID( "Mk  " );
	    var desc6 = new ActionDescriptor();
	    var id30 = charIDToTypeID( "null" );
	        var ref2 = new ActionReference();
	        var id31 = charIDToTypeID( "AdjL" );
	        ref2.putClass( id31 );
	    desc6.putReference( id30, ref2 );
	    var id32 = charIDToTypeID( "Usng" );
	        var desc7 = new ActionDescriptor();
	        var id33 = charIDToTypeID( "Grup" );
	        desc7.putBoolean( id33, true );
	        var id34 = charIDToTypeID( "Type" );
	            var desc8 = new ActionDescriptor();
	            var id35 = stringIDToTypeID( "presetKind" );
	            var id36 = stringIDToTypeID( "presetKindType" );
	            var id37 = stringIDToTypeID( "presetKindDefault" );
	            desc8.putEnumerated( id35, id36, id37 );
      	  var id38 = charIDToTypeID( "Crvs" );
	        desc7.putObject( id34, id38, desc8 );
	    var id39 = charIDToTypeID( "AdjL" );
	    desc6.putObject( id32, id39, desc7 );
	executeAction( id29, desc6, DialogModes.NO );
}

apply16 = function() {
	var id39 = charIDToTypeID( "AppI" );
    	var desc11 = new ActionDescriptor();
	    var id40 = charIDToTypeID( "With" );
      	  var desc12 = new ActionDescriptor();
      	  var id41 = charIDToTypeID( "T   " );
      	      var ref6 = new ActionReference();
      	      var id42 = charIDToTypeID( "Chnl" );
      	      var id43 = charIDToTypeID( "Chnl" );
      	      var id44 = charIDToTypeID( "RGB " );
      	      ref6.putEnumerated( id42, id43, id44 );
      	      var id45 = charIDToTypeID( "Lyr " );
        	      ref6.putName( id45, LFRef.name );
	        desc12.putReference( id41, ref6 );
	        var id46 = charIDToTypeID( "Invr" );
	        desc12.putBoolean( id46, true );
	        var id47 = charIDToTypeID( "Clcl" );
	        var id48 = charIDToTypeID( "Clcn" );
	        var id49 = charIDToTypeID( "Add " );
	        desc12.putEnumerated( id47, id48, id49 );
	        var id50 = charIDToTypeID( "Scl " );
	        desc12.putDouble( id50, 2.000000 );
	        var id51 = charIDToTypeID( "Ofst" );
	        desc12.putInteger( id51, 0 );
	    var id52 = charIDToTypeID( "Clcl" );
	    desc11.putObject( id40, id52, desc12 );
	executeAction( id39, desc11, DialogModes.NO );
}

round = function( num, decs ) {
	return Math.round(num*Math.pow(10,decs))/10;
}

apply8 = function() {
	var id94 = charIDToTypeID( "AppI" );
	    var desc20 = new ActionDescriptor();
	    var id95 = charIDToTypeID( "With" );
	        var desc21 = new ActionDescriptor();
	        var id96 = charIDToTypeID( "T   " );
	            var ref10 = new ActionReference();
	            var id97 = charIDToTypeID( "Chnl" );
	            var id98 = charIDToTypeID( "Chnl" );
	            var id99 = charIDToTypeID( "RGB " );
	            ref10.putEnumerated( id97, id98, id99 );
	            var id100 = charIDToTypeID( "Lyr " );
	            ref10.putName( id100, LFRef.name );
	        desc21.putReference( id96, ref10 );
	        var id101 = charIDToTypeID( "Clcl" );
	        var id102 = charIDToTypeID( "Clcn" );
	        var id103 = charIDToTypeID( "Sbtr" );
	        desc21.putEnumerated( id101, id102, id103 );
	        var id104 = charIDToTypeID( "Scl " );
	        desc21.putDouble( id104, 2.000000 );
	        var id105 = charIDToTypeID( "Ofst" );
	        desc21.putInteger( id105, 128 );
	    var id106 = charIDToTypeID( "Clcl" );
	    desc20.putObject( id95, id106, desc21 );
	executeAction( id94, desc20, DialogModes.NO );
}

goAhead=false;
sep.center();
sep.show();

if (goAhead) {
	var docRef = app.activeDocument;
	docRef.selection.selectAll();
	if (docRef.artLayers.length > 1)
		docRef.selection.copy(true);
	else
		docRef.selection.copy();

	var LFRef = docRef.paste();
	var nextRef = null;
	var smallest = Number(sep.vals.sm.smallest.text);
	var largest = Number(sep.vals.lg.largest.text);
	var steps = Number(sep.vals.stps.steps.text);
	var blurBy = smallest;
	var increment = (largest - blurBy) / steps;
	var i =0;

	while (i <= steps) {
		HFRef = LFRef.duplicate (LFRef, ElementPlacement.PLACEBEFORE);
		HFRef.blendMode = BlendMode.LINEARLIGHT;
		if (i > 0)
			HFRef.name = round(Number(blurBy - increment),1) + " - " + round(blurBy,1);
		else
			HFRef.name = " < " + round(smallest,1);
		LFRef.applyGaussianBlur(blurBy);
		docRef.activeLayer = HFRef;

		if (docRef.bitsPerChannel == BitsPerChannelType.EIGHT)
			apply8();
		else
			if (docRef.bitsPerChannel == BitsPerChannelType.SIXTEEN)
				apply16();

		if (sep.curves.value == true) {
			addCurves();
		}

		blurBy += increment;
		i=i+1;
	};
	LFRef.name = "> " + round(largest,1);

	docRef = null;
	HFRef = null;
	LFRef = null;
	nextRef = null;
};

app.preferences.rulerUnits = startRulerUnits;
app.preferences.typeUnits = startTypeUnits;
app.displayDialogs = startDisplayDialogs;

 

https://prepression.blogspot.com/2017/11/downloading-and-installing-adobe-scripts.html

Inspiring
March 11, 2024

Stefano, can you get the action of these steps, I would like to see if I can create a small UXP panel.

thanks as always

 

davescm
Community Expert
davescmCommunity ExpertCorrect answer
Community Expert
March 9, 2024

There is no need to buy anything. The steps for frequency separation are simple and you can record an action for each of 8 bit and 16 bit and a version to use either median and gaussian blur.

https://helpx.adobe.com/uk/photoshop/using/creating-actions.html

 

The steps in manual frequency separation are:

1. Make 2 duplicates of your image layer (Ctrl+J twice)
Name the lower - "Low frequency"
Name the Higher - "High Frequency"

2. Select the Low frequency layer and use Filter Gaussian Blur (around 6.0) or use Median if you prefer

3. Select the High frequency layer
Go to menu Image > Apply Image
Set the source layer to Low Frequency
Set the blending mode to Subtract
Set Scale to 2 *
Set offset to 128 *
Click OK
4. Change the blending mode of the high frequency layer to Linear Light






* Note - the above steps are for 8 bit/channel images. For 16 bit/channel step 3 changes slightly

3. Select the High frequency layer
Go to menu Image > Apply Image
Set the source layer to Low Frequency
Check "Invert" next to channel

Set the blending mode to Add
Set Scale to 2
Set Offset to 0
Click OK

Now carry on with step 4 above

 

That is it - just take a few minutes to record those steps into an action, or set of actions, and you are ready to click and  go.

 

Dave

 

Legend
March 11, 2024

Subtract actually works fine for 16-bit images. I've been using it that way for probably a decade.

Ivan Zajats
Inspiring
March 9, 2024

@FauxtoGuy, if you claim to be a pro, you should be able to write your own basic actions.

Search some articles and tutorials, there's a lot of information around.

FauxtoGuyAuthor
Inspiring
March 10, 2024

If I had ALL the answers, I wouldn't have posted the question here.

Stephen Marsh
Community Expert
Community Expert
March 8, 2024

@FauxtoGuy 

 

I have just made a Median-based version of the standard Gaussian Blur version of my Frequency Splitter action for you, see if it works and let me know.

 

Play the "Conditional Run" action in the set which will conditionally play the 8bpc or 16bpc action depending on the current file bit depth.

 

Inspiring
March 8, 2024