Endless Paradigm

Full Version: Interpreting color (and why I wish I paid attention in school)
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
This is going to be my first-ish coding post I've ever made.

I've been having a problem lately, one of my ideas for myself was to make a sorting algorithm to sort images based on color.

Sounds easy right, well, it depends.

Anyway, my first stop was running around for an imaging library that I could use to start doing this voodoo. Since I've heard one or two things about opencv, I decided to give it a go.

It was a bit tough installing the darn thing, but I got it working a few weeks ago. I then began loading images and screwing around with their data (like setting the red channel to zero, finding out how I iterate through the data structures and just really getting the hang of C/C++).

One of the issues that I came across was actually categorizing the colors. First I actually thought about using RGB, but that came across as stupid. How would I describe a range that would compose a color in RGB? If you viewed RGB (as defined in a cartesian coordinate system) you'd see that defining a some color, say purple, would have you taking a chunk off of the RGB cube. Not the type of thing I wanted to do.

That's when I learnt about the HSV/HSL cylinder coordinate system (ok well, I already knew about it, it's just that I actually didn't think of it as a cylinder). Personally, I thought it was absolutely perfect. Why? Because technically the hue value (the degrees around the cylinder) were the "definitions" of color I was looking for.

Stupidly enough, I decided to take the average of the hues throughout the image. It was a good idea at first, but the statistical method was incredibly weak (this is grade 8 algebra). For some images, I got the expected hue in a range I would call a color (270 - 300 would be what I call purple). Some just didn't make any sense (A picture with a lot going on with it, opinionally red and yellow in my eyes, came out to be green). Why this probably happened was due to the fact that when I take an average, it takes an average of all the data points, which skews the average to the wrong conclusion given two hues/colors are competing in the picture. That's when I also had another problem, not every "color" is defined with a hue. For example, brown is when you have orange/red with the brightness turned down by half. How would my algorithm check for that?

So some of the things I'm having trouble with right now:
- My statisical method sucks (I'm taking a flipping average and not trying to analyze certain areas of the image that have a certain color, I remember there is a statisical method to check for this but unfortunately I forgot where I should look for it. This is important because I can decide which group I should choose to say: "this is what the image is largely composed of") and I avoid having the problem where I'll get a green hue if there are two hue groups that are competing.

In retrospect, you can see that most of the methods I'm employing are very basic. Had I paid a little more attention to the intuitive applications of my other courses, this wouldn't be bogging me down. Oh well, I have to relearn everything now.

Stay in school if you want to be cool I guess.

EDIT: Actually, the saturation/value problem isn't all that hard, I just need to define an area rather than a range and that should be good in summarizing the color. The average statistic has got to change though.
This is hardly a trivial thing to do.  Classifying an image into a colour, firstly, can be considered an AI and/or highly heuristical task.

For one, you'd need to define how to handle certain border cases, such as:
- an image comprised evenly of two colours - eg half red, half blue » how do you classify this image?
- image comprised of pixels, each of a completely random colour; humans would probably just consider it a jumble with no specific colour, though from a distance, may look grey
-

...and wee're not even looking into image analysis, or anything about perceptual visualisation of the image.

However, if all you wish to do is stick with a simple method (note, I have not tried any of these, this is just my random speculation which may or may not work):
  1. If you're looking to find the most used colour, you can try a local weighted average over each hue/classification and find the highest average, eg

    Code:
    for(hue=0; hue<255; hue++) {
      // weighted average on 5 nearest colours - you may wish to weight over more
      wHueTally = hueTally[WRAP(hue -2)] *0.15 + hueTally[WRAP(hue -1)] *0.2 + hueTally[hue] *0.3 + hueTally[WRAP(hue +1)] *0.2 + hueTally[WRAP(hue +2)] *0.15
      if(wHueTally > max) {
        max = wHueTally
        theHue = hue
      }
    }

  2. You may consider doing a weighted average of the HSL value rather than just taking the H component, eg
    colourClassification = 0.5*H + 0.2*S + 0.3*L
    (you should play around to see what weights work best)
Awesome stuff Zinga! I used your implementation with a small added bonus of when I make a tally, I also multiply it by it's value. This at least gives precedence to colors that are more pronounced (less black) in the picture.

The results are pretty good, it can get objectively clear hues, sometimes it's a bit off, but this is awesome!

Also my wrap is terrible, a case statement to check for boundaries, I should probably make some sort of inline function to handle the wrapping, oh well.

Thanks for the response, it helped quite a bit and it made me come to the conclusion that averaging values isn't what I'm looking for, but rather a certain classification/choosing of color (hence the algorithm).

Also, classifying a picture with a bunch of random hues isn't all that important since I wanted to use this to sort color schemed backgrounds, so, sorting an image with different colors wouldn't be of specific interest.

EDIT:
double you tee eff???? The program gives the wrong output on some runs, giving a value of 359 and sometimes the right hue. What's up with that?!

EDIT 2:
I optimized with the -O2 flag and now the errors have gone away. Don't know whether i should pursue the cause of this.
Tetris999 Wrote: [ -> ]Also my wrap is terrible, a case statement to check for boundaries, I should probably make some sort of inline function to handle the wrapping, oh well.
Shouldn't be too difficult

C Code
// assumes -256 < n < 511
static inline int WRAP(int n) {
  if(n > 255) return n-256;
  if(n < 0) return n+256;
  return n;
}


Or if it makes sense to you

C Code
static inline int WRAP(int n) {
  return n & 0xFF;
}

Reference URL's