在c ++中计算直方图的梯度

时间:2009-12-29 10:47:58

标签: c++ gradient histogram

我计算了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 ++解决它,我可以帮助我。

感谢您的建议 马克

3 个答案:

答案 0 :(得分:3)

我认为您可以使用图像边界检测中使用的相同方法(这是一个渐变微积分)来计算渐变。如果直方图在矢量中,则可以将梯度的近似值计算为*:

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

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

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

<强>被修改

其他运营商可能会强调小差异(小梯度将更加强调)。 Roberts算法源自导数演算:

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

delta无限地趋于0(为了避免0除法),但绝不为零。在计算机的存储器中,这是不可能的,我们可以得到的最小值为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]

答案 1 :(得分:2)

  1. 取一些方形纸并画上你的直方图。通过直方图的0,0点绘制垂直和水平轴。

  2. 采取直边,并在您感兴趣的每个点旋转直边,直到它符合您对该点的渐变的想法。最重要的是,你这样做,你的梯度定义是你想要的。

  3. 一旦直边处于该角度,您希望在该角度画一条线。

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

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

  6. 现在,将此转换为代码非常简单,除了步骤2.您必须定义用于确定直方图上任何点的渐变的标准。简单的选择包括:

    a)在每个点,设置你的直边穿过该点,然后是右边的下一个;

    b)在每个点,设置你的直边通过点和​​左边的下一个点;

    c)在每个点,设置你的直边以通过左边的点和右边的点。

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

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

答案 2 :(得分:2)

这里有两种方法:

  1. 衍生物的离散近似
  2. 采用拟合函数的实数导数
  3. 第一种情况中尝试:

    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 suggested不同,这个定义是对称的。它是否重要取决于你的用例。)

    第二种情况中,为数据[*]拟合spline,并在样条库中询问您想要的点的衍生物。

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


    最后,如果您的数据有噪音,您可以在进行斜率检测之前将其平滑。那就是你避免追逐噪音,只看大规模的斜坡。