Search code examples
c++keyhistogrambins

Build a histogram with a predefined number of bins in C++


I want to build a histogram with a predefined number of bins defined by keys (in this case 12*5=60) in C++ and don't know how to do it. Here is a minimum example:

using namespace std;
using namespace cv;

// Function to calculate the keys defining specific ranges of r1 and theta_1
void getKeys(vector<float> r1_vector, vector<float> theta_1_vector, vector<vector<float>> &keys) {
    int r1_bin = 0;
    int r2_bin = 0;
    int theta1_bin = 0;

    vector<float> key;

    // r1 is divided equally into 5 bins ranging from -0.3 to 1.3

    for (size_t i = 0; i < r1_vector.size(); i++) {
        if (-0.3 <= r1_vector[i] && r1_vector[i] < 0.02) {
            r1_bin = 1;
        }
        else if (0.02 <= r1_vector[i] && r1_vector[i] < 0.34) {
            r1_bin = 2;
        }
        else if (0.34 <= r1_vector[i] && r1_vector[i] < 0.66) {
            r1_bin = 3;
        }
        else if (0.66 <= r1_vector[i] && r1_vector[i] < 0.98) {
            r1_bin = 4;
        }
        else if (0.98 <= r1_vector[i] && r1_vector[i] <= 1.30) {
            r1_bin = 5;
        }

    // theta_1 is divided equally into 12 bins ranging from 0 to 2*PI

        if (0 <= theta_1_vector[i] && theta_1_vector[i] < CV_PI / 6) {
            theta1_bin = 1;
        }
        else if (CV_PI / 6 <= theta_1_vector[i] && theta_1_vector[i] < CV_PI / 3) {
            theta1_bin = 2;
        }
        else if (CV_PI / 6 <= theta_1_vector[i] && theta_1_vector[i] < CV_PI / 2) {
            theta1_bin = 3;
        }
        else if (CV_PI / 2 <= theta_1_vector[i] && theta_1_vector[i] < 2 * CV_PI / 3) {
            theta1_bin = 4;
        }
        else if (2 * CV_PI / 3 <= theta_1_vector[i] && theta_1_vector[i] < 5 * CV_PI / 6) {
            theta1_bin = 5;
        }
        else if (5 * CV_PI / 6 <= theta_1_vector[i] && theta_1_vector[i] < CV_PI) {
            theta1_bin = 6;
        }
        else if (CV_PI <= theta_1_vector[i] && theta_1_vector[i] < 7 * CV_PI / 6) {
            theta1_bin = 7;
        }
        else if (7 * CV_PI / 6 <= theta_1_vector[i] && theta_1_vector[i] < 4 * CV_PI / 3) {
            theta1_bin = 8;
        }
        else if (4 * CV_PI / 3 <= theta_1_vector[i] && theta_1_vector[i] < 3 * CV_PI / 2) {
            theta1_bin = 9;
        }
        else if (3 * CV_PI / 2 <= theta_1_vector[i] && theta_1_vector[i] < 5 * CV_PI / 3) {
            theta1_bin = 10;
        }
        else if (5 * CV_PI / 3 <= theta_1_vector[i] && theta_1_vector[i] < 11 * CV_PI / 6) {
            theta1_bin = 11;
        }
        else if (11 * CV_PI / 6 <= theta_1_vector[i] && theta_1_vector[i] <= 2 * CV_PI) {
            theta1_bin = 12;
        }

        key.push_back(r1_bin);
        key.push_back(theta1_bin);
        keys.push_back(key);
        key.clear();
    }   
}



int main(int argc, char** argv)
{
    // Create some values - both vectors have the same size
    vector<float> r1_vec;
    r1_vec.push_back(-0.2);
    r1_vec.push_back(1.2);
    r1_vec.push_back(0.2);
    r1_vec.push_back(0.3);
    r1_vec.push_back(0.35);
    r1_vec.push_back(0.2);
    r1_vec.push_back(0.8);
    r1_vec.push_back(0.8);

    vector<float> theta_vec;
    theta_vec.push_back(1.4);
    theta_vec.push_back(2.4);
    theta_vec.push_back(3.7);
    theta_vec.push_back(2.4);
    theta_vec.push_back(1.5);
    theta_vec.push_back(1.6);
    theta_vec.push_back(2.4);
    theta_vec.push_back(5.8);

    vector<vector<float>> keys;
    getKeys(r1_vec, theta_vec, keys);

    // Print values
    /*for (size_t i = 0; i < keys.size(); i++) {    
            cout << "The keys for line one are: " << keys[i][0] << ", " << keys[i][1]  << endl;
    }*/

}

Now I don't know how to handle the 12 bins of theta_1 because I cannot simply count from 1 to 60 for my bins. I also have in mind that there could be a better way than building a histogram (e.g. unordered_map, map, bucket_sort or something like this). But therefore I would need specific/unique types for my keys. So in the end I want to count the occurence of every pair of keys (e.g. [2,12] has 10 occurences).
They keys might not just be pairs but even triples or quadruples and are stored in a vector<vector<float>>.


Solution

  • How about storing it in a map instead? You can then interate through the map to get the keys and occurences.

    class Histogram
    {
      map<int, int> HistMap; //key is the bin, value is count in bin
    
      void InsertIntoHMap(int);
      void CheckR1(float);
      void CheckTheta1(float);
    
     public:
       Histogram() {}
       void FillHistMap(vector<float>&, vector<float>&);
       map<int, int>& GetHMap();
       ~Histogram() {}
     };
    
     void Histogram::InsertIntoHMap(int bin)
     {
        if(HistMap.find(bin) == HistMap.end()) HistMap.insert({bin, 1});
        else HistMap[bin]++;
     }
    
     void Histogram::CheckR1(float r1)
     {
       if      (-0.3 <= r1 && r1 < 0.02)  InsertIntoHMap(1);
       else if (0.02 <= r1 && r1 < 0.34)  InsertIntoHMap(2);
       else if (0.34 <= r1 && r1 < 0.66)  InsertIntoHMap(3);
       else if (0.66 <= r1 && r1 < 0.98)  InsertIntoHMap(4);
       else if (0.98 <= r1 && r1 <= 1.30) InsertIntoHMap(5);
     }
    
     void Histogram::CheckTheta1(float t1)
     {
     // theta_1 is divided equally into 12 bins ranging from 0 to 2*PI
    
        if      (0 <= t1 && t1 < CV_PI / 6)                   InsertIntoHMap(1);       
        else if (CV_PI / 6 <= t1 && t1 < CV_PI / 3)           InsertIntoHMap(2);    
        else if (CV_PI / 6 <= t1 && t1 < CV_PI / 2)           InsertIntoHMap(3);      
        else if (CV_PI / 2 <= t1 && t1 < 2 * CV_PI / 3)       InsertIntoHMap(4); 
        else if (2 * CV_PI / 3 <= t1 && t1 < 5 * CV_PI / 6)   InsertIntoHMap(5);     
        else if (5 * CV_PI / 6 <= t1 && t1 < CV_PI)           InsertIntoHMap(6);
        else if (CV_PI <= t1 && t1 < 7 * CV_PI / 6)           InsertIntoHMap(7);     
        else if (7 * CV_PI / 6 <= t1 && t1 < 4 * CV_PI / 3)   InsertIntoHMap(8);   
        else if (4 * CV_PI / 3 <= t1 && t1 < 3 * CV_PI / 2)   InsertIntoHMap(9);
        else if (3 * CV_PI / 2 <= t1 && t1 < 5 * CV_PI / 3)   InsertIntoHMap(10);    
        else if (5 * CV_PI / 3 <= t1 && t1 < 11 * CV_PI / 6)  InsertIntoHMap(11);      
        else if (11 * CV_PI / 6 <= t1 && t1 <= 2 * CV_PI)     InsertIntoHMap(12)        
    }
    
     void Histogram::FillHistMap(vector<float>& r1_vector, vector<float>& theta_1_vector)
     {
       for (size_t i = 0; i < r1_vector.size(); i++)
       {
           CheckR1(r1_vector[i]);
           CheckTheta1(theta_1_vector[i]);  
       }
     }
    
    int main()
    {
       vector<float> r1_vec;
       r1_vec.push_back(-0.2);
       r1_vec.push_back(1.2);
       r1_vec.push_back(0.2);
       r1_vec.push_back(0.3);
       r1_vec.push_back(0.35);
       r1_vec.push_back(0.2);
       r1_vec.push_back(0.8);
       r1_vec.push_back(0.8);
    
       vector<float> theta_vec;
       theta_vec.push_back(1.4);
       theta_vec.push_back(2.4);
       theta_vec.push_back(3.7);
       theta_vec.push_back(2.4);
       theta_vec.push_back(1.5);
       theta_vec.push_back(1.6);
       theta_vec.push_back(2.4);
       theta_vec.push_back(5.8);
    
        Histogram H;
        H.FillHistMap(r1_vec, theta_vec);
    

    }