Search code examples
opencvcolorshistogramhue

What does OpenCV Core.MinMaxLocResult return?


I'm trying to do something similar to this post: Getting dominant colour value from HSV Histogram

I have an image and want to extract the dominant color (Hue) from it. I've gotten to the point where I have calculated the histogram, and gotten the maxValue from minMaxLoc. But the numbers I'm retrieving from Core.MinMaxLocResult make absolutely no sense. I'm getting things like 806924 and 1067036; shouldn't the expected values of Hue be between 0 and 180?

Is the histogram supposed to be normalized? How so? I've seen methods like "equalizeHist" and "normalize", but don't really know how to use these and how they'll help me.

Also, once I've gotten a sensible "most occuring" Hue number, how do I translate that to an actual color shade (like "Green is the most occuring color in this image")? Is there a standard Hue range? Like 0-10 is red, 10-20 is purple, etc?

UPDATE: HERE IS MY CODE:

    private void processImage(String imgFilename) {
            channels = new MatOfInt[] { new MatOfInt(0), new MatOfInt(1),
            new MatOfInt(2) };
    histSize = new MatOfInt(histSizeNum);
    hRanges = new MatOfFloat(0f, 180f); // hue varies from 0 to 179
    // use openCV stuff to convert from RGB to HLS space
    Mat src = Highgui.imread(imgFilename);
    Mat hls = new Mat();// destination color space
    Imgproc.cvtColor(src, hls, Imgproc.COLOR_RGB2HLS);
    Core.split(hls, hlsChannels);
    Mat hue = hlsChannels.get(0);
    Mat lum = hlsChannels.get(1);
    Mat sat = hlsChannels.get(2);
    // we compute the histogram from the 0-th channel for hue
    Imgproc.calcHist(Arrays.asList(hls), channels[0], new Mat(), hist,
            histSize, hRanges);

     Core.normalize(hist, hist, 0,2, Core.NORM_MINMAX, -1, new Mat());

    Core.MinMaxLocResult result = Core.minMaxLoc(hist);
    // max value should contain the most-recurring Hue value.
    double mostOccurringHue = result.maxVal;
    double leastOccurringHue = result.minVal;
    //double mostOccurringHue = result.maxLoc.x;
    //double leastOccurringHue = result.minLoc.x;

    // print out for sanity checking
    System.out.println("MAX HUE = " + Double.toString(mostOccurringHue) +"\n");
    System.out.println("MIN HUE = " + Double.toString(leastOccurringHue) +"\n");

Solution

  • Instead of using the openCV's ibuilt method of calculating the histogram and its normalization, i have written my own code for it as we are creating histogram only for hue channel. Have a look at my code.

    int main()
    {
    
        Mat input = imread("jan31/class4Jan31.jpg",1);
        Mat hsv_input;
        int h_bins = 5;
        Mat hist_input = Mat::zeros( 1, h_bins, CV_32FC1);
        int h_range = 179;
        int totalNumberPixels = 0;
    
        cvtColor(input, hsv_input, CV_RGB2HSV);
        Mat hsv_channels[3];
    
        split( hsv_input, hsv_channels );
    
        for (int i=0; i<hsv_channels[0].rows; i++)
        {
            for (int j=0; j<hsv_channels[0].cols; j++)
            {               
                if( (int)hsv_channels[1].at<uchar>(i,j)>10 &&    (int)hsv_channels[1].at<uchar>(i,j)>100)
                {               
                    totalNumberPixels++;
                    int pixel_value = (int)hsv_channels[0].at<uchar>(i,j);
                    int corresponding_bin =  ( pixel_value * h_bins ) / h_range;                
                    hist_input.at<float>( 0, corresponding_bin ) = ( hist_input.at<float>( 0, corresponding_bin ) + 1 );                
                }                                                                                       
            }
        }
    
        cout<<"\n total pixels: "<<totalNumberPixels;
    
        for(int i=0; i<hist_input.rows; i++)
        {
            for (int j=0; j<hist_input.cols; j++)
            {
                float pixel = hist_input.at<float>(i,j);
                hist_input.at<float>(i,j) = pixel / totalNumberPixels;
    
                pixel = hist_input.at<float>(i,j);
                cout<<"\n Pixel: "<<pixel;
            }
        }
    
        cv::waitKey(0);
        return 0;
    }