【问题标题】:How to remove the local average color from an image with OpenCV如何使用 OpenCV 从图像中去除局部平均颜色
【发布时间】:2026-01-13 17:15:01
【问题描述】:

我想要检测具有柔和渐变背景和锐利前景特征的图像。我希望在图像中找到绿色弧线。但是,绿色弧线仅相对于背景是绿色的(它们是半透明的)。绿色圆弧也只有一两个像素宽。

因此,对于图像的每个像素,我想减去周围像素的平均颜色。周围的 5x5 或 10x10 像素就足够了。这应该不会影响前景特征,但会移除柔和的背景,然后我可以选择绿色通道进行进一步处理。

有什么方法可以有效地做到这一点?它不必特别准确,但我想在 1080p 图像上以 30Hz 运行它。

【问题讨论】:

  • 传统的方法是先模糊再减去。您可能会发现,如果准确性不是那么重要,您可以有效地将图像缩小到其原始尺寸的 1/4 或更小,然后在较小的图像上使用较小的模糊/平均半径(这会更快)然后在减去之前按比例缩小到原始大小。
  • 我没有对其进行基准测试或实现它,但 Scale2x 算法 scale2x.it/algorithm 看起来很有趣,并且被认为足以包含在 CImg 库中.
  • 不确定你是否意识到,但如果你从每个像素中减去周围 9x9 区域的平均值,你会得到颜色失真......thesetchells.com/a.png
  • 我做了一些基准测试,在我的机器上使用 1920x1080 图像,框模糊大约需要 25 毫秒,减法大约需要 15 毫秒,你的肯定会有所不同,但可能会在单独的线程中进行框模糊,并且只除非背景变化非常快,否则每 10-30 帧执行一次,那么您将只有 15 毫秒的减法时间,这在 30 fps 视频上可能没问题。
  • 模糊减法效果很好,请给出正确答案以便我批准

标签: opencv


【解决方案1】:

您可以通过对图像进行简单的框模糊然后从原始图像中减去它来实现此目的:

blur(img,blurred,Size(15,15));
diff=img-blurred;

我在一个 1920x1080 的图像上尝试了这个,模糊需要 25 毫秒,而减法需要 15 毫秒,在一个体面的规格 iMac 上。

如果您的背景没有快速变化,您可以在第二个线程中计算几帧空间的模糊度并继续重复使用它,直到几帧后再次重新计算它,然后您将只有 15 毫秒的减法为每个 30fps 而不是 45ms 的处理做。

【讨论】:

    【解决方案2】:

    根据背景渐变的平滑程度,边缘检测和膨胀可能适合您。

    边缘检测将输出您在示例中显示的 3 行并丢弃背景渐变(同样,取决于平滑度)。扩大图像然后将加厚边缘,使您的线条轮廓更加显着。

    您可以将此边缘图叠加在原始图像上:

    Mat src,edges;
    //perform edge detection on src and output in edges. 
    Mat result;
    cvtColor(edges,edges,cv2.COLOR_GRAY2BGR);//change mask to a 3 channel image 
    subtract(edges,src,result);
    subtract(edges,result);
    

    结果应仅包含 3 种颜色的 3 行。从这里开始,您可以应用颜色过滤来选择绿色。

    【讨论】: