5

I need to find the most present color in an image with OpenCV. I referred https://docs.opencv.org/2.4/modules/imgproc/doc/histograms.html?highlight=calchist and when I run that code I get for the H-S histogram is as below image. How do I tell the most present color from that histogram? Can someone please tell me how I get the most present color in an image using the histogram for HSV? (I am using C++)

this

Nah
  • 1,690
  • 2
  • 26
  • 46
Satinger
  • 123
  • 1
  • 8

3 Answers3

4

As far as I can see (a very ambigous description on opencv site) here we have Hue on first axis, Saturation on second axis and color intensity as point brightness. Hue varies from 0 (red) to 180 (from violet to red). Saturaion varies from 0 to 255 (black-gray-white). Hue is quantized from 180 to 30. Saturation is quantized from 255 to 32 (in accordance with your link to opencv site). The brighter square area on histogram, the brighter some combination of hue and saturation on your image. I reproduced OpenCV sample on my PC. I added my source image and HS histogram. On HS histogram we can see one bright rectangle corresponding to blue color of medium saturation enter image description here I also added source modified for OpenCV 3.4.0

#include <Windows.h>
#include <Vfw.h>


#include "opencv2\core\core.hpp"
#include "opencv2\imgproc\imgproc.hpp"
#include "opencv2\imgcodecs\imgcodecs.hpp"
#include "opencv2\highgui\highgui.hpp"

using namespace cv;

int _tmain(int argc, _TCHAR* argv[])
{
    Mat src, hsv;

    src=imread("blue_circle.jpg");
    cvtColor(src, hsv, CV_BGR2HSV);

    // Quantize the hue to 30 levels
    // and the saturation to 32 levels
    int hbins = 30, sbins = 32;
    int histSize[] = {hbins, sbins};
    // hue varies from 0 to 179, see cvtColor
    float hranges[] = { 0, 180 };
    // saturation varies from 0 (black-gray-white) to
    // 255 (pure spectrum color)
    float sranges[] = { 0, 256 };
    const float* ranges[] = { hranges, sranges };
    MatND hist;
    // we compute the histogram from the 0-th and 1-st channels
    int channels[] = {0, 1};

    calcHist( &hsv, 1, channels, Mat(), // do not use mask
    hist, 2, histSize, ranges,
    true, // the histogram is uniform
    false );
    double maxVal=0;
    minMaxLoc(hist, 0, &maxVal, 0, 0);

    int scale = 10;
    Mat histImg = Mat::zeros(sbins*scale, hbins*10, CV_8UC3);

    for( int h = 0; h < hbins; h++ )
        for( int s = 0; s < sbins; s++ )
        {
            float binVal = hist.at<float>(h, s);
            int intensity = cvRound(binVal*255/maxVal);
            rectangle( histImg, Point(h*scale, s*scale),
            Point( (h+1)*scale - 1, (s+1)*scale - 1),
            Scalar::all(intensity),
            CV_FILLED );
        }

        namedWindow( "Source", CV_WINDOW_FREERATIO );
        imshow( "Source", src );

        namedWindow( "H-S Histogram", CV_WINDOW_FREERATIO );
        imshow( "H-S Histogram", histImg );
        waitKey(0);
    return 0;
}
  • Thank you for this. But how do I determine what color it is looking at the histogram? Is it possible? – Satinger May 11 '18 at 13:34
  • To get RGB values from histogram I'd suggest you the next sequence. Scan all rows and columns of histogram and find the element with maximum value. Actually it will be a V value. Then get position of this element inside histogram . Number of row and column will give you Hue and Saturaion value. And finally you will convert HSV to RGB – VideoProcessingResearcher May 14 '18 at 16:22
  • I did it with colorwheel as in the previous answer. Thanks a lot. – Satinger May 18 '18 at 10:46
3

Judging from the image you've posted, and a very brief read of the description at the link, it looks like the rows represent hues and columns represent saturations. So it looks like the above image is saying that a hue of 0 and a saturation of about 3/4ths of the max is the color with the most occurrences. Usually a hue of 0 is red, so it's probably a fairly bright, fairly pure red in this case.

user1118321
  • 25,567
  • 4
  • 55
  • 86
  • Thank you yes it's x-axis for saturation and y-axis for hues. But how do you tell the color? Is there a function in opencv that can tell the color from histogram? – Satinger May 11 '18 at 13:34
  • Have a look at the [HSV color wheel](https://en.wikipedia.org/wiki/Color_wheel#/media/File:Hsv_color_circle.svg). If I understand the documentation correctly, OpenCV returns values between 0 and 180 (why? I don't know) for the hue. I would expect the hue to be 2 * angle returned. Generally red is at 0° and as you move counterclockwise it moves through yellow at 60°, green at 120°, cyan at 180°, blue at 240°, magenta at 300° and back to red at 360/0°. – user1118321 May 11 '18 at 15:29
  • Got it. Thanks a lot. – Satinger May 18 '18 at 10:45
2

Maybe you need a colormap like this:

(The image is taken from my another answer : Choosing the correct upper and lower HSV boundaries for color detection with`cv::inRange` (OpenCV))

Notice that the Hue domains the color so I scale it 4X. The x axis is H, the y axis is S, while keep V=255.

Then according the maxval position (H-S), lookup the colormap to get the color.


Another example is that:

For this image:

enter image description here

Calculate the H-S hist, log it, threshold to get the domain colors' mask, like this:

enter image description here

Kinght 金
  • 17,681
  • 4
  • 60
  • 74
  • Thank you for this answer. I created a histogram with all three channels and got the max. I can manually check the color, but I can't figure out how to get what you have here. Can you please add the code? – Satinger May 12 '18 at 23:44