opencv绘制2d直方图 [英] opencv drawing a 2d histogram

查看:120
本文介绍了opencv绘制2d直方图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道如何在opencv c ++中绘制HSV Mat的二维直方图。我当前试图显示它的代码失败了。我已经四处查看如何绘制直方图,我发现的所有直方图都是将它们绘制为独立的1d直方图。



这是我当前输出的数字hue bins为30,饱和度为32:





这是另一个输出,其中色调分箱数为7,饱和分箱数为5:





我希望它看起来更像是这里的结果





I'm wondering how to plot a 2d histogram of an HSV Mat in opencv c++. My current code attempting to display it fails miserably. I've looked around on how to plot histograms and all the ones I've found were those plotting them as independent 1d histograms.

Here's my current output with the number of hue bins being 30 and saturation bins being 32:

Here's another output with the number of hue bins being 7 and saturaation bins being 5:

I would like it to look more like the result here

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

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

Also, how does one sort the histogram from highest to lowest (or vice versa) value frequency? That is another problem I am 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);
}

解决方案

Did you mean something like this?

  • 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:

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:

这篇关于opencv绘制2d直方图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆