Skip to main content
Participant
December 5, 2011
Answered

Easy way to extract all pixel Lab values - please help!

  • December 5, 2011
  • 2 replies
  • 5546 views

Hi,

For an image of any size/dimensions, I'm trying to automatically extract every pixel's color information by coordinate, ideally the Lab values. So the output would look something like this:

x          y          L          a          b

0          0          100     0          0

0          1          99       0          0

etc. The output would ideally be in CSV format.

I've seen some pretty outstanding scripts which are similar to what I need (but not quite) and I'm also a complete scripting novice so not sure where to begin! Any help gratefully received!

Oh and I'm on PS3 Extended.

Cheers

Steve

This topic has been closed for replies.
Correct answer Paul Riggott

Ok, this script assumes

There is an open document that is 8bit Lab mode

The script will create a CSV file in the same location as the open document (if it had not been saved it will be saved to the desktop) with the same name as the open document.

File.prototype.readByte = function() {
  return this.read(1).charCodeAt(0);
};
function convertByteToSignedByte(num){
     var dec = (num | (num % 256))-128
     return dec;
};
function convertByteToLum( num){
     var dec = Math.round((num/256)*100);
     return dec;
};

function main(){
if(!documents.length) return;
if(activeDocument.mode != DocumentMode.LAB) {
    alert("Please convert this document to Lab mode\r Then re-run this script");
    return;
    }
var Name = decodeURI(app.activeDocument.name).replace(/\.[^\.]+$/, '');
try{
var Path = activeDocument.path;
}catch(e){var Path = '~/Desktop';}
var rawFile = new File(Path +"/"+Name +".raw");
saveAsRaw(rawFile);
var csvFile = new File(Path +"/"+Name +".csv");
var len = 0;
var W = activeDocument.width.as('px');
CountW=0;
CountH=0;
rawFile.encoding = 'BINARY';
rawFile.open('r');
csvFile.open('w');
csvFile.writeln('X,Y,L,a,b');
while(!rawFile.eof){
    csvFile.write(CountW+',');
    csvFile.write(CountH+',');
     csvFile.write(convertByteToLum(rawFile.readByte())+',');
     csvFile.write(convertByteToSignedByte(rawFile.readByte())+',');
     csvFile.writeln(convertByteToSignedByte(rawFile.readByte()));
     len++;
     if(len % W == 0){
         CountH++;
         CountW=0;
         }else{
     CountW++;
     }
}
rawFile.close();
csvFile.close();
rawFile.remove();
}
main();
function saveAsRaw(file) {
var desc1 = new ActionDescriptor();
var desc2 = new ActionDescriptor();
desc2.putString( charIDToTypeID('FlCr'), "8BIM" );
desc2.putBoolean( charIDToTypeID('ChnI'), true );
desc1.putObject( charIDToTypeID('As  '), charIDToTypeID('Rw  '), desc2 );
desc1.putPath( charIDToTypeID('In  '), new File( file ) );
desc1.putBoolean( charIDToTypeID('Cpy '), true );
executeAction( charIDToTypeID('save'), desc1, DialogModes.NO );
};

2 replies

Paul Riggott
Inspiring
December 5, 2011

This might be better saving the document as a Raw file then converting that to a CSV file.

Paul Riggott
Paul RiggottCorrect answer
Inspiring
December 5, 2011

Ok, this script assumes

There is an open document that is 8bit Lab mode

The script will create a CSV file in the same location as the open document (if it had not been saved it will be saved to the desktop) with the same name as the open document.

File.prototype.readByte = function() {
  return this.read(1).charCodeAt(0);
};
function convertByteToSignedByte(num){
     var dec = (num | (num % 256))-128
     return dec;
};
function convertByteToLum( num){
     var dec = Math.round((num/256)*100);
     return dec;
};

function main(){
if(!documents.length) return;
if(activeDocument.mode != DocumentMode.LAB) {
    alert("Please convert this document to Lab mode\r Then re-run this script");
    return;
    }
var Name = decodeURI(app.activeDocument.name).replace(/\.[^\.]+$/, '');
try{
var Path = activeDocument.path;
}catch(e){var Path = '~/Desktop';}
var rawFile = new File(Path +"/"+Name +".raw");
saveAsRaw(rawFile);
var csvFile = new File(Path +"/"+Name +".csv");
var len = 0;
var W = activeDocument.width.as('px');
CountW=0;
CountH=0;
rawFile.encoding = 'BINARY';
rawFile.open('r');
csvFile.open('w');
csvFile.writeln('X,Y,L,a,b');
while(!rawFile.eof){
    csvFile.write(CountW+',');
    csvFile.write(CountH+',');
     csvFile.write(convertByteToLum(rawFile.readByte())+',');
     csvFile.write(convertByteToSignedByte(rawFile.readByte())+',');
     csvFile.writeln(convertByteToSignedByte(rawFile.readByte()));
     len++;
     if(len % W == 0){
         CountH++;
         CountW=0;
         }else{
     CountW++;
     }
}
rawFile.close();
csvFile.close();
rawFile.remove();
}
main();
function saveAsRaw(file) {
var desc1 = new ActionDescriptor();
var desc2 = new ActionDescriptor();
desc2.putString( charIDToTypeID('FlCr'), "8BIM" );
desc2.putBoolean( charIDToTypeID('ChnI'), true );
desc1.putObject( charIDToTypeID('As  '), charIDToTypeID('Rw  '), desc2 );
desc1.putPath( charIDToTypeID('In  '), new File( file ) );
desc1.putBoolean( charIDToTypeID('Cpy '), true );
executeAction( charIDToTypeID('save'), desc1, DialogModes.NO );
};

Paul Riggott
Inspiring
December 30, 2011

Hi Paul,

Could you comment on what is wrong with how i amend the script? I am trying to make the script reads every 50 pixel and also the average of that point if possible.

I cant seem to integrate the script you provided into mine... Hope you can amend the following for me!

File.prototype.readByte = function() {

  return this.read(1).charCodeAt(0);

};

function convertByteToSignedByte(num){

     var dec = (num | (num % 256))-128

     return dec;

};

function convertByteToLum( num){

     var dec = Math.round((num/256)*100);

     return dec;

};

function main(){

if(!documents.length) return;

if(activeDocument.mode != DocumentMode.LAB) {

    alert("Please convert this document to Lab mode\r Then re-run this script");

    return;

    }

var Name = decodeURI(app.activeDocument.name).replace(/\.[^\.]+$/, '');

try{

var Path = activeDocument.path;

}catch(e){var Path = '~/Desktop';}

var rawFile = new File(Path +"/"+Name +".raw");

saveAsRaw(rawFile);

var csvFile = new File(Path +"/"+Name +".csv");

var W = activeDocument.width.as('px');

scan_pixel=50;

CountW=0;

CountH=0;

rawFile.encoding = 'BINARY';

rawFile.open('r');

csvFile.open('w');

csvFile.writeln('X,Y,L,a,b');

while(!rawFile.eof){

    csvFile.write(CountW+',');

    csvFile.write(CountH+',');

     csvFile.write(convertByteToLum(rawFile.readByte())+',');

     csvFile.write(convertByteToSignedByte(rawFile.readByte())+',');

     csvFile.writeln(convertByteToSignedByte(rawFile.readByte()));

     if(CountW >= 3776){

         CountH=CountH+scan_pixel;

         CountW=0;

         }else if (CountH <=2520){

     CountW=CountW+scan_pixel;

     } else { return;}

}

csvFile.close();

}

main();

function saveAsRaw(file) {

var desc1 = new ActionDescriptor();

var desc2 = new ActionDescriptor();

desc2.putString( charIDToTypeID('FlCr'), "8BIM" );

desc2.putBoolean( charIDToTypeID('ChnI'), true );

desc1.putObject( charIDToTypeID('As  '), charIDToTypeID('Rw  '), desc2 );

desc1.putPath( charIDToTypeID('In  '), new File( file ) );

desc1.putBoolean( charIDToTypeID('Cpy '), true );

executeAction( charIDToTypeID('save'), desc1, DialogModes.NO );

};


It would have to be done differently as an average needs to be done. The following script will do 50pixel squares and write the results to the CSV file...

main();

function main(){

if(!documents.length) return;

if(activeDocument.mode != DocumentMode.LAB) {

    alert("Please convert this document to Lab mode\r Then re-run this script");

    return;

    }

var Name = decodeURI(app.activeDocument.name).replace(/\.[^\.]+$/, '');

try{

var Path = activeDocument.path;

}catch(e){var Path = '~/Desktop';}

var csvFile = new File(Path +"/"+Name +".csv");

csvFile.open('w');

csvFile.writeln("X,Y,L,a,b");

snapShot();

var startRulerUnits = preferences.rulerUnits;

preferences.rulerUnits = Units.PIXELS;

doc = app.activeDocument;

app.displayDialogs = DialogModes.NO;

doc.flatten();

var tilesAcross =activeDocument.width/50; //50 pixels

var tilesDown =activeDocument.height/50; //50 pixels

var tileWidth = parseInt(doc.width/tilesAcross);

var tileHeight = parseInt(doc.height/tilesDown);

ProcessFiles(tilesDown,tilesAcross,tileWidth,tileHeight);

revertToLastSnapshot();

app.preferences.rulerUnits = startRulerUnits;     

csvFile.close();

function ProcessFiles(Down,Across,offsetX,offsetY,SaveFiles){

var solidColour = new SolidColor();

TLX = 0; TLY = 0; TRX = offsetX; TRY = 0;

BRX = offsetX; BRY = offsetY; BLX = 0; BLY = offsetY;

for(var a = 0; a < Down; a++){

  for(var i = 0;i <Across; i++){

    activeDocument.selection.select([[TLX,TLY],[TRX,TRY],[BRX,BRY],[BLX,BLY]], SelectionType.REPLACE, 0, false);

    activeDocument.activeLayer.applyAverage();

                getColour(TLX,TLY);

    app.activeDocument.selection.deselect();

TLX = offsetX * (i+1) ; TRX  = TLX + offsetX; BRX = TRX; BLX = TLX; 

    }

TLX = 0; TLY = offsetY * (a +1); TRX = offsetX; TRY = offsetY * (a +1);

BRX = offsetX; BRY = TRY + offsetY; BLX = 0; BLY = (offsetY * (a +1)+offsetY);

}

}

function getColour(X,Y){

solidColour=app.activeDocument.colorSamplers.add([new UnitValue( Number(X)+1,'px'),new UnitValue(Number(Y)+1,'px' )]).color;

                var L = Math.round(solidColour.lab.l);

                var a = Math.round(solidColour.lab.a);

                var b = Math.round(solidColour.lab.b);

                csvFile.writeln((Number(X)+1)+","+(Number(Y)+1)+","+L+","+a+",",b);

                app.activeDocument.colorSamplers.removeAll();

}

function snapShot() {

    var desc9 = new ActionDescriptor();

        var ref5 = new ActionReference();

        ref5.putClass( charIDToTypeID('SnpS') );

    desc9.putReference( charIDToTypeID('null'), ref5 );

        var ref6 = new ActionReference();

        ref6.putProperty( charIDToTypeID('HstS'), charIDToTypeID('CrnH') );

    desc9.putReference( charIDToTypeID('From'), ref6 );

    desc9.putEnumerated( charIDToTypeID('Usng'), charIDToTypeID('HstS'), charIDToTypeID('FllD') );

    executeAction( charIDToTypeID('Mk  '), desc9, DialogModes.NO );

};

function revertToLastSnapshot() {

   var doc = app.activeDocument;

   var hsObj = doc.historyStates;

   var hsLength = hsObj.length;

   for (var i=hsLength - 1;i>-1;i--) {

     if (hsObj.snapshot) {

       doc.activeHistoryState = doc.historyStates.getByName('Snapshot ' + i);

       break;

     }

   }

}

}

c.pfaffenbichler
Community Expert
Community Expert
December 5, 2011

If the images are of any »serious« size I’m afraid what you are asking is, while possible, probably not sensible as iterating the color picker through all the pixels would be a rather timeconsuming practice.

May I ask what is the reason behind your request, what are you trying to achieve exactly?