【问题标题】:How to mathematically define a noisy contour? [closed]如何在数学上定义嘈杂的轮廓? [关闭]
【发布时间】:2019-06-05 21:06:34
【问题描述】:

看下图:

如您所见,某些区域非常嘈杂(非常锯齿状的边缘,有很多突然的变化)

我想从图像中消除这些区域,但要做到这一点,我需要能够确定这种“噪声”的含义。

我曾考虑测量连续轮廓点的角度变化,并用它来确定某物是否有噪声,但我不确定这是一种稳健的噪声区域检测。

有人对如何在数学上定义这些区域有建议吗?

【问题讨论】:

  • 分形维数可能有点矫枉过正。综合曲率?
  • 为了使您对角度变化的测量有意义,在比较图像的各个部分时,它们需要相对于固定大小的范围。我在下面添加了关于如何处理此问题的建议。
  • 最简单的粗略检查可能是检查周长与面积的比率。更好的方法是顺时针绕过轮廓,并将从一个点到下一个点的(绝对)角度相加。轮廓上高度变化的角度将产生非常大的绝对角度总和。但是,这对轮廓的大小并不可靠,因此您可能希望在划分时考虑周长或面积。这基本上是安德拉斯建议采用综合曲率的穷人版本。编辑:我没有意识到您在问题本身中发布了这个想法。
  • 你有没有白色轮廓的图像吗?分割程序不会生成粗轮廓(或根本不生成轮廓),它​​通常只是一个可视化工具。火焰石的答案似乎可以完成这项工作,但他根本无法获得独立的轮廓,所以结果很糟糕。

标签: python algorithm opencv math image-processing


【解决方案1】:

你可以试试这个:

  1. 将图像矩阵分割成完全可迭代的比例。

  2. 对于每个迭代空间,将白色像素拟合到空间中的线性回归。

  3. 存储每个部分的线性模型中的 RSME(均方根误差)。

  4. 计算所有迭代部分的标准差。

  5. 选择描述可容忍“噪声”阈值的标准差。

您需要尝试不同的“迭代大小”来找到最佳的噪声描述符。

如果你想比较图片之间的相对噪声水平,这个问题最好使用卷积机器学习设计来解决。

【讨论】:

  • 我不想用数学方法描述图像,我想用数学方法描述噪声部分。即把一个这样的区域想象成一个多边形。我怎么知道多边形有噪声?
  • 我已经更新了我的答案。如果您需要帮助了解如何实施任何步骤,请告诉我。
  • 我对 NN 有私仇
  • 你不需要为此使用神经网络,一个简单的线性内核就是你想要的。
  • 只是回归。
【解决方案2】:

我试图通过分析它们的曲率值来定义嘈杂的轮廓。 以下是实现细节:

1. Threshold the gray scale image using fixed threshold value of 250 to retrieve the white edges

2.Extract the contours in the threshold image

3.Calculate the curvature values along each contour

4.From the curvature data we can observer that the noisy contour's curvature values has higher variance value, therefore we can classify such
noisy contours using certain threshold value.

以下是上述步骤的 Python 实现。 这里我使用定义为here的笛卡尔坐标系的曲率估计方程@

#function to calculate the curvature values along a given contour and classify noisy contour
def contourCurvature(contourspt):
    #curvature value estimation using symmetric derivation
    # at points (i-step), i, (i+step)
    step = 5
    s1 = 2*step
    s2 = np.power(s1, 2)
    if len(contourspt) < s1:
        return False

    kp = []
    l = len(contourspt)
    ct = 0
    for i in range(l):
        p = i - step
        pp = i - s1
        if p < 0:
            p += l
            pp += l
        elif pp < 0:
            pp += l
        n = (i + step) % l
        nn = (i + s1) % l

        posPrev = contourspt[p][0]
        posPrevP = contourspt[pp][0]
        posCurr = contourspt[i][0]
        posNext = contourspt[n][0]
        posNextN = contourspt[nn][0]
        #first order derivative at point i w.r.t. x and y
        f1stderX = (posNext[0] - posPrev[0])/s1
        f1stderY = (posNext[1] - posPrev[1])/s1
        # second order derivative at point i w.r.t. x and y
        f2ndderX = (posNextN[0] - 2*posCurr[0] + posPrevP[0])/s2
        f2ndderY = (posNextN[1] - 2*posCurr[1] + posPrevP[1])/s2

        if f1stderX != 0 or f1stderY != 0:
            a = f2ndderX*f1stderY - f2ndderY*f1stderX
            b = np.power(np.power(f1stderX,2) + np.power(f1stderY,2), 3/2)
            curvature2D = float("{0:.5f}".format(a/b))

            #Check if contour contains any regular section of more than 
            # 20 percent of the contour length
            if np.abs(curvature2D) < 0.005:
                ct += 1
                if ct > l*0.2:
                    return True
            else:
                ct = 0
            if np.abs(curvature2D) < 0.0001 or np.abs(curvature2D) > 5: 
                curvature2D = 0 #local noise suppression
            #store the curvature values in a list
            kp.append(np.abs(curvature2D))

    # check the variance of curvatures values along the contour
    var = np.var(kp, ddof=1)
    if var < 0.01:
        print('Variance: ',var)
        return True
    return False


def main():
    gray = cv2.imread('D:/cnt.png', 0)
    #threshold the image using 250 as threhold value
    ret,th1 = cv2.threshold(gray,250,255,cv2.THRESH_BINARY)
    img1,contours,hierarchy = cv2.findContours(th1, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    img = cv2.cvtColor(gray, cv2.COLOR_GRAY2RGB)
    #iterate through each contour
    for cnt in contours:
        if(len(cnt)>50): #neglect the small contours as noise
            flag = contourCurvature(cnt)
            if(flag):
                cv2.drawContours(img,[cnt],0,(0,0,255),3)

    cv2.imshow('Final image', img)
    cv2.waitKey(0)

if __name__ == "__main__":
    main()

这是仅显示非噪声(真实)轮廓的输出图像。

虽然最终输出的图像遗漏了一些真实的轮廓,但这里欢迎任何其他改进此算法的想法。

【讨论】:

  • mm 这很奇怪,因为您没有检测到视觉上噪声较小的轮廓。我会说提取步骤是错误的。您应该识别独立的纯色区域并从此类纯色周围的相邻白色像素中获取轮廓。也就是说,OP 实际上可能具有轮廓,因为大多数情况下,这些白线来自可视化,因为分割过程不会在 blob 之间添加轮廓
  • 我在这里遇到的挑战是,一些轮廓的大部分长度都包含平滑点,但在某些区域它们由非常不规则的部分组成,因此这种不规则部分加起来方差值会使噪声总轮廓。因此,如果我们对具有长度超过某个阈值的规则曲率值部分的轮廓添加检查,然后将它们检测为真实轮廓。
  • 我要做的不是标记最大值,而是整合和规范化。计算轮廓中的所有角度,将它们加在一起并划分点数。然后在那里设置一个启发式阈值,但这应该有效
  • 是的,这似乎是一种可行的方法,我会尝试的。刚才我更新了评论中提到的答案。
  • 能否请您多评论一下您的解决方案?它似乎是在正确的方向(现在测试它),但有些部分对我来说并不完全清楚。提前致谢。
【解决方案3】:

您可以首先使用 Douglas-Peucker 用多边形曲线近似每个轮廓(或其中的一部分),以便最大误差是全局有界的,然后也许考虑

  1. 将近似值的周长与原始曲线的周长进行比较
  2. 计算原始曲线上每个点到近似多边形曲线的距离,然后计算该数据集的标准差。

或者您可以对同一轮廓进行粗略和精细的多边形近似,并计算每个粗略近似长度的精细近似中的段数。

【讨论】:

    猜你喜欢
    • 2015-09-26
    • 2017-06-05
    • 1970-01-01
    • 2013-01-29
    • 1970-01-01
    • 2018-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多