We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpPrograms › counting colors
Page Index Toggle Pages: 1
counting colors (Read 3436 times)
counting colors
Jun 9th, 2010, 11:33pm
 
Hey guys, i had to create a new account. My last one (jazz) didnt work anymore Sad

anyway, i have a little question, i am writing a program to calculate the average color of a webcam image. i will show you how i did that...
Code:


for (int i = 0; i < myCapture.pixels.length; i++) {
r+= red(myCapture.pixels[i]);
g+= green(myCapture.pixels[i]);
b+= blue(myCapture.pixels[i]);
}
r= r/myCapture.pixels.length;
g= g/myCapture.pixels.length;
b= b/myCapture.pixels.length;

average = color(r,g,b);


this works fine, but i always get a brownish grey color. Ok, i know why, because i am calculating the average Smiley but i thought maybe it makes more sense to get the color that appears most often to get a nice color out of an image.
but i have no idea how i could do that. i can not create an array for every 16.mil color available and count it up if it exists.
what would be the best way to do it ? any ideas ?

Thank you alot!
Re: counting colors
Reply #1 - Jun 10th, 2010, 1:28am
 
It depends on your exact needs, but if you use instead the HSB mode, you can make stats on hue, discarding saturation and brightness information. Or make broader categories, ranges of hue/saturation/brightness combinations.
In any case, it will be more significant than using RGB values...
Re: counting colors
Reply #2 - Jun 10th, 2010, 4:16am
 
my exact needs are, i am loading an image and want to know, whats the most used color in that image. which color exists the most. So i want to take care of brightness and saturation as well. So i am not quite sure how to start. even when using hsb mode.

I read that there is a colorlibrary by toxi, that has all kind of colors sorting. but only sort by hue, saturation, brightness, but not the amount of color Sad  

or does anybody else have a good idea how to extract the main color of an image, like i said, average color was not good, cause i mostly end up with a grey/brown.

Re: counting colors
Reply #3 - Jun 10th, 2010, 5:20am
 
jazzpower wrote on Jun 10th, 2010, 4:16am:
but i have no idea how i could do that. i can not create an array for every 16.mil color available and count it up if it exists.
[...]
I read that there is a colorlibrary by toxi, that has all kind of colors sorting. but only sort by hue, saturation, brightness, but not the amount of color Sad  


Well, you could very well use a HashMap (http://processing.org/reference/HashMap.html) to circumvent creating an array for the 16M colors. You'd scan the entire image pixels array and store an incremental count in the value associated to the String representation of the color.
Re: counting colors
Reply #4 - Jun 10th, 2010, 5:47am
 
OK, here is another approach.
Code:
final int GRANULARITY = 16;

class SmallColor
{
final int r;
final int g;
final int b;

SmallColor(int pr, int pg, int pb)
{
r = pr; g = pg; b = pb;
}

color GetColor()
{
return color(r, g, b);
}

int hashCode()
{
return (r * GRANULARITY + g) * GRANULARITY + b;
}
boolean equals(Object o)
{
SmallColor sc = (SmallColor) o;
return r == sc.r && g == sc.g && b == sc.b;
}
}

void setup()
{
size(500, 500);
background(255);
println(GRANULARITY);
colorMode(RGB, GRANULARITY);

HashMap colors = new HashMap(GRANULARITY * GRANULARITY * GRANULARITY);
PImage img = loadImage("D:/Dev/PhiLhoSoft/images/map.jpg");
image(img, 0, 0);
for (int i = 0; i < img.pixels.length; i++)
{
SmallColor sc = new SmallColor(
(int) red(img.pixels[i]),
(int) green(img.pixels[i]),
(int) blue(img.pixels[i]));
Integer frequency = (Integer) colors.get(sc);
if (frequency == null)
{
// Not in map yet
Integer value = Integer.valueOf(1);
colors.put(sc, value);
}
else
{
Integer value = Integer.valueOf(1 + frequency);
colors.put(sc, value);
}
}
int colorNb = colors.size();
println(colorNb + " colors ranges found");

ArrayList listOfColors = new ArrayList(colors.entrySet());
Collections.sort(listOfColors, new Comparator()
{
public int compare(Object o1, Object o2)
{
Map.Entry entry1 = (Map.Entry) o1;
Map.Entry entry2 = (Map.Entry) o2;
int val1 = (Integer) entry1.getValue();
int val2 = (Integer) entry2.getValue();
if (val1 == val2)
return 0;
if (val1 < val2)
return 1;
return -1;
}
});
final int diam = 20;
noStroke();
fill(GRANULARITY);
rect(width - 2 * diam, 0, 2 * diam, height);
for (int i = 0; i < 10; i++)
{
Map.Entry me = (Map.Entry) listOfColors.get(i);
SmallColor top = (SmallColor) me.getKey();
println((Integer) me.getValue() + " " + hex(top.GetColor()));
fill(top.GetColor());
ellipse(width - diam, diam + i * diam * 2, diam, diam);
}
}

I let Processing to do the color range reduction, you change the granularity to have broader or narrower ranges.
Re: counting colors
Reply #5 - Jun 13th, 2010, 4:24pm
 
Hey, for sake of completeness (and since you mentioned my color lib earlier anyway), here's another old demo using toxiclibs (also supports tolerances):

Code:
/**
* RGBColorHistogram demo
* @author toxi
*
* Dependencies: toxiclibscore-0015, colorutils-0003
* (or newer, available from: http://toxiclibs.org/ )
*/
import toxi.color.*;
import toxi.math.*;

void setup() {
 size(1280,640);
 background(255);
 noStroke();
 // load & show image
 PImage img=loadImage("test2.jpg");
 image(img,0,0);
 // creates histogram:
 // using only half the pixels (to retrieve cols from)
 // 10% tolerance for grouping colors
 // grouped colors are blended to form an average
 ArrayList hist=createHistogramFromImage(img.pixels, img.pixels.length/2, 0.1, true);
 // render histogram
 float x=0;
 float w=(float)width/hist.size();
 for(Iterator<HistEntry> i=hist.iterator(); i.hasNext() && x<width;) {
   HistEntry e=i.next();
   println(e);
   fill(e.col.toARGB());
   float h=e.freq*height;
   rect(x,height-h,w,h);
   x+=w;
 }
}

/**
* @param img
*    pixel array to create histogram for
* @param numSamples
*    number pixels to be sampled in image
* @param tolerance
*    color tolerance used to merge similar colors
*    (based on RGB distance)
* @param blendCols
*    switch to enable color blending of binned colors
* @return sorted histogram as ArrayList
*/
ArrayList createHistogramFromImage(int[] img, int numSamples, float tolerance, boolean blendCols) {
 ColorList srcCols=ColorList.createFromARGBArray(img,numSamples,false);
 ArrayList hist=new ArrayList();
 float maxFreq=1;
 for(Iterator<TColor> i=srcCols.iterator(); i.hasNext();) {
   TColor c=i.next();
   HistEntry existing=null;
   for(Iterator<HistEntry> j=hist.iterator(); j.hasNext();) {
     HistEntry e=j.next();
     if (e.col.distanceToRGB(c)<tolerance) {
       if (blendCols) e.col.blend(c,1f/(e.freq+1));
       existing=e;
       break;
     }
   }
   if (existing!=null) {
     existing.freq++;
     if (existing.freq>maxFreq) maxFreq=existing.freq;
   }
   else {
     hist.add(new HistEntry(c));
   }
 }
 Collections.sort(hist);
 // rescale frequencies
 maxFreq=1f/srcCols.size();
 for(Iterator i=hist.iterator(); i.hasNext();) {
   HistEntry e=(HistEntry)i.next();
   e.freq*=maxFreq;
 }
 return hist;
}

/**
* A single histogram entry, a coupling of color & frequency
* Implements a comparator to sort histogram entries based on freq.
*/
class HistEntry implements Comparable {
 float freq;
 TColor col;

 HistEntry(TColor c) {
   col=c;
   freq=1;
 }

 int compareTo(Object e) {
   return -(int)(freq-((HistEntry)e).freq);
 }

 public String toString() {
   return col.toHex()+": "+freq;
 }
}
Re: counting colors
Reply #6 - Jun 13th, 2010, 11:14pm
 
Oh man, this is really cool.
Both code is really useful.
Thanks toxi and thanks philho!
Page Index Toggle Pages: 1