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

sort bright photos from dark photos in bridge?

Explorer ,
Jul 10, 2017 Jul 10, 2017

Copy link to clipboard

Copied

This needs a creative mind.

I know we can sort pics via metadata in a bridge script, but is there any way to sort bright photos from dark photos? (regardless of aperture, flash, exposure time - based solely on illumination)  I'd like to run a different action on each.

And if not in bridge, can anyone think of a clever conditional in photoshop actions?

TOPICS
Scripting

Views

2.9K

Likes

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 ,
Jul 11, 2017 Jul 11, 2017

Copy link to clipboard

Copied

Is there a different, consistent metadata value to help distinguish between a light and dark file?

If not, then this would likely need the help of Photoshop in order to assess the histogram.

Re: export histogram mean value for RGB to csv file

How to get vaules in the histogram

Likes

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
Guide ,
Jul 12, 2017 Jul 12, 2017

Copy link to clipboard

Copied

I don't know if this will help. This script will create a csv file of mean histogram values for a folder of documents.

(Photoshop Script)

#target photoshop;

app.bringToFront();

main();

function main(){

var inputFolder= Folder.selectDialog ("Please select folder to process");

if(inputFolder == null) return;

var fileList = inputFolder.getFiles(/\.(jpg|dng|tif|psd|crw|cr2|psb|exr|nef|dcr|dc2|erf|raf|orf|tga|mrw|mos|srf|pic|pct|pxr|pdd|pef|png|x3f|rw2)$/i);

var outFile = File(Folder.desktop +"/"+decodeURI(inputFolder.name)+".csv");

outFile.open('w');

outFile.writeln("Filename,Mean Histogram");

for(var a in fileList){

open(fileList);

var area = activeDocument.histogram;

outFile.writeln(decodeURI(activeDocument.name)+ "," + mean(area).toFixed(0));

app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);

}

outFile.close();

alert("Process complete\nCSV created...\n" + decodeURI(outFile));

}

function mean(hist) {

   var acc = 0;

   var cnt = 0;

   for (var i = 0; i < hist.length; i++) {

     acc += i*hist;

     cnt += hist;

   }

   return acc/cnt;

};

Likes

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 ,
Jul 12, 2017 Jul 12, 2017

Copy link to clipboard

Copied

It does help SuperMerlin, I was looking into this using ImageJ as it can batch export out a spreadsheet file of the histogram mean value.

Is there any chance of the output having a column for the full file path+filename+extension?

Once we have an exported spreadsheet, then a Bride Script or ExifTool can be used to import a keyword, label, rating or other metadata entry in. Once there is metadata, it can be used to sort or filter… However I am still working on that bit, adding a conditional variable metadata entry based on the mean histogram value. Some sort of range would be required, such as:

Low Key = mean value between ???-???

Medium Key = mean value between ???-???

High Key = mean value between ???-???

At a start point, simply using the mean histogram value as a metadata value and then sorting on this value would be a start.

This is obviously not a one step workflow and there is still work to be done, but at least we have something brewing!

Likes

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
Guide ,
Jul 12, 2017 Jul 12, 2017

Copy link to clipboard

Copied

The script can be amended to add a label or metadata instead of outputing to a csv file.

It depends if the mean value will suffice?

Likes

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 ,
Jul 12, 2017 Jul 12, 2017

Copy link to clipboard

Copied

Cool, that would help SuperMerlin, thanks!

I don’t know what else can be done? How do we tell software to differentiate between say low key and high key?

A perfectly “level” average/midtone key would = 128 mean levels

A perfect high key image would = 255 mean levels

A perfect low key image would = 0 mean levels

Of course, we are not dealing with perfectly flat gray/white/black images – there is a range of tones.

So it is probably too hard to try to work out a range, such as low key = 0-50 mean levels etc.

At least having a keyword appended to the image that was numerical would allow the sorting of low to high or high to low etc.

Would it be possible to do the following?

1) Append the mean value as a keyword (so as not to replace existing keywords)

2) Perhaps add a space and text to the value, so instead of say “66”, it would read as “66 mean histogram value” or something?

I’ll post what I have knocked up using your original script and ExifTool shortly.

Likes

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 ,
Jul 12, 2017 Jul 12, 2017

Copy link to clipboard

Copied

OK, as a proof of concept, I used SuperMerlin’s original script to output the mean histogram level value to CSV file.

I then added the path to the image as a column. So the CSV import file had two columns with the following titles:

SourceFile,Subject

/path/to/file/hi.JPG,166 mean histogram value

/path/to/file/low.JPG,32 mean histogram value

/path/to/file/mid.jpg,128 mean histogram value

I then used the following ExifTool command to import and append the mean value as an entry in the Subject (keyword) metadata against each image:

exiftool -sep ',' -csv+='/path/to/csv/file/import-file.csv' 'path/to/image/folder'

Then in Bridge the keywords can be used to sort the images from say high key to low key based on the mean histogram value keyword:

mean-sort.png

Likes

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
Guide ,
Jul 12, 2017 Jul 12, 2017

Copy link to clipboard

Copied

Here is another version that labels the documents...

Big downfall at the moment. It does not do raw files.

#target photoshop;

app.bringToFront();

main();

function main(){

var inputFolder= Folder.selectDialog ("Please select folder to process");

if(inputFolder == null) return;

var fileList = inputFolder.getFiles(/\.(jpg|tif|psd|)$/i);

if (ExternalObject.AdobeXMPScript == undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");  

for(var a in fileList){

open(fileList);

var mean =  meanHist(activeDocument.histogram).toFixed(0);

switch( true ){

        case ( mean <= 110 😞 setLabel( fileList,"To Do"); break;

        case ( mean > 111 && mean <= 180 😞 setLabel( fileList,"Approved"); break;

        case ( mean >= 181 😞 setLabel( fileList,"Review"); break;

        default : break;

    }

app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);

}

};

function setLabel( file,label){

if ( !ExternalObject.AdobeXMPScript ) ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');

        var xmpf = new XMPFile( File(file).fsName, XMPConst.UNKNOWN, XMPConst.OPEN_FOR_UPDATE );

        var xmp = xmpf.getXMP();

       xmp.deleteProperty(XMPConst.NS_XMP, "Label");  

        xmp.setProperty(XMPConst.NS_XMP, "Label",label); 

      if (xmpf.canPutXMP( xmp )) {

         xmpf.putXMP( xmp );

      }

      xmpf.closeFile( XMPConst.CLOSE_UPDATE_SAFELY );

};

function meanHist(hist) {

   var acc = 0;

   var cnt = 0;

   for (var i = 0; i < hist.length; i++) {

     acc += i*hist;

     cnt += hist;

   }

   return acc/cnt;

};

Likes

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 ,
Jul 12, 2017 Jul 12, 2017

Copy link to clipboard

Copied

Nice one SuperMerlin!

I see that lines 14 , 15 and 16 control which mean histogram value range receives which label. The key will be adjusting the range of mean values to suit the range of images being processed and what the end user expects (I don’t that there are any empirical numerical standards that one can reference as to what mean RGB histogram values equate to say high key for example).

I presume that it is just a matter of swapping out the “setLabel” command for one that appends a keyword (although it is probably slightly harder than that)?

After sleeping on this, I realised that there are of course other ways instead of using the mean histogram value (whether RGB or Luminosity), however they would take more time. One method is using the Blur/Average filter and measuring the L value of Lab mode.  Another method is resampling down to a 2x2 or even a 1 pixel image and again, perhaps using the L value of Lab mode as the metric as to how dark or light the image is.

As for raw camera images, it is sadly the nature of the beast. Raw camera data uses a linear gamma and the raw histogram is “biased” (I’m sure that it would still be workable and not impossible to deal with) – not to mention that they are “latent images” and it depends on the processing/development settings as to what the final histogram values are. Even camera manufacturers convert the raw data into a “default” rendered state to show the histogram “preview” on the back of the camera, it is not an exact science. This is why the camera histo may show highlight clipping, while it is still possible to recover 1 stop of data from the raw file that would be clipped on the rendered JPEG.

EDIT: If you could access the embedded thumbnail in the raw image or the Bridge preview files, then you could get to the rendered histo, otherwise you would need to open the raw file, apply a default preset to render, then open into Photoshop, run your script code etc. I don’t believe that Adobe allows one to access the raw file’s histogram, but I could be wrong. I can envisage other workflows where CLI tools such as DCRAW, EXIFTOOL and others may be used to do similar, piping the output of one into the other etc.

Likes

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
Guide ,
Jul 13, 2017 Jul 13, 2017

Copy link to clipboard

Copied

Yes the problem would be setting the values Stephen.

I have fixed the script so that it handles raw files as well...

#target photoshop;

app.bringToFront();

main();

function main(){

var inputFolder= Folder.selectDialog ("Please select folder to process");

if(inputFolder == null) return;

var fileList = inputFolder.getFiles(/\.(jpg|dng|tif|psd|crw|cr2|psb|exr|nef|dcr|dc2|erf|raf|orf|tga|mrw|mos|srf|pic|pct|pxr|pdd|pef|png|x3f|rw2)$/i);

if (ExternalObject.AdobeXMPScript == undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");  

for(var a in fileList){

open(fileList);

var EXT =fileList.name.toLowerCase().match(/[^\.]+$/).toString();

var mean =  meanHist(activeDocument.histogram).toFixed(0);

if(!isRawFile(EXT)){

switch( true ){

        case ( mean <= 110 😞 setLabel( fileList,"To Do"); break;

        case ( mean > 111 && mean <= 180 😞 setLabel( fileList,"Approved"); break;

        case ( mean >= 181 😞 setLabel( fileList,"Review"); break;

        default : break;

    }

}else{

    //raw file

    var file= File(decodeURI(fileList).replace(/\.[^\.]+$/, '.xmp'));

switch( true ){

        case ( mean <= 110 😞 setMetadata( file,"To Do"); break;

        case ( mean > 111 && mean <= 180 😞 setMetadata( file,"Approved"); break;

        case ( mean >= 181 😞 setMetadata( file,"Review"); break;

        default : break;

    }

    }

app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);

}

};

function setMetadata( file, label ){

try{

if (ExternalObject.AdobeXMPScript == undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");

  if(file.exists){

     file.open('r');

     file.encoding = "UTF8";

     file.lineFeed = "unix";

     file.open("r", "TEXT", "????");

     var xmpStr = file.read();

     file.close();

     }else{

         var xmpStr='';

         }

     var xmp = new XMPMeta( xmpStr );

        xmp.deleteProperty(XMPConst.NS_XMP, "Label");  

        xmp.setProperty(XMPConst.NS_XMP, "Label",label);

     file.open('w');

     file.encoding = "UTF8";

     file.lineFeed = "unix";

     file.write( xmp.serialize() );

     file.close();

     }catch(e){alert(e+"-"+e.line);}

}

function isRawFile(ext){

var rawFileTypes = Array( "tiff", "crw", "nef", "raf", "orf", "mrw", "dcr", "mos", "srf", "pef", "dcr", "cr2", "erf", "x3f", "raw" );

for(var a in rawFileTypes){

    if(ext.toString().toLowerCase() == rawFileTypes.toString()){

        return true;      

    }

    }

return false;

};

function setLabel( file,label){

if ( !ExternalObject.AdobeXMPScript ) ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');

        var xmpf = new XMPFile( File(file).fsName, XMPConst.UNKNOWN, XMPConst.OPEN_FOR_UPDATE );

        var xmp = xmpf.getXMP();

       xmp.deleteProperty(XMPConst.NS_XMP, "Label");  

        xmp.setProperty(XMPConst.NS_XMP, "Label",label); 

      if (xmpf.canPutXMP( xmp )) {

         xmpf.putXMP( xmp );

      }

      xmpf.closeFile( XMPConst.CLOSE_UPDATE_SAFELY );

};

function meanHist(hist) {

   var acc = 0;

   var cnt = 0;

   for (var i = 0; i < hist.length; i++) {

     acc += i*hist;

     cnt += hist;

   }

   return acc/cnt;

};

Likes

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
Guide ,
Jul 15, 2017 Jul 15, 2017

Copy link to clipboard

Copied

Yet another version, with the code tidied and  using Lab mode.

#target photoshop;

app.bringToFront();

main();

function main(){

var inputFolder= Folder.selectDialog ("Please select folder to process");

if(inputFolder == null) return;

var fileList = inputFolder.getFiles(/\.(jpg|dng|tif|psd|crw|cr2|psb|exr|nef|dcr|dc2|erf|raf|orf|tga|mrw|mos|srf|pic|pct|pxr|pdd|pef|png|x3f|rw2)$/i);

if (ExternalObject.AdobeXMPScript == undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");  

for(var a in fileList){

open(fileList);

var doc = activeDocument;

if (doc.mode != DocumentMode.LAB) doc.changeMode(ChangeMode.LAB);

var L = activeDocument.channels["Lightness"].histogram; 

var mean =  meanHist(L).toFixed(0);

var label = "";

switch( true ){

        case ( mean <= 110 😞 label="To Do"; break;

        case ( mean > 111 && mean <= 180 😞 label="Approved"; break;

        case ( mean >= 181 😞 label="Review"; break;

        default : break;

    }

if(fileType() != "Camera Raw"){

setLabel( fileList, label);

}else{

    //raw file

    var file= File(decodeURI(fileList).replace(/\.[^\.]+$/, '.xmp'));

    setMetadata( file,label);

    }

app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);

}

};

function setMetadata( file, label ){

try{

if (ExternalObject.AdobeXMPScript == undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");

  if(file.exists){

     file.open('r');

     file.encoding = "UTF8";

     file.lineFeed = "unix";

     file.open("r", "TEXT", "????");

     var xmpStr = file.read();

     file.close();

     }else{

         var xmpStr='';

         }

     var xmp = new XMPMeta( xmpStr );

        xmp.deleteProperty(XMPConst.NS_XMP, "Label");  

        xmp.setProperty(XMPConst.NS_XMP, "Label",label);

     file.open('w');

     file.encoding = "UTF8";

     file.lineFeed = "unix";

     file.write( xmp.serialize() );

     file.close();

     }catch(e){alert(e+"-"+e.line);}

}

function setLabel( file,label){

if ( !ExternalObject.AdobeXMPScript ) ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');

        var xmpf = new XMPFile( File(file).fsName, XMPConst.UNKNOWN, XMPConst.OPEN_FOR_UPDATE );

        var xmp = xmpf.getXMP();

       xmp.deleteProperty(XMPConst.NS_XMP, "Label");  

        xmp.setProperty(XMPConst.NS_XMP, "Label",label); 

      if (xmpf.canPutXMP( xmp )) {

         xmpf.putXMP( xmp );

      }

      xmpf.closeFile( XMPConst.CLOSE_UPDATE_SAFELY );

};

function meanHist(hist) {

   var acc = 0;

   var cnt = 0;

   for (var i = 0; i < hist.length; i++) {

     acc += i*hist;

     cnt += hist;

   }

   return acc/cnt;

};

function fileType(){

var ref = new ActionReference();

ref.putProperty( charIDToTypeID("Prpr"), stringIDToTypeID("format"));

ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );

return executeActionGet(ref).getString(stringIDToTypeID("format"));

};

Likes

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
Explorer ,
Jul 15, 2017 Jul 15, 2017

Copy link to clipboard

Copied

This is all fantastic. I am overwhelmed by the talent on this forum! I finally have a day off work tomorrow and will give it a trial run.

Likes

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
New Here ,
Dec 23, 2019 Dec 23, 2019

Copy link to clipboard

Copied

Not working in Photoshop CC2018 and CC2019 😞
I've got the error:

Error 1242: Illegal argument - argument 1
- File/Folder expected
Une: 19
-> open(fileList);

Likes

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
New Here ,
May 07, 2018 May 07, 2018

Copy link to clipboard

Copied

Awesome script, thanksSuperMerlin I'm only working with jpgs and in lightroom, so I would like to avoid xmp. How can I write this directly to the exif instead of creating an xmp?

Also, can anyone thing of how I could sort images in lightroom this way? Without renaming the filename.

Likes

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
Guide ,
May 08, 2018 May 08, 2018

Copy link to clipboard

Copied

This version writes the mean value to keywords I.E. "Mean value = 114.34"

Sorry I know nothing about Lightroom, so can't help there.

#target photoshop; 

app.bringToFront(); 

 

main(); 

function main(){ 

var inputFolder= Folder.selectDialog ("Please select folder to process"); 

if(inputFolder == null) return; 

var fileList = inputFolder.getFiles(/\.(jpg|dng|tif|psd|psb|exr|png)$/i); 

if (ExternalObject.AdobeXMPScript == undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");    

for(var a in fileList){ 

open(fileList); 

var doc = activeDocument; 

if (doc.mode != DocumentMode.LAB) doc.changeMode(ChangeMode.LAB);  

var L = activeDocument.channels["Lightness"].histogram;   

var mean =  meanHist(L).toFixed(2); 

if(fileType() != "Camera Raw"){ 

setMetadata( fileList, mean); 

}else{ continue;}

app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);

}

}; 

function setMetadata( file,mean){ 

var data = "Mean value = " + mean;

if ( !ExternalObject.AdobeXMPScript ) ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript'); 

        var xmpf = new XMPFile( File(file).fsName, XMPConst.UNKNOWN, XMPConst.OPEN_FOR_UPDATE ); 

        var xmp = xmpf.getXMP();    

        xmp.appendArrayItem(XMPConst.NS_DC, "subject", data, 0,XMPConst.PROP_IS_ARRAY);  

      if (xmpf.canPutXMP( xmp )) { 

         xmpf.putXMP( xmp ); 

      } 

      xmpf.closeFile( XMPConst.CLOSE_UPDATE_SAFELY ); 

}; 

function meanHist(hist) {  

   var acc = 0;  

   var cnt = 0;  

   for (var i = 0; i < hist.length; i++) {  

     acc += i*hist;  

     cnt += hist;  

   }  

   return acc/cnt;  

}; 

function fileType(){ 

var ref = new ActionReference(); 

ref.putProperty( charIDToTypeID("Prpr"), stringIDToTypeID("format")); 

ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );  

return executeActionGet(ref).getString(stringIDToTypeID("format")); 

};

Likes

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
Explorer ,
Sep 16, 2020 Sep 16, 2020

Copy link to clipboard

Copied

Doesn't work for me too on PS 21.2. Seems everything related to activeDocument.histogram goes down a black hole on newer versions of PS. Any thoughts on that? Is that a known bug or a change in the API?

Likes

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 08, 2018 May 08, 2018

Copy link to clipboard

Copied

Awesome script, thanksSuperMerlin. I'm only working with jpgs and in lightroom, so I would like to avoid xmp. How can I write this directly to the exif instead of creating an xmp?

Also, can anyone thing of how I could sort images in lightroom this way? Without renaming the filename.

Jarrod, do you mean that if you are working on an image titled “myphoto_1234.jpg” that in the same location, a separate file will also be generated with the title “myphoto_1234.xmp”? An XMP “sidecar” file should only be created for raw files if your Bridge/ACR settings are configured for “XMP Sidecar” and not for “Camera Raw Database”. Metadata (such as labels, keywords etc) should be written to all rendered files, except raw which is where the sidecar may come into play if not using the CRDB.

Likes

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
New Here ,
Dec 29, 2019 Dec 29, 2019

Copy link to clipboard

Copied

I've tested/tried everyone script above and noone work. I've tried it on CC2018, CC2019 and older version of Photoshop - CS2.

I've got error:

Error 1242: Illegal argument - argument 1
- File/Folder expected
Une: 19
-> open(fileList);

So I changed open(fileList) to open(fileList[a]) and script startr running but nothing happen, only open and close files from selected folder.

Is anything I'm doing wrong? I run script directly from Photoshop -> Files -> Scripts. I have more then 5 milion photos day and night and I want separate day from nighy shots. Do this task manual is neverending story, so maybe someone could help me to run this script and help automate Label .jpg photos.

Likes

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 ,
Sep 16, 2020 Sep 16, 2020

Copy link to clipboard

Copied

LATEST

Have you thought of using the time captured in metadata? 9PM is night, 3PM is day. etc.

Likes

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