9

I am trying to access an 3D histogram of a RGB image. But the histogram matrix returns the number of rows and columns equal to -1. I want to iterate through the histogram and check the individual values in the 3D matrix. But, when I check the number of rows and columns in the matrix, I get -1 as shown below.

CODE

int main( int argc, const char** argv ) {
    Mat image = imread("fl.png");
    int histSize[3] = {8, 8, 8};
    float range[2] = {0, 256};
    const float * ranges[3] = {range, range, range};
    int channels[3] = {0, 1, 2};
    Mat hist;
    calcHist(&image, 1, channels, Mat(), hist, 3, histSize, ranges);
    cout << "Hist.rows = "<< hist.rows << endl;
    cout << "Hist.cols = "<< hist.cols << endl;
    return 0;
}

OUTPUT

Hist.rows = -1
Hist.cols = -1

What mistake am I making? How can I access the individual matrix values.

bikz05
  • 1,575
  • 12
  • 17

1 Answers1

11

From the documentation of Mat:

//! the number of rows and columns or (-1, -1) when the array has more than 2 dimensions

But you have 3 dimensions.

You can access individual values of your histogram using hist.at<T>(i,j,k).

Or you can use iterators as described in the documentation here.

Code

    // Build with gcc main.cpp  -lopencv_highgui -lopencv_core -lopencv_imgproc
    #include <iostream>
    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui.hpp>
    #include <opencv2/imgproc.hpp>

    using std::cout;
    using std::endl;
    using namespace cv; # Please, don't include whole namespaces!

    int main( int argc, const char** argv ) {
        Mat image = imread("good.jpg");
        int histSize[3] = {8, 8, 8};
        float range[2] = {0, 256};
        const float * ranges[3] = {range, range, range};
        int channels[3] = {0, 1, 2};
        Mat hist;
        calcHist(&image, 1, channels, Mat(), hist, 3, histSize, ranges);
        cout << "Hist.dims = " << hist.dims << endl;
        cout << "Value: " << hist.at<double>(0,0, 0) << endl;
        cout << "Hist.rows = "<< hist.rows << endl;
        cout << "Hist.cols = "<< hist.cols << endl;
        return 0;
    }

Iterate through every value:

        for (MatConstIterator_<double> it = hist.begin<double>(); it != hist.end<double>(); it++) {
            cout << "Value: " << *it << "\n";
        }
        cout << std::flush;

Iterate through every value using indices:

        for (int i=0; i<histSize[0]; i++) {
            for (int j=0; j<histSize[1]; j++) {
                for (int k=0; k<histSize[2]; k++) {
                    cout << "Value(" << i << ", " << j << ", " << k <<"): " << hist.at<double>(i, j, k) << "\n";
                }
            }
        }
        cout << std::flush;
Unapiedra
  • 15,037
  • 12
  • 64
  • 93
  • Thanks for the edited answer. I read the documentation earlier, but could not figure it out, how to iterate through the it. How can I iterate using for loops to access single value of histogram? – bikz05 Oct 17 '14 at 10:52
  • 1
    I've added that info. – Unapiedra Oct 17 '14 at 11:21
  • @Unipiedra Thank You. I have accepted the answer, but is there a way to also access the value using the current index values i.e. `i,j,k`. – bikz05 Oct 17 '14 at 11:42
  • So function like cv::normalize (like normalize(hist, hist, 0, 255, NORM_MINMAX, -1, Mat()); ) will not work? – mrgloom Oct 08 '15 at 17:16
  • The question was about accessing individual elements. I don't see how ` normalize ` would help. – Unapiedra Oct 08 '15 at 17:19
  • `normalize()` won't work for a 3D histogram. Neither does the function `minMaxLoc`. – Yonatan Simson Dec 10 '15 at 14:11