【问题标题】:opencv drawing a 2d histogramopencv绘制二维直方图
【发布时间】:2015-05-29 18:16:24
【问题描述】:

我想知道如何在 opencv c++ 中绘制 HSV Mat 的二维直方图。我当前试图显示它的代码惨遭失败。我环顾四周,了解如何绘制直方图,我发现的所有方法都是将它们绘制为独立的一维直方图。

这是我当前的输出,色调箱数为 30,饱和度箱数为 32:

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

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

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

我也注意到每当我做 cout

另外,如何从最高到最低(反之亦然)值频率对直方图进行排序?这是我试图解决的另一个问题。

我目前的功能如下。

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

【问题讨论】:

  • 什么是二维直方图?直方图是图像(或具有任何维度的任何数据集)中每种颜色(或任何其他参数)的概率(或像素数),因此绘图是二维图 x 轴是颜色(值、代码、索引...)和 y轴是概率。所以你的意思是二维直方图,或者你想为每个图像片段(如网格)制作直方图?并以某种方式像 3D 图一样绘制直方图? .... 顺便提一句。直方图输出通常是一维数组而不是图像...
  • 您也不能按频率对颜色进行排序,因为颜色不是光频率(某些频率的光有颜色但向后不起作用),因此您可以按色调排序。如果您标准化颜色强度(值 = 1),那么您可以绘制直方图的 3D 图基 xy 平面是 HSV 色环,Z 是该颜色的概率......如果没有标准化,您将需要 4D 图......对于这样地块类型
  • 这确实是一个二维直方图,我应该清楚这一点。我的错!另外,我将如何按色调排序?我也可以按饱和度排序以跟随每种色调吗?
  • 您可以对直方图进行排序、映射、包装您喜欢的方式,例如查看我的答案...所以这实际上取决于您要输出的内容和维度...。跨度>
  • 我真的很想对它进行排序,以便对直方图中最高的色调和饱和度进行排序并相互跟随。我在 opencv 中尝试了 sort() 函数并尝试了 sort(hist, hist, by rows) 和 sort(hist, hist, by columns) 但不幸的是它似乎没有那么简单。

标签: opencv image-processing histogram


【解决方案1】:

你的意思是这样的吗?

  • 是 HSV 直方图,显示为 3D 图
  • V 被忽略以进入 3D(否则它将是 4D 图......)

如果是,那么这是怎么做的(我不使用 OpenCV,所以根据您的需要调整它):

  1. 将源图像转换为 HSV
  2. 计算直方图忽略 V 值
    • 无论 V 是什么,具有相同 H、S 的所有颜色都被视为单色
    • 您可以忽略任何其他参数,但 V 参数似乎是最佳选择
  3. 画图

    • 首先绘制颜色较深的椭圆(HSV 基盘)
    • 然后为每个点获取相应的直方图值并绘制颜色更亮的垂直线。线条大小与直方图值成正比

这是我使用的 C++ 代码:

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
  • 输入图像为pic0(玫瑰),输出图像为pic1(直方图)
  • pic2 是将 pic0 转换为 HSV 以进行直方图计算
  • zed 是用于 3D 显示的 Zed 缓冲区,避免 Z 排序 ...

我将自己的图片类用于图像,所以一些成员是:

  • xs,ys 图像大小(以像素为单位)
  • p[y][x].dd 是 (x,y) 位置的像素,为 32 位整数类型
  • clear(color) - 清除整个图像
  • resize(xs,ys) - 将图像调整为新分辨率
  • rgb2hsv()hsv2rgb() ...猜猜它的作用:)

[edit1]您的二维直方图

看起来您已将颜色编码为二维数组。一个轴是H,第二个轴是S。所以你需要从数组地址计算H,S 值。如果它是线性的,那么对于HSV[i][j]

  • H=h0+(h1-h0)*i/maxi
  • S=s0+(s1-s0)*j/maxj
  • i,j 反转
  • h0,h1,s0,s1 是颜色范围
  • maxi,maxj 是数组大小

如您所见,您也像我一样丢弃了V,所以现在您在直方图二维数组中的每个单元格都有H,S。其中概率是单元格值。现在,如果您想绘制图像,您需要知道如何输出它(作为 2D 图形、3D、映射......)。对于未排序的 2D 图形绘制图形,其中:

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

如果你想对它进行排序,那么只需以不同的方式计算 x 轴或按排序顺序循环二维数组,x 只是递增

[edit2] 更新代码和部分图片

我已经修复了上面的 C++ 代码(错误的 Z 值符号,更改了 Z 缓冲区条件并添加了更大的点以获得更好的输出)。您的二维数组颜色可以是这样的:

其中一个轴/索引是H,另一个SValue 是固定的(我选择200)。如果您的轴被交换,那么只需通过y=x 镜像它我认为...

颜色排序实际上只是从数组中选择所有颜色的顺序。例如:

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

这是递增的方式。您可以从H,S 计算x,而不是实现不同的排序或交换forsx++ 必须在内部循环中)

如果您想要 RGB 直方图,请参阅:

【讨论】:

  • @rayryeng thx,但如果添加一些更好的缩放比例,比如丢弃最常见的背景颜色,效果会更好。点也应该超过 1 个像素以覆盖孔,并且可能是对数 y 会更好......
  • 当你说“如果你想对它进行排序,那么只需以不同的方式计算 x 轴”是 cv::sort(Hist, Hist, CV_SORT_DESCENDING);你的意思是? docs.opencv.org/modules/core/doc/operations_on_arrays.html#sort 还是我应该多次使用 stackoverflow.com/questions/17831753/sorting-cvmat-in-opencv?编辑:我一直很好的结果。但是,它仍然有点偏离。 i.imgur.com/WElGR4l.pngi.imgur.com/fmlivjo.png
  • @Zypps987 你不能通过该函数对数组进行排序(除非你也有颜色信息)在这种情况下排序只是一种排序方式/顺序如何从二维数组中选择单元格并呈现他们...不,我在 CV 领域不活跃(我做过一些商业项目,但我不是该领域的专家)您链接的输出图像不是直方图...直方图对您的源图像没有视觉参考过滤/转换图像而不是直方图
  • 我使用了 Luv 的倒置 2d 直方图来抑制背景并增强前景(或者至少也尝试过......)。这是一篇简短的论文,但输出图像可能会清楚地说明我想要做什么。我还需要在opencv中实现或找到一个可以计算Mat内欧几里得距离的函数。 breckon.eu/toby/publications/papers/sokalski10uavsalient.pdf
  • i.imgur.com/jD6FQUb.png 到目前为止我只使用 hsv 的色调(现在是一维直方图)得到的结果。我在想我现在应该只对前 2-3 个 bin 进行排序......但它仍然出现反转,黑色被抑制,白色被增强。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-12
  • 1970-01-01
  • 2021-10-13
相关资源
最近更新 更多