【发布时间】:2018-03-21 05:20:00
【问题描述】:
假设我有以下图片:
我正在寻找一种以编程方式确定红色是图片中最常见颜色的方法。
到目前为止,我已经尝试了几种方法,但结果很差,很糟糕。我目前的做法是先减少图像中的颜色。
这是通过以下代码完成的:
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
问题是,对于这张图片,我得到以下值:
- 色相:240
- 饱和度:0
- 值:0
但是,我希望 HSV 值更接近这个:
- 色相:356
- 饱和度:94
- 价值:58
希望有人能指出我哪里出错了。
【问题讨论】:
-
懒得分析您的代码,但只是提示您测试您是否正确处理图像像素格式?我敢打赌你得到 RGB 并将其作为 BGR 处理,反之亦然,因为色调 240 是蓝色而不是红色(我习惯于 GDI/Canvas 通常具有与某些像素格式的原始图像数据相反的通道顺序)但是 S ,V 设置为零确实很奇怪。也看看这个:HSV histogram
-
只是好奇,如何使用calcHist 计算颜色直方图并找到峰值?当然,不是用 HSV 值来回答你的问题。 calcHist 将比 kmeans 快得多。
-
@dhanushka 速度取决于颜色直方图的实现、箱数等......因此它可能不一定比具有相同精度的 k-means 快。但是是的,我也会使用直方图,这就是为什么我建议在之前的评论中使用链接,因为我的 C++ 实现可以进行 RGB -> HSV 转换、计算和渲染 HSV 直方图(没有 openCV)
标签: c++ opencv image-processing colors