• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Slimming layers with Difference

Contributor ,
May 25, 2021 May 25, 2021

Copy link to clipboard

Copied

Current workflow( When retouching is required on a background copy (patch etc) (obviously increasing file size))

  • compare retouched layer with background via difference (with background layer below)
  • load as as selection and invert selection
  • clear selected areas (unchanged areas removed)
doc = app.activeDocument

CalcDiff()
ChanNme ("Difference")
var diffChan = doc.channels.getByName ("Difference")
loadChannelSelection ()
doc.selection.invert()
selectRGB ()
doc.selection.clear()
executeAction(s2t("delete"), undefined, DialogModes.NO)
doc.selection.deselect()
diffChan.remove()





function c2t(s) {return charIDToTypeID(s)}
function s2t(s){return stringIDToTypeID(s)}

function selectRGB(){
    var d1 = new ActionDescriptor();
    var r1 = new ActionReference();
    r1.putEnumerated(s2t("channel"),s2t("channel"),s2t("RGB"))
    d1.putReference(s2t("null"), r1)
   executeAction(s2t("select"), d1, DialogModes.NO)
   }


function CalcDiff(){
var d1 = new ActionDescriptor();
    d1.putClass( s2t( "new" ), s2t( "channel" ) );
        var d2 = new ActionDescriptor();
            var r1 = new ActionReference();
             r1.putEnumerated( s2t( "channel" ), s2t( "channel" ), s2t( "gray" ));
   r1.putEnumerated( s2t( "layer" ), s2t( "ordinal" ), s2t( "targetEnum" ));   
//            r1.putName(s2t( "layer" ), "Layer 1" );
        d2.putReference( s2t( "to" ), r1 );
        d2.putEnumerated( s2t( "calculation" ), s2t( "calculationType" ),s2t( "difference" ) );
            var r2 = new ActionReference();
            r2.putEnumerated( s2t( "channel" ), s2t( "channel" ), s2t( "gray" ));
            r2.putProperty(s2t( "layer" ), s2t( "background" ));
        d2.putReference( s2t( "source2" ), r2 );
    var idcalculation = s2t( "calculation" );
    d1.putObject( s2t( "using" ), s2t( "calculation" ), d2 );
executeAction( s2t( "make" ), d1, DialogModes.NO );
}



function ChanNme(name) {

var r1 = new ActionReference();
var d1 = new ActionDescriptor();
var d2 = new ActionDescriptor();
r1.putEnumerated(s2t("channel"),s2t("ordinal"),s2t("targetEnum"));
d1.putReference( s2t("target"), r1 );
d2.putString(s2t("name"), name);
d1.putObject(s2t("to"), s2t("channel"), d2 );
executeAction(s2t("set"), d1, DialogModes.NO );

}


function loadChannelSelection(){
    var d1 = new ActionDescriptor()
        var r1 = new ActionReference()
        r1.putProperty(c2t( "Chnl" ), c2t( "fsel" ) )
    d1.putReference( c2t( "null" ), r1 )
        var r2 = new ActionReference()
        r2.putEnumerated(  c2t( "Chnl" ),c2t( "Ordn" ),c2t( "Trgt" ) )
    d1.putReference( c2t( "T   " ), r2 )
executeAction( c2t( "setd" ), d1, DialogModes.NO )

}

 

My questions are:

  1. is this an accurate way of removing unchanged parts of a layer? 
  2. is difference the best comparision blend mode math to use?

 

Im almost certain than small changes do not load in selection.. any thoughts or improvements to the accuracy would be greatly appreciated. 

 

 

TOPICS
Actions and scripting

Views

1.5K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , May 25, 2021 May 25, 2021

I used to do this many years ago with an action.

 

I would suggest that you add an equalize step to amplify the differences, then a threshold step to unify. Possibly expand these areas and blur slightly so that there is a minimum edge of unchanged pixels when the mask is applied. 

Hope this helps!

 

Votes

Translate

Translate
Adobe
Community Expert ,
May 25, 2021 May 25, 2021

Copy link to clipboard

Copied

I used to do this many years ago with an action.

 

I would suggest that you add an equalize step to amplify the differences, then a threshold step to unify. Possibly expand these areas and blur slightly so that there is a minimum edge of unchanged pixels when the mask is applied. 

Hope this helps!

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
May 25, 2021 May 25, 2021

Copy link to clipboard

Copied

come up with this, 

 

ive used diffuse instead of gaussian blur, its seems the equalize step obliterates any anti aliasing, thought diffuse might be a bit more subtle. 

 

doc = app.activeDocument

CalcDiff()
ChanNme ("Difference")
var diffChan = doc.channels.getByName ("Difference")
executeAction( s2t("equalize"), undefined, DialogModes.NO );
debugger
diffuse()

loadChannelSelection ()
doc.selection.invert()
selectRGB ()
doc.selection.clear()
executeAction(s2t("delete"), undefined, DialogModes.NO)
doc.selection.deselect()
diffChan.remove()





function c2t(s) {return charIDToTypeID(s)}
function s2t(s){return stringIDToTypeID(s)}

function selectRGB(){
    var d1 = new ActionDescriptor();
    var r1 = new ActionReference();
    r1.putEnumerated(s2t("channel"),s2t("channel"),s2t("RGB"))
    d1.putReference(s2t("null"), r1)
   executeAction(s2t("select"), d1, DialogModes.NO)
   }

function Gblur(){    var d1 = new ActionDescriptor();
    d1.putUnitDouble( s2t("radius"),s2t("pixelsUnit"), 1.000000 );
executeAction( s2t("gaussianBlur"), d1, DialogModes.NO );}

function diffuse(){    var d1 = new ActionDescriptor()
    d1.putEnumerated( c2t( "Md  " ), c2t( "DfsM" ), s2t( "anisotropic" ))
  d1.putInteger(  c2t( "FlRs" ), 3603398 )
executeAction( c2t( "Dfs " ), d1, DialogModes.NO )}



function CalcDiff(){
var d1 = new ActionDescriptor();
    d1.putClass( s2t( "new" ), s2t( "channel" ) );
        var d2 = new ActionDescriptor();
            var r1 = new ActionReference();
             r1.putEnumerated( s2t( "channel" ), s2t( "channel" ), s2t( "gray" ));
   r1.putEnumerated( s2t( "layer" ), s2t( "ordinal" ), s2t( "targetEnum" ));   
//            r1.putName(s2t( "layer" ), "Layer 1" );
        d2.putReference( s2t( "to" ), r1 );
        d2.putEnumerated( s2t( "calculation" ), s2t( "calculationType" ),s2t( "difference" ) );
            var r2 = new ActionReference();
            r2.putEnumerated( s2t( "channel" ), s2t( "channel" ), s2t( "gray" ));
            r2.putProperty(s2t( "layer" ), s2t( "background" ));
        d2.putReference( s2t( "source2" ), r2 );
    var idcalculation = s2t( "calculation" );
    d1.putObject( s2t( "using" ), s2t( "calculation" ), d2 );
executeAction( s2t( "make" ), d1, DialogModes.NO );
}



function ChanNme(name) {

var r1 = new ActionReference();
var d1 = new ActionDescriptor();
var d2 = new ActionDescriptor();
r1.putEnumerated(s2t("channel"),s2t("ordinal"),s2t("targetEnum"));
d1.putReference( s2t("target"), r1 );
d2.putString(s2t("name"), name);
d1.putObject(s2t("to"), s2t("channel"), d2 );
executeAction(s2t("set"), d1, DialogModes.NO );

}


function loadChannelSelection(){
    var d1 = new ActionDescriptor()
        var r1 = new ActionReference()
        r1.putProperty(c2t( "Chnl" ), c2t( "fsel" ) )
    d1.putReference( c2t( "null" ), r1 )
        var r2 = new ActionReference()
        r2.putEnumerated(  c2t( "Chnl" ),c2t( "Ordn" ),c2t( "Trgt" ) )
    d1.putReference( c2t( "T   " ), r2 )
executeAction( c2t( "setd" ), d1, DialogModes.NO )

}

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 25, 2021 May 25, 2021

Copy link to clipboard

Copied

I found my old action... 2003, yikes! If I remember correctly, this was made after the healing tools were introduced in v7, back when it was not possible to heal to a transparent layer, as was possible with the clone stamp tool. I don't miss the days of dust-busting scans!

 

heal.png

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
May 26, 2021 May 26, 2021

Copy link to clipboard

Copied

Thank you that's useful. Out of interest, what did you set the threshold and levels to?

 

I mainly want to use it to slim down a merged layer from Frequency separtion. 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 26, 2021 May 26, 2021

Copy link to clipboard

Copied

 

Threshold was 128, levels was auto contrast.

 

Out of curiosity I ran the action through xtools:

 

#target photoshop
//
// HealingProv1_0APS5.jsx
//

//
// Generated Wed May 26 2021 18:48:30 GMT+1000
//

cTID = function(s) { return app.charIDToTypeID(s); };
sTID = function(s) { return app.stringIDToTypeID(s); };

//
//==================== Healing Pro v1.0 APS5 ==============
//
function HealingProv1_0APS5() {
  // Stop
  function step1(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    desc1.putString(cTID('Msge'), "Healing Pro v1.0 APS5\r\rStephen Marsh\r\rhttp://members.ozemail.com.au/~binaryfx");
    desc1.putBoolean(cTID('Cntn'), true);
    executeAction(cTID('Stop'), desc1, dialogMode);
  };

  // Stop
  function step2(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    desc1.putString(cTID('Msge'), "Run on a targeted,  healed layer -  do not apply to flat  background data. \r\rThis action presumes a two layer document, with the upper duplicate layer holding the cloned or healed data.\r\rContinue or Stop?");
    desc1.putBoolean(cTID('Cntn'), true);
    executeAction(cTID('Stop'), desc1, dialogMode);
  };

  // Duplicate
  function step3(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    var ref1 = new ActionReference();
    ref1.putEnumerated(cTID('Dcmn'), cTID('Ordn'), cTID('Frst'));
    desc1.putReference(cTID('null'), ref1);
    desc1.putString(cTID('Nm  '), "HealingPro Temp");
    executeAction(cTID('Dplc'), desc1, dialogMode);
  };

  // Set
  function step4(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    var ref1 = new ActionReference();
    ref1.putEnumerated(cTID('Lyr '), cTID('Ordn'), cTID('Trgt'));
    desc1.putReference(cTID('null'), ref1);
    var desc2 = new ActionDescriptor();
    desc2.putEnumerated(cTID('Md  '), cTID('BlnM'), cTID('Dfrn'));
    desc1.putObject(cTID('T   '), cTID('Lyr '), desc2);
    executeAction(cTID('setd'), desc1, dialogMode);
  };

  // Flatten Image
  function step5(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    executeAction(sTID('flattenImage'), undefined, dialogMode);
  };

  // Convert Mode
  function step6(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    desc1.putClass(cTID('T   '), cTID('Grys'));
    executeAction(sTID('convertMode'), desc1, dialogMode);
  };

  // Equalize
  function step7(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    executeAction(cTID('Eqlz'), undefined, dialogMode);
  };

  // Maximum
  function step8(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    desc1.putInteger(cTID('Rds '), 3);
    executeAction(cTID('Mxm '), desc1, dialogMode);
  };

  // Threshold
  function step9(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    desc1.putInteger(cTID('Lvl '), 128);
    executeAction(cTID('Thrs'), desc1, dialogMode);
  };

  // Gaussian Blur
  function step10(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    desc1.putDouble(cTID('Rds '), 2);
    executeAction(sTID('gaussianBlur'), desc1, dialogMode);
  };

  // Levels
  function step11(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    desc1.putBoolean(cTID('AuCo'), true);
    executeAction(cTID('Lvls'), desc1, dialogMode);
  };

  // Set
  function step12(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    var ref1 = new ActionReference();
    ref1.putProperty(cTID('Chnl'), sTID("selection"));
    desc1.putReference(cTID('null'), ref1);
    desc1.putEnumerated(cTID('T   '), cTID('Ordn'), cTID('Al  '));
    executeAction(cTID('setd'), desc1, dialogMode);
  };

  // Copy
  function step13(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    executeAction(cTID('copy'), undefined, dialogMode);
  };

  // Close
  function step14(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    desc1.putEnumerated(cTID('Svng'), cTID('YsN '), cTID('N   '));
    executeAction(cTID('Cls '), desc1, dialogMode);
  };

  // Make
  function step15(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    var desc2 = new ActionDescriptor();
    desc2.putString(cTID('Nm  '), "HealingPro Alpha");
    desc2.putEnumerated(cTID('ClrI'), cTID('MskI'), cTID('MskA'));
    var desc3 = new ActionDescriptor();
    desc3.putDouble(cTID('Rd  '), 255);
    desc3.putDouble(cTID('Grn '), 0);
    desc3.putDouble(cTID('Bl  '), 0);
    desc2.putObject(cTID('Clr '), sTID("RGBColor"), desc3);
    desc2.putInteger(cTID('Opct'), 50);
    desc1.putObject(cTID('Nw  '), cTID('Chnl'), desc2);
    executeAction(cTID('Mk  '), desc1, dialogMode);
  };

  // Set
  function step16(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    var ref1 = new ActionReference();
    ref1.putProperty(cTID('Chnl'), sTID("selection"));
    desc1.putReference(cTID('null'), ref1);
    desc1.putEnumerated(cTID('T   '), cTID('Ordn'), cTID('Al  '));
    executeAction(cTID('setd'), desc1, dialogMode);
  };

  // Paste
  function step17(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    executeAction(cTID('past'), undefined, dialogMode);
  };

  // Set
  function step18(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    var ref1 = new ActionReference();
    ref1.putProperty(cTID('Chnl'), sTID("selection"));
    desc1.putReference(cTID('null'), ref1);
    desc1.putEnumerated(cTID('T   '), cTID('Ordn'), cTID('None'));
    executeAction(cTID('setd'), desc1, dialogMode);
  };

  // Set
  function step19(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    var ref1 = new ActionReference();
    ref1.putProperty(cTID('Chnl'), sTID("selection"));
    desc1.putReference(cTID('null'), ref1);
    var ref2 = new ActionReference();
    ref2.putEnumerated(cTID('Chnl'), cTID('Ordn'), cTID('Trgt'));
    desc1.putReference(cTID('T   '), ref2);
    executeAction(cTID('setd'), desc1, dialogMode);
  };

  // Select
  function step20(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    var ref1 = new ActionReference();
    ref1.putEnumerated(cTID('Chnl'), cTID('Chnl'), sTID("CMYK"));
    desc1.putReference(cTID('null'), ref1);
    executeAction(cTID('slct'), desc1, dialogMode);
  };

  // Make
  function step21(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    desc1.putClass(cTID('Nw  '), cTID('Chnl'));
    var ref1 = new ActionReference();
    ref1.putEnumerated(cTID('Chnl'), cTID('Chnl'), cTID('Msk '));
    desc1.putReference(cTID('At  '), ref1);
    desc1.putEnumerated(cTID('Usng'), cTID('UsrM'), cTID('RvlS'));
    executeAction(cTID('Mk  '), desc1, dialogMode);
  };

  // Delete
  function step22(enabled, withDialog) {
    if (enabled != undefined && !enabled)
      return;
    var dialogMode = (withDialog ? DialogModes.ALL : DialogModes.NO);
    var desc1 = new ActionDescriptor();
    var ref1 = new ActionReference();
    ref1.putEnumerated(cTID('Chnl'), cTID('Ordn'), cTID('Trgt'));
    desc1.putReference(cTID('null'), ref1);
    desc1.putBoolean(cTID('Aply'), true);
    executeAction(cTID('Dlt '), desc1, dialogMode);
  };

  step1(false, true);      // Stop
  step2(true, true);      // Stop
  step3();      // Duplicate
  step4();      // Set
  step5();      // Flatten Image
  step6();      // Convert Mode
  step7();      // Equalize
  step8();      // Maximum
  step9();      // Threshold
  step10();      // Gaussian Blur
  step11();      // Levels
  step12();      // Set
  step13();      // Copy
  step14();      // Close
  step15();      // Make
  step16();      // Set
  step17();      // Paste
  step18();      // Set
  step19();      // Set
  step20();      // Select
  step21();      // Make
  step22();      // Delete
};

//=========================================
//                    HealingProv1_0APS5.main
//=========================================
//

HealingProv1_0APS5.main = function () {
  HealingProv1_0APS5();
};

HealingProv1_0APS5.main();

// EOF

"HealingProv1_0APS5.jsx"
// EOF

 

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
May 25, 2021 May 25, 2021

Copy link to clipboard

Copied

What are you supposed to do with the resulting layer?

 

Note: the result of the calculation can be not only the channel, but also the selection.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
May 25, 2021 May 25, 2021

Copy link to clipboard

Copied

The resulting layer is just any pixel retouching that has been done, so it stays in the stack. The channel gives more flexibility, in terms of amplifing it as Stephen_A_Marsh suggested

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
May 26, 2021 May 26, 2021

Copy link to clipboard

Copied

With your script, you will only spoil your work. Moreover, his work depends on the channel settings.

See video.

 

upd.

https://disk.yandex.ru/i/84AJAxrBKs2Lgw

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Contributor ,
May 26, 2021 May 26, 2021

Copy link to clipboard

Copied

LATEST

Thanks for demo, I guess merging down is safest

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
May 25, 2021 May 25, 2021

Copy link to clipboard

Copied

quoteclear selected areas (unchanged areas removed)

By @Gibson Editions

 

Your script deletes just the changed parts from me.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines