梯度向量的直方图分级

时间:2017-11-13 12:35:02

标签: c++ image-processing graphics statistics computer-vision

我正在开发一个项目,它有一个小组件,需要比较图像渐变的分布。假设我已经使用Sobel滤波器计算了x和y方向上的图像梯度,并且对于每个像素具有2矢量。显然,获得幅度和方向是相当微不足道的,如下:

Magnitude and Direction Equations

然而,我不清楚的是如何将这两个组件分成二维直方图,以获得任意数量的二进制数。

我考虑过这些问题(用浏览器编写):

//Assuming normalised magnitudes.
//Histogram dimensions are bins * bins.
int getHistIdx(float mag, float dir, int bins) {
    const int magInt = reinterpret_cast<int>(mag);
    const int dirInt = reinterpret_cast<int>(dir);
    const int magMod = reinterpret_cast<int>(static_cast<float>(1.0));
    const int dirMod = reinterpret_cast<int>(static_cast<float>(TWO_PI));

    const int idxMag = (magInt % magMod) & bins
    const int idxDir = (dirInt % dirMod) & bins;
    return idxMag * bins + idxDir;
}

但是,我怀疑mod操作会引入很多不正确的重叠,即完全不同的渐变放入同一个bin。

非常感谢对这个问题的任何见解。

我想避免使用任何现成的库,因为我希望将此项目尽可能地保持为依赖关系。我还打算在CUDA中实现这一点。

2 个答案:

答案 0 :(得分:0)

我认为你应该将你的箱子安排在一个正方形阵列中,然后通过vx和vy独立地进行bin。

如果您的渐变合理地,即使您只需要先扫描数据以在x和y中累积最小值和最大值,然后均匀地分割渐变。

如果渐变分布非常不均匀,您可能需要先对(例如)vx进行排序,并安排每个bin之间的边界完全均匀地划分值。

中间解决方案可能是获得最小值和最大值忽略(例如)10%最极端值。

答案 1 :(得分:0)

这更像是一个直方图问题?而不是你的一个标签。两件事:

  1. 在2D平原中,两个方向相等的调制2pi实际上是相同的 - 因此调制是有意义的。
  2. 我认为调整规范没有实际或合乎逻辑的理由。
  3. 接下来,您说您想要一个“二维直方图”,但返回一个数字。 2D直方图,以及在您的上下文中有意义的是3D绘图 - 平面是theta / R,2是索引的,而3D轴是“计数”。

    首先建议,返回

    return Pair<int,int>(idxMag,idxDir);
    

    然后您可以制作2D直方图或2个2D直方图。

    关于“垃圾箱数量”

    这是用例依赖的。 需要定义您想要的垃圾箱数量(对于theta和R可能不同)。也许只是一些不变的10箱?也许它应该取决于载体的数量?在任何情况下,您都需要一个接收向量数或向量总数的函数,并返回每个轴的二进制数。这最初可能是一个常数(10个分档),你可以玩它。一旦你决定了垃圾箱的数量:

    确定分档

    1. 对于0<theta<2 pi这样的有界案例,这很容易。假设平坦分布,将间隔平均分成箱数。你的调制实际上很好地处理了这个 - 如果你实际上已经调整了2 * pi,你没有。您仍然需要确定bin边界。
    2. 对于R,这变得更加棘手,因为这是无限的。这里有两个选项,但都依赖于相同的策略 - 选择最大的bin。任意(Say R=10),所以任何比这更长的矢量都放在“超过最大”的bin中。其余部分平均分配(例如,您可以选择其他分配)。另一种选择是使用最长的矢量来确定最大箱的边缘。
    3. 获取索引

      一旦你有了垃圾箱,你需要搜索垃圾箱中当前矢量的幅度/方向。如果bin是表示bin的最小值/最大值(可能是索引)的对,比如在链表中,那么它就像(例如mag):

      bin = histogram.first;
      while ( mag > bin.min ) bin = bin.next;
      magIdx = bin.index;
      

      如果bin没有保存索引,你可以使用一个计数器并在while中增加它。此外,对于幅度,最终箱应该保持“无穷大”或一些大数量作为限制。请注意,这与调制无关,尽管这可以适用于您的方向 - 正如您编码的那样。我不明白这对规范是否有意义。

      尽管如此,你必须考虑一下你想要的东西。在任何情况下,这里的所有“对象”都足以让你自己写,甚至使用小数组。