Ask Your Question

Finding Dominant colors in an image in c++

asked 2019-12-06 01:11:01 -0500

it_master gravatar image

updated 2019-12-06 07:09:44 -0500

ojesus gravatar image

I have been scouring the net for quite some time in regards to finding the same answer, but in c++. So far, nothing yielded any usable sample codes or guides in regards to this topic. And the only thing I have found for this subject is through an old forum answer just nearly 2 years ago (See this for reference), but the result from that was still erroneous.

With that being said, I have to ask.

How to find dominant colors in OpenCV in C++?

Edit: I have managed to make the program from the reference work, but all I'm left is a simplified image. It may make things easier, but I'm still looking for a way to find the dominant color in the image. (Akin similar to the resulting cluster color bar displayed in the sample program in this site: OpenCV and Python K-Means Color Clustering

Here is the snippet code I'm currently using for the program:

Mat ocv = resulthsv; //resulthsv is the image made after converting to hsv and masking.

    // convert to float & reshape to a [3 x W*H] Mat 
    //  (so every pixel is on a row of it's own)
Mat data;
ocv.convertTo(data, CV_32F);
data = data.reshape(1,;

// do kmeans
Mat labels, centers;
kmeans(data, 8, labels, TermCriteria(CV_TERMCRIT_ITER, 10, 1.0), 3,
    KMEANS_PP_CENTERS, centers);

// reshape both to a single row of Vec3f pixels:
centers = centers.reshape(3, centers.rows);
data = data.reshape(3, data.rows);

// replace pixel values with their center value:
Vec3f *p = data.ptr<Vec3f>();
for (size_t i = 0; i<data.rows; i++) {
    int center_id =<int>(i);
    p[i] =<Vec3f>(center_id);

// back to 2d, and uchar:
ocv = data.reshape(3, ocv.rows);
ocv.convertTo(ocv, CV_8U);

imshow(windowName, resulthsv); 
imwrite("t1.png", resulthsv);
imshow("Dominant color", ocv);

return 0;

Here is the initial image (after masking):

image description

And here is the image after K-means:

image description

edit retag flag offensive close merge delete


I have managed to make the program from the reference work

please edit your question, and show us !

berak gravatar imageberak ( 2019-12-06 02:31:58 -0500 )edit

I have edited the question.

it_master gravatar imageit_master ( 2019-12-06 02:53:35 -0500 )edit

^^ yea, cute, thanks ;)

can it be that the code is doing "too much" (and that you don't understand, what it does ?)

did you want a visualization of the kmeans colors, not replace them in the image ? (again, once you have those, what do you need to do ?)

berak gravatar imageberak ( 2019-12-06 02:54:21 -0500 )edit

Yeah, that seems to be the case. And I'm just looking for just the 3 most dominant colors in the image, so hopefully it would help. Displaying the most dominant color shown followed by the second and third dominant color.


Like I said, I just needed to display the first photo, then display the next window that would display the most dominant color in a box, followed by the second and third dominant color (or whichever way the output can be displayed)

it_master gravatar imageit_master ( 2019-12-06 02:56:26 -0500 )edit

Displaying the most dominant color

ok, doable ;) and then ? that's not where your program ends, no ?

berak gravatar imageberak ( 2019-12-06 03:01:03 -0500 )edit

After the display of the 3 most dominant colors in the window, that's about it. probably save those colors as images? (that might have been too much to ask), but the main thing is just that. I'm creating a somewhat complex program, and this is just one module of the whole program.

it_master gravatar imageit_master ( 2019-12-06 03:04:46 -0500 )edit

1 answer

Sort by ยป oldest newest most voted

answered 2019-12-06 03:20:12 -0500

berak gravatar image

updated 2019-12-06 06:49:21 -0500

here's something to try, after retrieving the K centers using kmeans() (like above):

Mat showCenters(const Mat &centers , int siz=64) {
    Mat cent = centers.reshape(3, centers.rows);
    // make  a horizontal bar of K color patches:
    Mat draw(siz , siz * cent.rows, cent.type(), Scalar::all(0));
    for (int i=0; i<cent.rows; i++) {
         // set the resp. ROI to that value (just fill it):
         draw( Rect(i * siz, 0, siz, siz)) =<Vec3f>(i,0);
    draw.convertTo(draw, CV_8U);

    // optional visualization:
    imshow("CENTERS", draw);

    //imwrite("centers.png", draw);

    return draw;

image description good luck !

edit flag offensive delete link more



For some reason, I can only see black and white after the code execution.

it_master gravatar imageit_master ( 2019-12-06 03:45:04 -0500 )edit

what is the input range to kmeans ? did you scale it to [0..1] ? (then you might need to scale it back to [0..255] when converting back)

berak gravatar imageberak ( 2019-12-06 03:58:17 -0500 )edit

I think I got it. Thanks a bunch!

Last minor thing, how do I exclude a particular color from the array, for example, a background color black?

it_master gravatar imageit_master ( 2019-12-06 04:11:41 -0500 )edit

some errors corrected in the code above, please take a look

berak gravatar imageberak ( 2019-12-06 05:58:26 -0500 )edit

I still need to know as to how do I exclude a articular color

it_master gravatar imageit_master ( 2019-12-11 04:26:17 -0500 )edit

Question Tools

1 follower


Asked: 2019-12-06 01:11:01 -0500

Seen: 1,905 times

Last updated: Dec 06 '19