Skip to main content
Participant
December 5, 2011
Answered

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

  • December 5, 2011
  • 2 replies
  • 5563 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 20, 2011

Is there any way to extract the average LAB value of say 20 pixel squares?

I attempted to amend your script to this function, but realize that although the X and Y value change according to what i want, the LAB values are still running as per every pixel!


This will return a twenty pixel square Lab average...

//usage = getLabAverage X , Y
function main(){
if(!documents.length) return;
var Result =getLabAverage(10,10);
var L = Math.round(Result.lab.l);
var a = Math.round(Result.lab.a);
var b = Math.round(Result.lab.b);
alert("L = " + L + " a = " + a + " b = " + b);
}
main();

function getLabAverage(x,y){
var startRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
activeDocument.selection.select([[x,y], [x+20,y], [x+20,y+20], [x, y+20]], SelectionType.REPLACE, 0, false);
activeDocument.activeLayer.applyAverage();
var solidColour = new SolidColor();
solidColour=app.activeDocument.colorSamplers.add([new UnitValue( x+1,'px'),new UnitValue(y+1,'px' )]).color;
executeAction( charIDToTypeID('undo'), undefined, DialogModes.NO );
activeDocument.selection.deselect();
app.preferences.rulerUnits = startRulerUnits;
app.activeDocument.colorSamplers.removeAll();
return solidColour;
}

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?