我正在开发一个项目,它有一个小组件,需要比较图像渐变的分布。假设我已经使用Sobel滤波器计算了x和y方向上的图像梯度,并且对于每个像素具有2矢量。显然,获得幅度和方向是相当微不足道的,如下:
然而,我不清楚的是如何将这两个组件分成二维直方图,以获得任意数量的二进制数。
我考虑过这些问题(用浏览器编写):
//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中实现这一点。
答案 0 :(得分:0)
我认为你应该将你的箱子安排在一个正方形阵列中,然后通过vx和vy独立地进行bin。
如果您的渐变合理地,即使您只需要先扫描数据以在x和y中累积最小值和最大值,然后均匀地分割渐变。
如果渐变分布非常不均匀,您可能需要先对(例如)vx进行排序,并安排每个bin之间的边界完全均匀地划分值。
中间解决方案可能是获得最小值和最大值忽略(例如)10%最极端值。
答案 1 :(得分:0)
这更像是一个直方图问题?而不是你的一个标签。两件事:
接下来,您说您想要一个“二维直方图”,但返回一个数字。 2D直方图,以及在您的上下文中有意义的是3D绘图 - 平面是theta / R,2是索引的,而3D轴是“计数”。
首先建议,返回
return Pair<int,int>(idxMag,idxDir);
然后您可以制作2D直方图或2个2D直方图。
关于“垃圾箱数量”
这是用例依赖的。 您需要定义您想要的垃圾箱数量(对于theta和R可能不同)。也许只是一些不变的10箱?也许它应该取决于载体的数量?在任何情况下,您都需要一个接收向量数或向量总数的函数,并返回每个轴的二进制数。这最初可能是一个常数(10个分档),你可以玩它。一旦你决定了垃圾箱的数量:
确定分档
0<theta<2 pi
这样的有界案例,这很容易。假设平坦分布,将间隔平均分成箱数。你的调制实际上很好地处理了这个 - 如果你实际上已经调整了2 * pi,你没有。您仍然需要确定bin边界。R
,这变得更加棘手,因为这是无限的。这里有两个选项,但都依赖于相同的策略 - 选择最大的bin。任意(Say R=10
),所以任何比这更长的矢量都放在“超过最大”的bin中。其余部分平均分配(例如,您可以选择其他分配)。另一种选择是使用最长的矢量来确定最大箱的边缘。获取索引
一旦你有了垃圾箱,你需要搜索垃圾箱中当前矢量的幅度/方向。如果bin是表示bin的最小值/最大值(可能是索引)的对,比如在链表中,那么它就像(例如mag):
bin = histogram.first;
while ( mag > bin.min ) bin = bin.next;
magIdx = bin.index;
如果bin没有保存索引,你可以使用一个计数器并在while中增加它。此外,对于幅度,最终箱应该保持“无穷大”或一些大数量作为限制。请注意,这与调制无关,尽管这可以适用于您的方向 - 正如您编码的那样。我不明白这对规范是否有意义。
尽管如此,你必须考虑一下你想要的东西。在任何情况下,这里的所有“对象”都足以让你自己写,甚至使用小数组。