【问题标题】:Removing outlier pixels from a small binary image从小二值图像中去除异常像素
【发布时间】:2012-07-13 09:06:24
【问题描述】:

我目前正在实施一种算法,用于识别有色质量的最小惯性轴(由二阶矩提供)。为此,我需要获取第一时刻给出的质心。

加权平均功能运行良好,但由于异常像素,我收到了不想要的结果。

这里是平均函数:

(例如 x 的加权平均值)

for (i = 0, i < rows, i++) {
    for (j = 0, j < cols, j++) {
        if (colorAt(i,j).isForeground()) {
            tempSumX++;
            totalForeground++;
        }
    }
    x_ += i*tempSumX;
    tempSumX = 0;
}
x_ /= totalForeground; //where x_ represents the x coordinate of the weighted center of mass.

给定这样的图像,它仅由两种颜色(背景和前景)表示,我如何去除边缘像素?注意:外围像素是指不属于大色块的任何东西。白点是计算出来的质心,不正确。

非常感谢。

【问题讨论】:

  • 你看过形态过滤器吗?
  • 我考虑过它们,但我不确定它们在我的情况下效果如何。只是不太了解情况。我也在研究图论来识别连接。
  • 它看起来不像一个平均值,或者您是否有任何在图像中看不到的异常值?在计算加权平均值时,您具体衡量了什么?
  • “由于异常像素,我收到了不想要的结果。”在没有像我展示的那样较小的单独像素的图像上,加权质心是正确的。或者也许不是。请允许我再看看我的程序..
  • 我目前用于加权平均的算法现在在上面的帖子中。

标签: algorithm computer-vision noise outliers


【解决方案1】:

有很多填充算法可以识别给定起点的所有连接像素。

另外,去除像这些来自噪声的小异常值的常用方法是腐蚀图像,然后将其扩大以恢复到相同的大小 - 尽管如果你纯粹是在做 CoG,你不一定需要扩大步骤

【讨论】:

  • 我正在查看 mathematician1975 推荐的形态过滤器,但我对我将使用什么结构元素感到困惑。一般原则是有道理的,但我不太确定 SE 的东西。如果我要使用洪水填充,我会简单地多次使用它来识别哪个形状是最大的吗?也就是说,我怎么知道从哪里开始搜索?
  • FloodFill 对我来说似乎是一个好方法。即使您使用连接组件标签,您也必须决定使用哪个 blob。这里有一个 OpenCV 示例:areshopencv.blogspot.com/2011/12/…。然后,您可以让 OpenCV 为您计算时刻:opencv.willowgarage.com/documentation/cpp/…
  • 感谢您的帮助!我最终使用了连接组件标记算法,因为它更适合我的需要。感谢 OpenCV API 链接,烧杯......虽然我事先已经为自己编写了所有代码。哎呀。
【解决方案2】:

怎么样,用伪代码:

for( y = 0; y < rows; y++ )
{    
   for ( x = 0; x < cols; x++ )
   {
       if ( pixel( x, y ).isColor() )
       {
          int sum = 0;
          // forgetting about edge cases for clarity...
          if ( !pixel( x-1, y-1 ).isColor() ) sum++;
          if ( !pixel( x,   y-1 ).isColor() ) sum++;
          if ( !pixel( x+1, y-1 ).isColor() ) sum++;
          if ( !pixel( x-1, y   ).isColor() ) sum++;
          if ( !pixel( x+1, y   ).isColor() ) sum++;
          if ( !pixel( x-1, y+1 ).isColor() ) sum++;
          if ( !pixel( x,   y+1 ).isColor() ) sum++;
          if ( !pixel( x+1, y+1 ).isColor() ) sum++;
          if ( sum >= 7 )
          {
             pixel( x, y ).setBackground();
             x -= 1;
             y -= 1;
          }
       }
   }
}

即移除任何被 7 个背景像素包围的像素。如果您将像素的颜色更改回可能受影响的最早像素。

您对“异常值”的衡量可能会发生变化 - 例如您可以将对角线像素视为价值 1/2 的值。例如。正上方、下方、左侧和右侧的像素计为 2。然后使用不同的数字作为总和。

您可以通过增加过滤器的大小来提高准确度 - 例如增加到 5x5 而不是 3x3。在这种情况下,2 以外的像素应该算得更少。

【讨论】:

    【解决方案3】:

    我认为您的算法不正确。二进制图像中的 m10 (对不起,我不知道如何做下标)是前景像素的 x 坐标的总和,所以你的代码应该是这样的:

    for (i = 0, i < rows, i++) {
        for (j = 0, j < cols, j++) {
            if (colorAt(i,j).isForeground()) {
                tempSumX += i;
                totalForeground++;
            }
        }
    }
    x_ = tempSumX/totalForeground; //where x_ represents the x coordinate of the weighted center of mass.
    

    假设这与您之前的帖子 Algorithm for Finding Longest Stretch of a Value at any Angle in a 2D Matrix 有关,您应该计算同一循环中的其他一阶和二阶矩:

    m01 += j;
    m20 += i*i;
    m02 += j*j;
    m11 += i*j;
    

    (您的算法中的 tempSumX 只是 m10,totalForeground 是 m00)

    试一试,如果您仍然无法处理异常值,您可以使用 Connected Component Labeling http://en.wikipedia.org/wiki/Connected_component_labeling 来查找最大质量。 (可在 matlab 中使用 bwlabelbwconncomp。)

    【讨论】:

    • 这实际上就是我正在做的事情,除了你通过删除乘法方面来简化它。循环中的 tempSumX++,外部的 tempSumX*i 与循环中的 tempSumX + i 完全相同。图像的问题是我交换了图像中点的 x 和 y 坐标。加权算法正常工作。在我提出这个问题后,我确实尝试了一个连接组件标记算法,但是我在 C++ 中找到一个好的联合查找实现时遇到了问题。有什么建议吗?
    • 原来如此。我想我对最大 x 维度是 rows 而最大 y 维度是 cols 感到困惑。抱歉,我碰巧没有一个好的 union-find 实现可以给你指点。
    • 您确定您的colorAt(i,j) 函数将y(行)作为第一个参数,将x(列)作为第二个参数吗?也许错误就在那里。因为您在交换坐标时报告了正确的结果。为了清楚起见,我建议使用yx 而不是ij。编辑:嗯,现在我也很困惑。重命名变量的建议仍然有效。
    • 我使用 colorAt 函数进行简化。我正在使用 OpenCV,矩阵数据存储在一个 uchars 数组中。所以数据访问是正确的,因为我之前已经将它用于许多其他颜色计算。我同意更改名称,我可能会这样做只是为了让我的生活更轻松。原来我的大部分问题现在都是基于我的 k-means 不够精确......
    猜你喜欢
    • 2021-08-02
    • 2013-03-27
    • 1970-01-01
    • 1970-01-01
    • 2019-06-08
    • 2021-12-18
    • 2013-06-21
    • 2021-05-17
    • 1970-01-01
    相关资源
    最近更新 更多