Skip to main content
Participant
October 22, 2011
Question

Recording location of selected object

  • October 22, 2011
  • 1 reply
  • 1185 views

I would like to record the center (x,y) coordinates of a selected area.  Here is the context:

I am using Photoshop CS5 for photoanalysis.  Here is the process:

1) Open photograph for analysis

2) Set measurement scale

3) Select a ROI (Region Of Interest) -- usually this is continguous but occasionally disjoint

4) Layer via Copy

5) Change layer name to something informative that we need for our later analysis (species identification, condition, etc)

6) Repeat 3-5 until all ROIs are completed for that image

7) Run script (see below)

The result is a document with many layers and each layer has an ROI. 

I wrote a script that does the following:

Traverse layers. For each layer,

     Select non-transparent pixels (i.e., select ROI)

     Record Measurements (area, perimeter, height, width) in Measurement Log

     Write out the layer name (remember, this is informative) to a file

Export Measurement File (distinct from layer name file)

QUESTION:

     For each ROI, I need to record the position of the selected area.  I.e., I would like to know the center (x,y) location of the ROI, which could be calculated adequately from xmin, xmax, ymin, and ymax for the selected area on each photograph or from a list of all of the pixel locations included in the selection.  Since I am already writing out a separate file from my script, I can include this information there.  But I don't know how to call up the position of the selected region or the list of pixels highlighted in a selection.

These location will only be compared for ROIs within a single photograph.  Ideally, I would like to restrict this to the largest contiguous selected area within a region, but that seems more challenging.

     Sadly, there is no option to record the x,y position of the selection in the Measurement Log, which would be a super nice addition to the Measurement Tool.  (The other nice addition for the Measurement Log would be the ability to edit the name of each measurement.)

Thanks in advance!

I've pasted the actual script below.

-Megan

*************************************************************************************

//define what measure log items I want to export

var dpoints = ["Label","Area","Perimeter","Height","Width","Scale","ScaleFactor","Document"];

    //might be possible to also get other info like the middle location [(xmax-xmin)/2,(ymax-ymin)/2)]

    //not part of measure log and would need to normalize to the size of photo

//since log is not adjustable, create a string for export that will hold the layer names in the same order

//these layer names will be connected to the output later

var str ="";

// and a header line

str = 'LayerName\n';

// function from Xbytor to traverse all layers and do ftn in each layer

traverseLayers = function(doc, ftn, reverse) {

  function _traverse(doc, layers, ftn, reverse) {

    var ok = true;

    for (var i = 1; i <= layers.length && ok != false; i++) {

       //count up from layer 0 to layer layers.length-1 for regular -or- count from layers.length-1 to 0 for reverse

      var index = (reverse == true) ? layers.length-i : i - 1;

      var layer = layers[index];

      app.activeDocument.activeLayer = app.activeDocument.layers[index];

     if (layer.typename == "LayerSet") {   //if this is a layerset then traverse layers within the layerset

        ok = _traverse(doc, layer.layers, ftn, reverse);

       } else {

        ok = ftn(doc, layer);

    }

    }

    return ok;

  };

  return _traverse(doc, doc.layers, ftn, reverse);

};

//function that selects non-tranparent pixels from Mike Hale

layerPixels2Selection = function(){

if(app.activeDocument.activeLayer.isBackgroundLayer){

   return;

   }

var desc = new ActionDescriptor();

var ref = new ActionReference();

ref.putProperty( charIDToTypeID( "Chnl" ), charIDToTypeID( "fsel" ) );

desc.putReference( charIDToTypeID( "null" ), ref );

var ref1 = new ActionReference();

ref1.putEnumerated( charIDToTypeID( "Chnl" ), charIDToTypeID( "Chnl" ), charIDToTypeID( "Trsp" ) );

desc.putReference( charIDToTypeID( "T   " ), ref1 );

executeAction( charIDToTypeID( "setd" ), desc, DialogModes.NO );

}

//in each layer, record layer name, call layerPixels2Selection and record measurements on selection

takeMeasurements=function (doc, layer){

    if(app.activeDocument.activeLayer.isBackgroundLayer==false){

        str += layer.name+'\n';          //record the layer name in a the string str

         //select all non-transparent pixels  

        layerPixels2Selection()         

        //record measurements to measurement log

        app.activeDocument.recordMeasurements(MeasurementSource.MEASURESELECTION,dpoints);

        app.activeDocument.selection.deselect();

   }

else {

return;

   }

}

//now, traverse thru layers, calling takeMeasurements each time

traverseLayers(app.activeDocument, takeMeasurements,0);

//Write out the Layer Name file and export the measurement log

//Would be great to be able to put these together, but I don't know Java well enough to do it here.

var LayerFile = new File(app.activeDocument.path+'/'+app.activeDocument.name.match(/([^\.]+)/)[1]+"Layers.csv" );

var LogFile = new File(app.activeDocument.path+'/'+app.activeDocument.name.match(/([^\.]+)/)[1]+"Log.csv" );

// open the file, write the data, then close the file

LayerFile.open('w');

LayerFile.writeln(str);

LayerFile.close();

app.measurementLog.exportMeasurements(LogFile,MeasurementRange.ALLMEASUREMENTS);

app.measurementLog.deleteMeasurements(MeasurementRange.ALLMEASUREMENTS);

This topic has been closed for replies.

1 reply

c.pfaffenbichler
Community Expert
Community Expert
October 23, 2011

    Select non-transparent pixels (i.e., select ROI)

Have you tried using the Layers’ bounds-property instead and writing those out instead of using the measurementLog?

mjd73Author
Participant
October 23, 2011

I haven't tried this.  These layers were generated in the program, rather than by script, so I think they are a LayerSet object, rather than ArtLayer objects, yes?  If so, can I still use layer.bounds to get the bounds?  From the documentation, it sounds like this should give me the coordinates of the bounding rectangle.  Is this correct?

Thanks for the suggestion.  I'm new to this, so I am not familiar with all the capabilities.

M

Inspiring
October 23, 2011

From looking at the script you posted it is working with layers. They may be in layerSets but it is the layers in those sets that are being referenced.

Yes, the layer bounds property is the coordinates for the bounding rectangle. Using bounds may or may not be that helpful depending on the shape of your ROI layers.