1

我计算了 3D 灰度图像的直方图(一个简单的 1d 数组)。现在我想计算这个直方图在每个点的梯度。所以这实际上意味着我必须在某些点计算一维函数的梯度。但是我没有功能。那么如何用具体的 x 和 y 值来计算呢?

为简单起见,您能否在示例直方图上向我解释这一点 - 例如使用以下值(x 是强度,y 是这种强度的频率):

x1 = 1; y1 = 3

x2 = 2; y2 = 6

x3 = 3; y3 = 8

x4 = 4; y4 = 5

x5 = 5; y5 = 9

x6 = 6; y6 = 12

x7 = 7; y7 = 5

x8 = 8; y8 = 3

x9 = 9; y9 = 5

x10 = 10;y10 = 2

我知道这也是一个数学问题,但由于我需要用 C++ 解决它,我虽然你可以在这里帮助我。

谢谢你的建议马克

4

3 回答 3

3

我认为您可以使用与图像边界检测中使用的相同方法(这是一种梯度演算)来计算梯度。如果您的直方图在一个向量中,您可以计算梯度的近似值*:

for each point in the histogram compute 
     gradient[x] = (hist[x+1] - hist[x])

这是一种非常简单的方法,但我不确定是否最准确。

  • 近似值,因为您使用的是离散数据而不是连续数据

编辑

其他运算符可能会强调小的差异(小梯度将变得更加强调)。罗伯茨算法源自导数:

lim delta -> 0 = f(x + delta) - f(x) / delta

delta 无限趋向于 0(为了避免 0 除法)但绝不为零。在计算机的内存中这是不可能的,我们可以得到的最小 delta 是 1(因为 1 是图像(或直方图)中点到点的最小距离)。

替代

lim delta -> 0 to lim delta -> 1

我们得到

f(x + 1) - f(x) / 1 = f(x + 1) - f(x) => vet[x+1] - vet[x]
于 2009-12-29T11:36:48.927 回答
2
  1. 拿一些方格纸,在上面画出你的直方图。还通过直方图的 0,0 点绘制垂直轴和水平轴。

  2. 取一条直尺,在您感兴趣的每个点旋转直尺,直到它与您对该点的梯度的想法一致。这样做是最重要的,你对渐变的定义就是你想要的。

  3. 一旦直边处于您想要的角度,以该角度绘制一条线。

  4. 从刚刚画的直线上的任意 2 个点垂下垂线。如果您选择的 2 个点之间的水平距离约为直方图宽度的 25% 或更多,则执行以下步骤会更容易。从相同的 2 点绘制水平线与直方图的垂直轴相交。

  5. 您的线现在定义了 x 距离和 y 距离,即水平/垂直(分别)轴的长度,由它们与垂线/水平线的交点标出。您想要的渐变是 y 距离除以 x 距离。

现在,除了第 2 步之外,将其转换为代码非常简单。您必须定义用于确定直方图上任意点的梯度的标准是什么。简单的选择包括:

a) 在每一点,放下你的直尺以通过该点,下一个在其右侧;

b) 在每一点,放下你的直尺以穿过该点,下一个在它的左边;

c) 在每一点,放下你的直尺,穿过左边的点和右边的点。

您可能想要研究更复杂的选择,例如通过直方图上的多个点拟合曲线(例如二次或高阶多项式)并使用其导数来表示梯度。

在您理解纸上的问题之前,请避免使用 C++ 或其他任何方式进行编码。一旦你理解了它,编码应该是微不足道的。

于 2009-12-29T11:08:22.410 回答
2

这里通常有两种方法:

  1. 导数的离散近似
  2. 取拟合函数的实导数

在第一种情况下尝试:

g = (y_(i+1) - y_(i-1))/2*dx

在除末端之外的所有点,或其中之一

g_left-end  = (y_(i+1) - y_i)/dx
g_right-end = (y_i - y_(i-1))/dx

其中dx是 x 点之间的间距。(与Andres 建议的同样正确的定义不同,这个定义是对称的。它是否重要取决于您的用例。)

第二种情况下,将样条曲线拟合到您的数据 [*],并在您想要的点询问样条曲线库的导数。

[*] 使用图书馆!除非这是一个学习项目,否则不要自己实施。我会使用ROOT因为我已经在我的机器上安装了它,但它是一个非常重的包,只是为了得到一个样条......


最后,如果您的数据有噪声,您可能希望在进行斜率检测之前对其进行平滑处理。那是您避免追逐噪音,而只看大型斜坡。

于 2009-12-29T17:22:29.473 回答