确定图像中最常出现的颜色(OpenCV和C ++)

时间:2017-10-09 22:30:45

标签: c++ opencv image-processing colors

假设我有以下图片:

enter image description here

我正在寻找的是一种以编程方式确定红色是图片中最常见颜色的方法。

到目前为止,我已经尝试了一些方法,其中包含了各种糟糕到糟糕的结果。我目前的方法是首先减少图像中的颜色。

enter image description here

使用以下代码完成:

Mat samples(src.rows * src.cols, 3, CV_32F);
for( int y = 0; y < src.rows; y++ )
for( int x = 0; x < src.cols; x++ )
for( int z = 0; z < 3; z++)
samples.at<float>(y + x * src.rows, z) = src.at<Vec3b>(y,x)[z];

int clusterCount = 16;
Mat labels;
int attempts = 2;
Mat centers;
kmeans(samples, clusterCount, labels, TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 10000, 0.0001), attempts, KMEANS_PP_CENTERS, centers );

Mat reduced( src.size(), src.type() );
for( int y = 0; y < src.rows; y++ )
for( int x = 0; x < src.cols; x++ )
{
    int cluster_idx = labels.at<int>(y + x * src.rows,0);
    reduced.at<Vec3b>(y,x)[0] = centers.at<float>(cluster_idx, 0);
    reduced.at<Vec3b>(y,x)[1] = centers.at<float>(cluster_idx, 1);
    reduced.at<Vec3b>(y,x)[2] = centers.at<float>(cluster_idx, 2);
}

有一个令人烦恼的问题,它有缩放问题而没有留下权利的一部分,但我现在可以忍受。

接下来,我尝试了一些方法,我希望将颜色映射出来,例如使用直方图。

Mat image_hsv;

cvtColor(src, image_hsv, CV_BGR2HSV);

// Quanta Ratio
int scale = 10;

int hbins = 36, sbins = 25, vbins = 25;
int histSize[] = {hbins, sbins, vbins};

float hranges[] = { 0, 360 };
float sranges[] = { 0, 256 };
float vranges[] = { 0, 256 };

const float* ranges[] = { hranges, sranges, vranges };
MatND hist;

int channels[] = {0, 1, 2};

calcHist( &image_hsv, 1, channels, Mat(), // do not use mask
         hist, 3, histSize, ranges,
         true, // the histogram is uniform
         false );

int maxVal = 0;

int hue = 0;
int saturation = 0;
int value = 0;

for( int h = 0; h < hbins; h++ )
for( int s = 0; s < sbins; s++ )
for( int v = 0; v < vbins; v++ )
{
    int binVal = hist.at<int>(h, s, v);
    if(binVal > maxVal)
    {
        maxVal = binVal;

        hue = h;
        saturation = s;
        value = v;
    }
}

hue = hue * scale * scale; // angle 0 - 360
saturation = saturation * scale; // 0 - 255
value = value * scale; // 0 - 255

问题是,对于此图像,我得到以下值:

  • Hue:240
  • 饱和度:0
  • 价值:0

但是,我期待HSV值接近这个:

  • Hue:356
  • 饱和度:94
  • 价值:58

希望有人可以指出我哪里出错了。

1 个答案:

答案 0 :(得分:0)

这确实是计算机图形学中的经典问题。只是从字面上找到最常见的颜色直方图不是一个好主意,令人惊讶的是你可能会发现它是黄色/绿色而不是红色的阴影,因为&#34; red&#34;包含变体,几乎不会落入相同的直方图箱中。

适当的算法基于最小二乘法。你需要找到一个平方和#34;距离和#34;是最小的。您可以将方形距离定义为dr ^ 2 + dg ^ 2 + db ^ 2(r / b / g代表红色/绿色/蓝色分量),或者您可以使用权重来反映对这些组件的不同灵敏度。您也可以在不同的基础上代表它(即yuv等)

如果您在实施最小二乘方面需要帮助,请写下评论。

<强>更新

在你的情况下,最小二乘的解决方案只是直方图给出的权重的平均值水平。

result = sum(n * hist [n])/ sum(hist [n])。

请注意,此公式适用于每个颜色分量,即它们是独立的。