Opencv draws a 2d histogram

I am wondering how to build a 2d histogram of HSV matrix in opencv C ++. My current code trying to display it fails. I looked around how to build histograms, and all I found was that they displayed them as independent 1d histograms.

Here my current output with 30 shades buffers and saturated bunkers is 32:

Here is another output with the number of shade buffers equal to 7, and saturation bins 5:

I would like it to be more like the result here

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

I also noticed when I do cout <Hist.size it gives me 50x50. I have to understand what just means that the first dimension of the array is 250?

In addition, how to sort the histogram from maximum to low (or vice versa) frequency? This is another problem I'm trying to solve.

My current function is as follows.

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<float>(i-1))), Point(hbins*sbins*(i-1), sbins - cvRound(Hist.at<float>(i))), Scalar(255,0,0), 2, 8, 0); } imshow (HISTOGRAM, histImage); } 
+2
source share
1 answer

Did you mean something like this?

HSV histogram as 3D graph

  • HSV histogram shown as 3D
  • V ignored to get to 3D (otherwise it will be a 4D chart ...)

, if yes, then how to do it (I do not use OpenCV, so configure it to your needs):

  • convert source image to hsv
  • calculate a histogram ignoring the value of V
    • all colors with the same H, S are treated as one color no matter what V
    • you can ignore any other, but parameter V looks like the best choice
  • draw a graph

    • first draw an ellipse with a darker color (basic HSV disk)
    • then for each point, take the corresponding histogram value and draw a vertical line with a brighter color. The line size is proportional to the histogram value.

Here is the C ++ code I made using:

 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<pic2.ys;y++) // compute it for (x=0;x<pic2.xs;x++) { c=pic2.p[y][x]; h=c.db[picture::_h]; s=c.db[picture::_s]; w=h+(s<<8); // form 16 bit number from 24bit HSV color his[w]++; // update color usage count ... } for (n=0,x=0;x<65536;x++) if (n<his[x]) n=his[x]; // max probability // draw the colored HSV base plane and histogram zed =pic1; zed .clear(999); // zed buffer for 3D pic1.clear(0); // image of histogram for (h=0;h<255;h++) for (s=0;s<255;s++) { c.db[picture::_h]=h; c.db[picture::_s]=s; c.db[picture::_v]=100; // HSV base darker c.db[picture::_a]=0; x=pic1.xs>>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 
  • input image pic0 (rose), output image pic1 (bar graph)
  • pic2 is pic0 converted to HSV for histogram calculation
  • zed is the Zed buffer for the 3D display, eliminating the sorting of Z ...

I use my own image class for images, so some members:

  • xs,ys image size in pixels
  • p[y][x].dd - pixel at position (x, y) as a 32-bit integer type
  • clear(color) - clears the entire image
  • resize(xs,ys) - resize the image to a new resolution
  • rgb2hsv() and hsv2rgb() ... guess what it does :)

[edit1] your two-dimensional histogram

It looks like you have a color-coded 2D array. One axis is H and the second is S Therefore, you need to calculate the value of H,S from the address of the array. If it is linear, then for HSV[i][j] :

  • H=h0+(h1-h0)*i/maxi
  • S=s0+(s1-s0)*j/maxj
  • or i,j canceled
  • h0,h1,s0,s1 - color ranges
  • maxi,maxj - array size

As you can see, you also drop V as I do, so now you have H,S for each cell in the 2D histogram array. Where probability is the value of the cell. Now, if you want to draw an image, you need to know how to display it (as a 2D graph, 3D, display, ...). For unsorted graphics drawing 2D graphics, where:

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

If you want to sort it, just calculate the x axis differently or loop the 2D array in sort order and x just increase

[edit2] updating code and some images

I restored the C ++ code above (the wrong sign of the Z value, changed the state of the Z-buffer and added more points for a more pleasant output). The colors of the 2D array can be as follows:

HS colors

If one axis / index is H , the remaining S and Value fixed (I select 200). If your axes exchange, then just flip it to y=x , I think ...

Sorting colors is just the order in which you select all the colors from an array. eg:

 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); } 

This is an incremental path. You can compute x from H,S instead to achieve different sorting or fors replacement ( x++ should be in the inner loop)

If you want a graph of the RGB histogram, look:

+8
source

Source: https://habr.com/ru/post/1234949/


All Articles