views:

174

answers:

2

Hi everybody: i want to take a picture and retrieve the main color analyzing its palette (i think this should be the easiest way), but i don't know really where to start.

A: 

Assuming you have a raw 24 bit RGB image and you want to find the number of times each color appears:

there are really 2 simple ways of doing this:

my favourite is just to create an array of ints for each possible color, then just index into that array and ++ that method does use like 64 meg of memory tho.

another method is to create a linked list, adding to it each time a new color is encountered, the structs stored in the list would store the color and the number of times encountered, its slow to do all the accumulating cause you have to search the whole list for each pixel, but it would be quicker to sort by number of times used, as only colors actually used are in the list (making it more ideal for small images too)

I like a compromise between the two:

take say, red and green to index into an array of linked lists, that way the array is only 256k (assuming it just stores a pointer to the list) and the lists to search will be relatively short because its only the blue variants of the Red,Green color. if you were only interested in the SINGLE MOST used color, I would just store this in a "max color" variable, that I would compare with each time I iterated over a pixel and incremented a color, that way you don't have to go through the whole structure searching for the most used at the end.

struct Pixel
{
   byte R,G,B;
}

const int noPixels = 1024*768; // this is whatever the number of pixels you have is

Pixel pixels[noPixels]; // this is your raw array of pixels

unsinged int mostUsedCount = 0;
Pixel mostUsedColor;

struct ColorNode
{
    ColorNode* next;
    unsigned int count;
    byte B;
} 

ColorNode* RG = new ColorNode[256*256];
memset(RG,0,sizeof(ColorNode)*256*256);

for(int i = 0; i<noPixels; i++)
{
   int idx = pixels[i].R + pixels[i].G*256;
   ColorNode*t;
   for(t=RG[idx]; t; t = t->next)
   {
      if(t->B == pixels[i].B)
      {
          break;
      }
   }
   if(!t)
   {
       t = new ColorNode;
       t->next = RG[idx];
       RG[idx] = t;
       t->B = pixels[i].B;
       t->count = 0;
   }

   t->count++;
   if(t->count > mostUsedCount)
   {
       mostUsedCount = t->count;
       mostUsedColor = pixels[i];
   }
}

you might consider using a Binary Tree, or Tree of some kind too, rather than just searching through a list like that. but I'm not too knowledgeable on that type of thing...

Oh yeah... I forgot about memory management.

you could just go through the whole array and delete all the nodes that need deleting, but that would be boring.

if possible, allocate all the memory you would possibly need at the beginning, that would be 256k + sizeof(ColorNode) *noPixels ~= 256 + 2 to 3 times the size of your raw image data.

that way you can just pull nodes out using a simple stack method, and then delete everything in one foul swoop.

another thing you could do is also add the nodes to another link list for ALL allocated nodes as well, this increases the iterating process, adds data to Color node, and just saves having to iterate through the entire array to find lists to delete.

matt
Why use a linked list when you have counted set? http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/Foundation/Classes/NSCountedSet_Class/Reference/Reference.html
KennyTM
A: 

the format is JPG: the image is the one i take from camera...

timetravel0