2017-10-09 70 views
0

中最頻繁出現的顏色比方說,我有如下形象:判斷一個圖像(OpenCV的&C++)

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 

的問題是,對於這個圖像I得到以下值:

  • 色調:240
  • 飽和度:0
  • 值:0

然而,我我期待的HSV值更接近這個:

  • 色調:356
  • 飽和度:94
  • 值:58

希望有人能指出我哪裏錯了。

+0

懶得分析你的代碼,但只是一個提示測試你正確處理你的圖像像素格式?我敢打賭,你得到RGB並將其作爲BGR處理,反之亦然,因爲色調240是藍色而不是紅色(我習慣於GDI/Canvas通常對某些像素格式的原始圖像數據的反轉順序)但S ,V設置爲零確實很奇怪。也請看看這個:[HSV直方圖](https://stackoverflow.com/a/29286584/2521214) – Spektre

+0

只是好奇,如何計算顏色直方圖使用[calcHist](https://docs.opencv.org /2.4/modules/imgproc/doc/histograms.html#calchist)並找到高峯?當然,不是HSV值問題的答案。 calcHist將比kmeans快得多。 – dhanushka

+0

@dhanushka速度取決於顏色直方圖的實現,數量等等......所以它可能也不一定比具有相同精度的k-means更快。但是,我也會使用直方圖,這就是爲什麼我建議在以前的評論中的鏈接,因爲有我的C++實現,即RGB - > HSV轉換,計算和渲染HSV直方圖(無openCV) – Spektre

回答

0

這確實是計算機圖形學中的一個經典問題。只是從字面上直接找到最常見的顏色和直方圖並不是一個好主意,令人驚訝的是,您可能會發現它是黃色/綠色的陰影而不是紅色,因爲「紅色」的值包含變化並且幾乎不會落入相同的直方圖箱。

適當的算法是基於最小二乘法。你需要找到顏色的平方「距離」是最小的。您可以將您的平方距離定義爲dr^2 + dg^2 + db^2(r/b/g表示紅色/綠色/藍色分量),或者您可以使用權重來反映對這些分量的不同敏感度。您也可以用不同的基數表示(如yuv等)

如果您需要實施最小二乘法的幫助,請在評論中寫下。

更新:

你的情況最小二乘的解決方案只是平均值水平與直方圖給出的權重。

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

請注意,該公式適用於每種顏色成分,即它們是獨立的。