opencv drawing a 2d histogram

Did you mean something like this?

HSV histogram as 3D graph

  • it is HSV histogram showed as 3D graph
  • V is ignored to get to 3D (otherwise it would be 4D graph …)

if yes then this is how to do it (I do not use OpenCV so adjust it to your needs):

  1. convert source image to HSV
  2. compute histogram ignoring V value
    • all colors with the same H,S are considered as single color no matter what the V is
    • you can ignore any other but the V parameter looks like the best choice
  3. draw the graph

    • first draw ellipse with darker color (HSV base disc)
    • then for each dot take the corresponding histogram value and draw vertical line with brighter color. Line size is proportional to the histogram value

Here is the C++ code I did this with:

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 is pic0 (rose), output image is pic1 (histogram graph)
  • pic2 is the pic0 converted to HSV for histogram computation
  • zed is the Zed buffer for 3D display avoiding Z sorting …

I use my own picture class for images so some members are:

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

[edit1] your 2D histogram

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

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

As you can see you also discard V like me so now you have H,S for each cell in histogram 2D array. Where probability is the cell value. Now if you want to draw an image you need to know how to output this (as a 2D graph, 3D, mapping,…). For unsorted 2D graph draw graph where:

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

If you want to sort it then just compute the x axis differently or loop the 2D array in sort order and x just increment

[edit2] update of code and some images

I have repaired the C++ code above (wrong Z value sign, changed Z buffer condition and added bigger points for nicer output). Your 2D array colors can be as this:

HS colors

Where one axis/index is H, the other S and Value is fixed (I choose 200). If your axises are swapped then just mirror it by y=x I think …

The color sorting is really just an order in which you pick all the colors from array. for example:

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 the incrementing way. You can compute x from H,S instead to achieve different sorting or swap the fors (x++ must be in the inner loop)

If you want RGB histogram plot instead see:

Leave a Comment