2015-03-01 10 views
6

Voglio trovare il colore dominante su un'immagine. Per questo, so che dovrei usare l'istogramma dell'immagine. Ma non sono sicuro del formato dell'immagine. Quale di rgb, hsv o immagine grigia, dovrebbe essere usato?Trova il colore dominante su un'immagine

Dopo aver calcolato l'istogramma, dovrei trovare il valore massimo sull'istogramma. Per questo, dovrei trovare sotto il valore massimo binVal per l'immagine hsv? Perché l'immagine del mio risultato contiene solo il colore nero?

float binVal = hist.at<float>(h, s);

EDIT:

Ho provato il codice qui sotto. Disegna l'istogramma h-s. E le mie immagini dei risultati sono qui. Non trovo nulla dopo la soglia binaria. Forse trovo il valore dell'istogramma massimo in modo errato.

enter image description here enter image description here

cvtColor(src, hsv, CV_BGR2HSV); 

// Quantize the hue to 30 levels 
// and the saturation to 32 levels 
int hbins = 20, sbins = 22; 
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); 
int maxIntensity = -100; 
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); 
     if(intensity > maxIntensity) 
      maxIntensity = intensity; 
    } 
} 
std::cout << "max Intensity " << maxVal << std::endl; 
Mat dst; 
cv::threshold(src, dst, maxIntensity, 255, cv::THRESH_BINARY); 

namedWindow("Dest", 1); 
imshow("Dest", dst); 
namedWindow("Source", 1); 
imshow("Source", src); 

namedWindow("H-S Histogram", 1); 
imshow("H-S Histogram", histImg); 

risposta

5

La soluzione

  • Trova HS istogramma
  • trovare il valore di picco H (utilizzando la funzione minmaxLoc)
  • Immagine divisa 3 canali (h, s, v)
  • Applica alla soglia.
  • creare un'immagine dalla fusione a 3 canali
+3

Ti dispiacerebbe postare qualche codice? Grazie –

3

ecco alcuni suggerimenti per iniziare.

  • Tutti i 3 canali in RGB contribuire al colore, in modo che avrebbe dovuto in qualche modo capire dove tre diversi istogrammi sono tutti al massimo. (O la loro somma è massima, o qualsiasi altra cosa.)
  • HSV ha tutte le informazioni sul colore (beh, tonalità) in un canale, quindi devi considerare solo un istogramma.
  • La scala di grigi elimina tutte le informazioni sul colore, quindi è praticamente inutile per il colore di ricerca .

Provare a convertire in HSV, quindi calcolare l'istogramma sul canale H.

Come dici tu, vuoi trovare il valore massimo nell'istogramma. Ma:

  • Si potrebbe prendere in considerazione un intervallo di valori invece di uno solo, dire da 20-40 invece di 30. Prova diverse taglie.
  • Ricordare che la tonalità è circolare, quindi H=0 e H=360 sono gli stessi.
  • Prova tracciare l'istogramma seguendo questo:
    http://docs.opencv.org/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.html
    per vedere se i risultati hanno senso.
  • Se si utilizza una gamma di tonalità e si trova un intervallo massimo, è possibile utilizzare solo la parte centrale dell'intervallo come colore dominante, oppure è possibile trovare la media dei colori all'interno di tale intervallo e usa quello

    Provare. Giocare.

8

In alternativa, è possibile provare un approccio k-means. Calculate k clusters con k ~ 2..5 e prendi il centroide del gruppo più grande come colore dominante.

Il docu pitone di OpenCV ha un illustrated example che ottiene il colore dominante (s) piuttosto bene:

+0

dovrei trovare la più grande area di colore molto velocemente, e la mia immagine è molto grande. Questo metodo è efficiente per questo compito? – zumma

+0

hmm, grazie del tuo consiglio. Non lo uso. – zumma

+0

No, è molto più lento di un semplice istogramma (la versione esatta è anche NP-completa). Ma dal momento che questa attività esegue una forte riduzione della dimensionalità da 'N' pixel fino a un solo colore, è molto probabile che non tenga conto di tutti i pixel, cioè sottocampione dell'immagine prima (indipendente dal metodo che usi per determinare effettivamente un colore dopo). – mbschenkel

Problemi correlati