8

So I was trying to puzzle out how to calculate the average hue of a number of objects whose colors are represented by HSL values. Thankfully, I stumbled across this Stack Overflow post, and set to work implementing the algorithm provided in the top answer (I am working in C++).

Unfortunately, my implementation doesn't seem to work. Here it is, in full; note that though I write "Hue" I am using angles, in degrees, as per the initial implementation (switching from 0-360 angles to 0-256 hues, once I know my code works, shouldn't be hard).

#include <iostream>    
#include <vector>
#include <cmath>

#define PI (4*atan(1))

int main()
{
    ///
    /// Calculations adapted from this source:
    /// https://stackoverflow.com/questions/8169654/how-to-calculate-mean-and-standard-deviation-for-hue-values-from-0-to-360

    std::vector<double> Hues = {355, 5, 5, 5, 5};

    //These will be used to store the sum of the angles
    double X = 0.0;
    double Y = 0.0;

    //Loop through all H values
    for (int hue = 0; hue < Hues.size(); ++hue)
    {
        //Add the X and Y values to the sum X and Y
        X += cos(Hues[hue] / 180 * PI);
        Y += sin(Hues[hue] / 180 * PI);
    }

    //Now average the X and Y values
    X /= Hues.size();
    Y /= Hues.size();

    //Get atan2 of those
    double AverageColor = atan2(X, Y) * 180 / PI;

    std::cout << "Average: " << AverageColor << "\n";
    return 0;
}

Instead of the expected answer of 3 (since 355 should be equivalent to -5 in this scheme), I get 86.9951.

Can somebody point out what I'm doing wrong? This seems very basic.

Community
  • 1
  • 1
GarrickW
  • 2,181
  • 5
  • 31
  • 38

2 Answers2

7

atan2 takes its arguments in reverse order. I know, annoying! So try:

double AverageColor = atan2(Y, X) * 180 / PI;

The answer it gives now is 3.00488.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • Oh gods, that's embarassing. I should have seen that. Thanks! – GarrickW Dec 19 '12 at 19:13
  • 4
    A way to remind oneself of this fact is to remember that what you are trying to do is to get `atan(Y / X)`, except that we want it still working as `X -> 0`. This kind of looks like `atan2(Y, X)`. – Magnus Hoff Dec 19 '12 at 19:14
  • To simplify programmer's life, note that some languages are in the reverse order - for example in Excel atan2(x;y) – aka.nice Dec 19 '12 at 19:59
2

Try atan2(Y, X). atan2(a,b) is similar to atan(a/b), and you need the arctangent of the average sine over the average cosine.

aschepler
  • 70,891
  • 9
  • 107
  • 161