Öffnen Sie ein 2D-Histogramm

Ich frage mich, wie man ein 2D-Histogramm einer HSV-Matte in opencv c ++ aufträgt. Mein aktueller Code, der versucht, ihn anzuzeigen, scheitert kläglich. Ich habe mich umgeschaut, wie man Histogramme zeichnet, und alle, die ich gefunden habe, waren diejenigen, die sie als unabhängige 1D-Histogramme grafisch darstellen.

Hier ist meine aktuelle Ausgabe mit der Anzahl der Farbton-Bins von 30 und Sättigungs-Bins von 32:

Hier ist eine weitere Ausgabe, bei der die Anzahl der Farbtonbehälter 7 und die Sättigungsbehälter 5 betragen:

Ich möchte, dass es hier mehr wie das Ergebnis aussieht

http://docs.opencv.org/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.html

Ich merkte auch, wenn ich << Hist.size cout mache, gibt es mir 50×50. Darf ich das verstehen, bedeutet das nur, dass die erste Dimension des Arrays 250 groß ist?

Wie sortiert man das Histogramm von der höchsten zur niedrigsten (oder umgekehrt) Werthäufigkeit? Das ist ein anderes Problem, das ich versuche zu lösen.

Meine derzeitige function ist wie folgt.

void Perform_Hist(Mat& MeanShift, Mat& Pyramid_Result, Mat& BackProj){ Mat HSV, Hist; int histSize[] = {hbins, sbins}; int channels[] = {0, 1}; float hranges[] = {0, 180}; float sranges[] = {0, 256}; const float* ranges[] = {hranges, sranges}; cvtColor(MeanShift, HSV, CV_BGR2HSV); Mat PyrGray = Pyramid_Result.clone(); calcHist(&HSV, 1, channels, Mat(), Hist, 2, histSize, ranges, true, false); normalize(Hist, Hist, 0, 255, NORM_MINMAX, -1, Mat()); invert(Hist, Hist, 1); calcBackProject(&PyrGray, 1, channels, Hist, BackProj, ranges, 1, true); double maxVal = 0; minMaxLoc(Hist, 0, &maxVal, 0, 0); int scale = 10; Mat histImage = Mat::zeros(sbins*scale, hbins*10, CV_8UC3); for(int i = 1; i < hbins * sbins; i++){ line(histImage, Point(hbins*sbins*(i-1), sbins - cvRound(Hist.at(i-1))), Point(hbins*sbins*(i-1), sbins - cvRound(Hist.at(i))), Scalar(255,0,0), 2, 8, 0); } imshow (HISTOGRAM, histImage); } 

   

Meinst du sowas?

HSV-Histogramm als 3D-Graph

  • Es ist HSV-Histogramm als 3D-Grafik angezeigt
  • V wird ignoriert, um zu 3D zu gelangen (sonst wäre es ein 4D Graph …)

Wenn ja, dann geht das so (ich benutze OpenCV nicht, also passen Sie es an Ihre Bedürfnisse an):

  1. Quellbild in HSV konvertieren
  2. Histogramm berechnen, wobei der V-Wert ignoriert wird
    • Alle colors mit den gleichen H, S werden als einzelne Farbe angesehen, egal was das V ist
    • Sie können alle anderen ignorieren, aber der V-Parameter sieht wie die beste aus
  3. Zeichnen Sie das Diagramm

    • erste Ellipse mit dunklerer Farbe (HSV-Basisscheibe)
    • dann für jeden Punkt den entsprechenden Histogrammwert nehmen und vertikale Linie mit hellerer Farbe zeichnen. Die Zeilengröße ist proportional zum Histogrammwert

Hier ist der C ++ Code, mit dem ich das gemacht habe:

 picture pic0,pic1,pic2,zed; int his[65536]; DWORD w; int h,s,v,x,y,z,i,n; double r,a; color c; // compute histogram (ignore v) pic2=pic0; // copy input image pic0 to pic2 pic2.rgb2hsv(); // convert to HSV for (x=0;x<65536;x++) his[x]=0; // clear histogram for (y=0;y>1; // HSV base disc position centers on the bottom y=pic1.ys-100; a=2.0*M_PI*double(h)/256.0; // disc -> x,y r=double(s)/256.0; x+=120.0*r*cos(a); // elipse for 3D ilusion y+= 50.0*r*sin(a); z=-y; if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } x++; if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } y++; if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } x--; if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } y--; w=h+(s< <8); // get histogram index for this color i=((pic1.ys-150)*his[w])/n; c.db[picture::_v]=255; // histogram brighter for (;(i>0)&&(y>0);i--,y--) { if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } x++; if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } y++; if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } x--; if (zed.p[y][x].dd>=z){ pic1.p[y][x]=c; zed.p[y][x].dd=z; } y--; } } pic1.hsv2rgb(); // convert to RGB to see correct colors 
  • Eingabebild ist pic0 (Rose), Ausgabebild ist pic1 (Histogramm)
  • pic2 ist das pic0 , das für die Histogrammberechnung in HSV umgewandelt wurde
  • zed ist der Zed-Puffer für die 3D-Anzeige, die Z-Sortierung vermeidet …

Ich verwende meine eigene Bildklasse für Bilder, also sind einige Mitglieder:

  • xs,ys Größe des Bildes in Pixel
  • p[y][x].dd ist Pixel an der Position (x, y) als 32-Bit-Integer-Typ
  • clear(color) – Löscht das gesamte Bild
  • resize(xs,ys) – passt das Bild an die neue Auflösung an
  • rgb2hsv() und hsv2rgb()hsv2rgb() mal, was es macht 🙂

[edit1] dein 2D Histogramm

Es sieht so aus, als ob Sie in ein 2D-Array eingefärbt sind. Eine Achse ist H und die zweite ist S Sie müssen also den H,S Wert aus der Array-Adresse berechnen. Wenn es linear ist, dann für HSV[i][j] :

  • H=h0+(h1-h0)*i/maxi
  • S=s0+(s1-s0)*j/maxj
  • oder i,j umgekehrt
  • h0,h1,s0,s1 sind die Farbbereiche
  • maxi,maxj sind die Array-Größe

Wie du sehen kannst, wirfst du auch V wie ich ab, also hast du jetzt H,S für jede Zelle im 2D-Histogramm. Wo ist die Wahrscheinlichkeit der Zellwert? Wenn Sie nun ein Bild zeichnen möchten, müssen Sie wissen, wie Sie es ausgeben (als 2D-Grafik, 3D, Mapping, …). Für unsortierte 2D-Graphen zeichnen Sie Graphen, in denen

  • x=i+maj*i
  • y=HSV[i][j]
  • color=(H,S,V=200);

Wenn Sie es sortieren möchten, berechnen Sie einfach die x-Achse anders oder führen Sie eine Schleife in der 2D-Anordnung in Sortierreihenfolge und x nur inkrementieren

[edit2] Aktualisierung des Codes und einiger Bilder

Ich habe den obigen C ++ – Code repariert (falsches Z-Wert-Zeichen, geänderte Z-Puffer-Bedingung und größere Punkte für eine schönere Ausgabe hinzugefügt). Ihre 2D-Array-colors können wie folgt aussehen:

HS Farben

Wo eine Achse / ein Index H , ist das andere S und der Value fest (ich wähle 200). Wenn deine Achsen vertauscht sind, dann spiegele es einfach mit y=x ich denke …

Die Farbsortierung ist eigentlich nur eine Reihenfolge, in der Sie alle colors aus dem Array auswählen. beispielsweise:

 v=200; x=0; for (h=0;h<256;h++) for (s=0;s<256;s++,x++) { y=HSV[h][s]; // here draw line (x,0)->(x,y) by color hsv2rgb(h,s,v); } 

Dies ist der schrittweise Weg. Du kannst x aus H,S berechnen H,S um eine andere Sortierung zu erreichen oder die fors tauschen ( x++ muss in der inneren Schleife sein)

Wenn Sie stattdessen einen RGB-Histogramm-Plot wünschen, siehe:

  • wie man das RGB-Farbhistogramm des Bildes mit dem Ziel c aufträgt