Most frequently used color

Anyone, especially newbies, asking for help with Photoshop Scripting and Photoshop Automation - as opposed to those contributing to discussion about an aspect of Photoshop Scripting

Moderators: Tom, Kukurykus

artefacti

Most frequently used color

Post by artefacti »

Hello!

I'd like to write a script that can read out the most frequently used colors from an image. Is there a special function?

THX

Professional AI Audio Generation within Adobe Premiere Pro - Download Free Plugin here

pfaffenbichler

Most frequently used color

Post by pfaffenbichler »

Please elaborate on the need or rationale for this.
And how do you define »most frequently used colors« anyway – how many colors, which tolerances are you willing to accept, …?
artefacti

Most frequently used color

Post by artefacti »

Thank you for your reply.

Sorry. My English is not so good.

I want to filter out the main colors of an image of product images.

e.g. red, yellow, green, blue, etc.

These values ​​will then be written to a CSV, so that the products can later be sorted by color in my onlineshop.

My idea would be to examine the product images all 50 or 100 pixels with the color picker to determine the HEX-Code. This HEX-Code I could assign to a colorfamily (red, green, yellow) At least I could count out which colorfamiliy has the most HEX-values.

But perhaps there is an easier another function for this?

By the way - these product images are art prints
pfaffenbichler

Most frequently used color

Post by pfaffenbichler »

Hopefully one of the regulars will chime in, because I see certain difficulties, but quite likely something like this has been attempted before.

I think the RGB Histogram can be tricky or even useless to evaluate for this task but iterating a ColorPicker through the image would almost certainly be quite slow (the Mosaic Filter could be used to average the squares the centers of which are to be measured by the way).

Maybe the Lab-histogram would be more meaningful.
Paul Riggott once gave a Script that used a RAW file to get a list of all pixels’ (in an Lab-image) L-, a- and b-values, maybe using this approach could be used to quantify the colors, too. (Applied to a downsampled copy of the image it might be faster than the ColorPicker method.)

Another possibility might be to use the Select > Color Range feature for the six colors and White and Black and compare the resultant Selections’ histograms.
artefacti

Most frequently used color

Post by artefacti »

Hi,

It works very fine just to downscaling an image to 5 pixels width. Thereby the number of pixels that have to be read out, is very small.
larsen67

Most frequently used color

Post by larsen67 »

I have used Bridge for image data in a couple of scripts for Illustrator and Indesign… Has been much quicker for me than using Photoshop… I just wanted an Array of values to use else where… Image/Pattern generation of such… Bridge will let you down sample a file if need be too… Here is what I have used a couple of times… My little home iMac will get a mega pixel in about 15-20 seconds… Yours should be much less…

Code: Select all#target bridge

getImage();

function getImage() {
   
   var image, bit;

   image = app.document.selections[0]; // First item of selection

   bit = new BitmapData( image.spec, true ); // Make bitmap data

   //bit = bit.resize( bit.height/40, 'bicubicSharper' );

   $.writeln( 'Width: ' + bit.width + ' Height: ' + bit.height );

   //bit.exportTo( File( Folder.desktop + '/Muppet_Fluff.jpg', 100 ) );
   
   readColorData( bit );

};

function readColorData( bitMap ) {

   var main, pix, row, x, y;
   
   main = Array();

   for ( y = 0; y < bitMap.height; y++ ) {
      
      row = Array();
      
      for ( x = 0; x < bitMap.width; x++ ) {
         
         pix = bitMap.getPixel( x, y );
         
         row.push( new Color( pix ).toString() );
         
         //row.push( new Color( pix ).number );
         
         //row.push( new Color( pix ) );

      };

      main.push( row );

   };

   writeImageData( main );

};

function writeImageData( data ) {

   var txt = File( Folder.desktop + '/Muppet_Fluff.txt' );

   txt.open( 'w' );
   txt.write( data.toSource() );
   txt.close();

};
artefacti

Most frequently used color

Post by artefacti »

good evening,

thanks for all the answers. this script is part of a larger script that runs in Photoshop. So I would like to implement it using Photoshop. I have no expereience to access with javascript on bridge or other programs.

I am now working on this: first I converted the image into a 3 pixels wide or tall image. Here I get a very good result of the colors used.

Code: Select all//SKALIERE AUF 3PIXEL IN DER HOECHSTEN LAENGE__________________________________________________________________________________

var PixelBreite = activeDocument.width.value;
var PixelHoehe = activeDocument.height.value;

if (PixelBreite>=PixelHoehe)

{
   
    var smallBreite = 3;
    var smalHoehe = Math.round(PixelHoehe*3/PixelBreite);
    activeDocument.resizeImage(smallBreite,smallHoehe,150);
    }

else

{
   
        var smallHoehe = 3;
    var smalBreite = Math.round(PixelBreite*3/PixelHoehe);
    activeDocument.resizeImage(smallBreite,smallHoehe,150);
   
   
    }


see here:



After this I am starting a loop for selecting the 6 (or more) pixels:


Code: Select all
//SCHLEIFE FUER DAS SELEKTIEREN DER EINZELNEN PIXEL UND AUSLESEN DER FARBWERTE_______________________________________________

var PixelBreite = activeDocument.width.value;
var PixelHoehe = activeDocument.height.value;
var AnzahlPixel = PixelBreite*PixelHoehe;


Farbwerte = "";

for (var i = 1;  i <= AnzahlPixel;  i++) {
   
//X und Y Ursprung ermitten

var xUrsprung = ((PixelBreite*PixelHoehe)+(i-1))%PixelBreite;

if (i<=PixelBreite)

{ var yUrsprung = 0;
    }

else { if (i>PixelBreite&&i<=2*PixelBreite)
   
    { yUrsprung = 1;
        }

else {yUrsprung = 2;}
    }
 
//Selektion erstellen

var PixelSelektion = [[xUrsprung,yUrsprung],[xUrsprung+1,yUrsprung],[xUrsprung+1,yUrsprung+1],[xUrsprung,yUrsprung+1]];
activeDocument.selection.select(PixelSelektion);

        }




So now the loop selects every pixel; I tested it with the alert function.

How can I now get the color information out of each pixel? Which function should I use?
Mike Hale

Most frequently used color

Post by Mike Hale »

Depending on which version of Photoshop you want to support you either make a selection of that single pixel then get the color from the histogram or use a ColorSampler( newer versions ) to get the color.

ColorSamplers will be a little faster but either way it will be slow if there are a lot of pixels you want to check. I don't think Photoshop script is suited to doing this.

If you are will to use another app to examine the data for the color you can save the image as a Photoshop raw file or a PBM file and extract the color info using that file with some app better suited to working with a large amount of data.
artefacti

Most frequently used color

Post by artefacti »

Thank you. Because I first resize the image to a maximum of 3x3 pixel, the maximum number of pixels to be examined is limited on 9 pixels.

I will try tomorrow colorsampler and post my experiences and progress.

PS: I am using CS5
pfaffenbichler

Most frequently used color

Post by pfaffenbichler »

I’ve been giving it some more thought and I found a fairly convoluted approach to evaluate the prevalence of the six colors that is probably not much use here, but still … 
The Script would run faster when using Selections instead of alpha channels, but I have not found a way to turn off »Warning: No pixels are more than 50% selected. The selection edges will not be visible.« when running Calculations or Color Range in the Script.

Code: Select all// 2012, use at your own risk;
#target photoshop
if (app.documents.length > 0) {
var myDocument = app.activeDocument;
if (myDocument.mode == DocumentMode.RGB) {
// collect means of color ranges;
var theArray = new Array;
//get Red;
theArray.push(["red", getColorRangeHistogram ("Grn ", true, "Bl  ", true, "Rd  ", false)[0]]);
//get Yellow;
theArray.push(["yellow", getColorRangeHistogram ("Grn ", false, "Rd  ", false, "Bl  ", true)[0]]);
//get Green;
theArray.push(["green", getColorRangeHistogram ("Bl  ", true, "Rd  ", true, "Grn ", false)[0]]);
//get Cyan;
theArray.push(["cyan", getColorRangeHistogram ("Bl  ", false, "Grn ", false, "Rd  ", true)[0]]);
//get Blue;
theArray.push(["blue", getColorRangeHistogram ("Grn ", true, "Rd  ", true, "Bl  ", false)[0]]);
//get Magenta;
theArray.push(["magenta", getColorRangeHistogram ("Bl  ", false, "Rd  ", false, "Grn ", true)[0]]);
theArray.sort(sortByDate);
// compare values;
var sortedArray =  [[theArray[0][0]]];
for (var m = 1; m < theArray.length; m++) {
   var thePrevious = theArray[m - 1];
   var thisOne = theArray[m];
   if (thisOne[1] > thePrevious[1] - 2) {
      sortedArray[sortedArray.length - 1].push(thisOne[0])
      }
   else {
      sortedArray.push([thisOne[0]])
      }
   };
// get results;
var theString = new String;
for (var n = 0; n < sortedArray.length; n++) {
   var theseOnes = sortedArray[n];
   if (theseOnes.length > 1) {theString = theString + "Number " + (n + 1) + " colors are " + theseOnes.join(", ") + "\n"}
   else {theString = theString + "Number " + (n + 1) + " color is " + theseOnes[0] + "\n"};
   };
// get the overall mean;
var theMean = histogramMean(myDocument.histogram);
switch (Math.round(theMean[0] / 256 * 4)) {
   case 0: theBright = "very dark";
   break;
   case 1: theBright = "dark";
   break;
   case 2: theBright = "of medium brightness";
   break;
   case 3: theBright = "light";
   break;
   case 4: theBright = "very light";
   break;
   };
theString = theString + "\n\n the image appears to be " + theBright + ". ";
alert (theString);
};
};
////// get histogram  of channel operations //////
function getColorRangeHistogram (channel1, inverse1, channel2, inverse1, channel3, inverse3) {
var theChannel1 = channelOperation (channel1, inverse1, channel2, inverse1, "Drkn");
var theChannel = channelOperation (theChannel1, false, channel3, inverse3, "linearBurn");
theChannel1.remove();
var theHisto = theChannel.histogram;
app.activeDocument.selection.deselect();
theChannel.remove();
return histogramMean (theHisto)
};
////// channel operation //////
function channelOperation (channel1, inverse1, channel2, inverse2, theBlend) {
// =======================================================
var idMk = charIDToTypeID( "Mk  " );
    var desc1 = new ActionDescriptor();
    var idNw = charIDToTypeID( "Nw  " );
    var idChnl = charIDToTypeID( "Chnl" );
    desc1.putClass( idNw, idChnl );
    var idUsng = charIDToTypeID( "Usng" );
        var desc2 = new ActionDescriptor();
        var idT = charIDToTypeID( "T   " );
if (channel1.constructor == String) {
            var ref1 = new ActionReference();
            var idChnl = charIDToTypeID( "Chnl" );
            var idChnl = charIDToTypeID( "Chnl" );
            var idGrn = charIDToTypeID( channel1 );
            ref1.putEnumerated( idChnl, idChnl, idGrn );
            var idLyr = charIDToTypeID( "Lyr " );
            var idOrdn = charIDToTypeID( "Ordn" );
            var idMrgd = charIDToTypeID( "Mrgd" );
            ref1.putEnumerated( idLyr, idOrdn, idMrgd );
        desc2.putReference( idT, ref1 );
      }
else {
      var ref2 = new ActionReference();
      var idChnl = charIDToTypeID( "Chnl" );
      ref2.putName( idChnl, channel1.name );
      desc2.putReference( idT, ref2 );
   };
        var idInvr = charIDToTypeID( "Invr" );
        desc2.putBoolean( idInvr, inverse1 );
        var idClcl = charIDToTypeID( "Clcl" );
        var idClcn = charIDToTypeID( "Clcn" );
if (theBlend.length > 4) {
        var idDrkn = stringIDToTypeID( theBlend );
      }
else {
        var idDrkn = charIDToTypeID( theBlend );
      };
        desc2.putEnumerated( idClcl, idClcn, idDrkn );
        var idSrctwo = charIDToTypeID( "Src2" );
            var ref2 = new ActionReference();
            var idChnl = charIDToTypeID( "Chnl" );
            var idChnl = charIDToTypeID( "Chnl" );
            var idBl = charIDToTypeID( channel2 );
            ref2.putEnumerated( idChnl, idChnl, idBl );
            var idLyr = charIDToTypeID( "Lyr " );
            var idOrdn = charIDToTypeID( "Ordn" );
            var idMrgd = charIDToTypeID( "Mrgd" );
            ref2.putEnumerated( idLyr, idOrdn, idMrgd );
        desc2.putReference( idSrctwo, ref2 );
        var idInvS = charIDToTypeID( "InvS" );
        desc2.putBoolean( idInvS, inverse2 );
    var idClcl = charIDToTypeID( "Clcl" );
    desc1.putObject( idUsng, idClcl, desc2 );
executeAction( idMk, desc1, DialogModes.NO );
return app.activeDocument.channels[app.activeDocument.channels.length - 1];
};
////// get mean of histogram //////
function histogramMean (theHist) {
// get total number;
var thePixels = 0;
for (var m = 0; m < theHist.length; m++) {
   thePixels = thePixels + theHist[m]
   };
// get mean and median;
var theMean = 0;
var aTotal = 0;
var check = false;
for (var n = 0; n < theHist.length; n++) {
   theMean = theMean + (n * theHist[n] / thePixels);
   aTotal = aTotal + theHist[n];
   if (aTotal >= thePixels / 2 && check == false) {
      theMedian = n;
      check = true;
      }
   };
// get standard deviation;
var theStandDev = 0;
for (var o = 0; o < theHist.length; o++) {
   theStandDev = theStandDev + (Math.pow ((o - theMean), 2) * theHist[o])
   };
theStandDev = Math.sqrt (theStandDev / thePixels);
//
return ([theMean, theMedian, theStandDev]);
//alert (thePixels + " pixels\n" + theMean + " mean\n" + theMedian + " median\n" + theStandDev + " standard deviation")
};
////// to sort a double array based on script by sam, http://www.rhinocerus.net/forum/lang-javascript/ //////
function sortByDate(a,b) {
if (a[1]<b[1]) return 1;
if (a[1]>b[1]) return -1;
return 0;
};