C++ OpenCV 视觉库是不是适合这种图像分割案例?
Posted
技术标签:
【中文标题】C++ OpenCV 视觉库是不是适合这种图像分割案例?【英文标题】:Is the C++ OpenCV vision library suitable for this case of image segmentation?C++ OpenCV 视觉库是否适合这种图像分割案例? 【发布时间】:2011-12-29 20:00:39 【问题描述】:我正在尝试为 C++ 寻找一个易于使用的视觉库。这是我的情况:我有一个连接到计算机的相机(不过,为了简单起见,我们可以假设计算机上存在图像文件),这就是图像的理想外观:
这个想法是垂直堆叠的三个对象将具有高度对比的颜色。我需要确定物体的位置,因此视觉库要么必须找到物体的边缘,要么必须确定它们的质心。
我以前从未使用过视觉系统,所以我一直在做一些研究,看起来 OpenCV 很受欢迎。它是否易于用于我的应用程序,或者是否有其他库可用于轻松确定对象的位置?
感谢您的建议!
【问题讨论】:
【参考方案1】:OpenCV 绝对是一个易于使用的视觉库。我在很多计算机视觉项目中都使用过它,对我来说它使用起来非常直观。
我假设对象颜色是未知的(如果不是,here's 是一个关于如何在 OpenCV 中找到特定颜色的非常好的教程)。
这是解决您的问题的一个粗略想法(我正在考虑在 OpenCV 中易于实现哪些操作):
将图像转换为 HSV 颜色空间 - 如果颜色具有高对比度,则该空间中的颜色应该具有非常不同的色调值,因此请仅使用色调图片
使用Otsu的方法对图片进行阈值(阈值会自动确定)
如果它挑选出中间对象(例如,背景上有 2 个连接的组件),则分割完成。如果对象是方形的,您可以使用findContours
或什至对线条使用霍夫变换。
如果它只挑选出外部对象,您可以再次以相同的方式找到它的轮廓,设置感兴趣区域(您正在处理的图片的一部分)使其刚好在轮廓内,并阈值再次在图像的内部找到其他两个对象之间的边界。最后,只需将找到的轮廓叠加在单独的图像上即可。
最棘手的情况是它是否设置了阈值,以便您只能找到最里面的对象。乍一看,您无法将其与上述情况区分开来,但第二个(内部)阈值不会给出任何相关结果。在这种情况下,您可能会在找到的阈值区域(第二个对象的色调)之外选择一个色调,并将(刚刚找到的)最里面的物体的色调设置为那个。现在,您再次获得 2-Hue 图片,您可以对其进行阈值处理并找到外部两个对象之间的轮廓。最后,和上一个案例一样,将找到的轮廓叠加起来。
【讨论】:
"颜色在这个空间中应该有非常不同的色调值"有用的技巧,我会记住的。【参考方案2】:对于这个特定的图像,您不需要在全色空间中工作,而是可以单独处理强度(HSV 的“V”部分 - “值”表示强度)。
正如 Penelope 所说,您是使用价值空间还是色调空间,将取决于您为真实对象生成的自然图像。对于一般情况,您可能需要结合使用色调和值(强度)来正确分割图像。与在色调值向量空间中工作不同,在 H 和 V 图像平面中分别工作然后组合结果更为直接。 (3D 向量空间中的分割当然是可能的,但对于这个项目来说可能会不必要地复杂。)
OpenCV 中的分水岭算法可以很好地满足您的需求。 http://www.seas.upenn.edu/~bensapp/opencvdocs/ref/opencvref_cv.htm
关于 Otsu 方法的一个警告:当强度值(或色调值)的直方图是双峰分布时,分离两种模式很好,但对于自然图像,真正的双峰分布并不常见。如果背景和/或前景对象的强度和/或色调从对象的一侧到另一侧发生变化,则 Otsu 的表现可能很差。
Otsu 当然可以扩展到多种模式,正如 Gonzalez 和 Woods 的 数字图像处理 以及其他关于该主题的介绍性教科书所解释的那样。但是,即使您使用 Otsu 一次分离一对模式,背景渐变也会导致问题。
您还需要确保即使您的相机镜头放大或缩小,您仍会找到相同的二值化阈值。基本的 Otsu 技术使用图像直方图中的所有像素。这意味着您可以打乱图像中的所有像素以产生具有与原始图像相同的图像直方图的纯噪声,并且 Otsu 的方法将生成相同的阈值。
一个常见的技巧是依赖边缘附近的像素。在您的示例中,我们可以将图像视为具有锐利边缘、锐角和(希望)统一 HSV 值的区域。可以通过多种方式对边缘附近的像素进行采样,包括:
-
找到强边缘点(使用 Canny 或一些更简单的技术)。沿着边缘梯度的方向,在距离边缘点 +/- D 处,对(相对)前景和(相对)背景的灰度级进行采样。距离 D 应远小于相关对象的大小。
找到强大的边缘点。使用边缘点本身的灰度级作为可能所需阈值的估计。在您的示例中,您将出现两个强峰:一个位于 object1 和 object2 之间的边缘,另一个位于 object2 和 object3 之间的边缘。
由于您的对象有角,您可以使用它们来帮助识别适合采样的对象边界和/或边缘像素。
如果您有名义上的矩形对象,您还可以使用 Hough 边缘或 RANSAC 边缘算法来识别图像中的线条、找到拐角处的交叉点等。
话虽如此,对于几乎任何涉及堆叠在一起的对象的自然图像,您都会遇到几个复杂问题:
阴影 标称颜色一致的对象的颜色和强度渐变 如果物体与光学系统的距离不同,则边缘的清晰度会有所不同如果您确定存在多少对象,您可以尝试 K 均值 技术。 http://aishack.in/tutorials/knearest-neighbors-in-opencv/
对于更复杂的分割任务,例如不知道对象数量时,您可以使用 Mean Shift 技术,但我建议先尝试更简单的技术。
第一步也是最简单的解决方法是使用适当的照明。要减少反射和阴影,请使用漫射照明。对于许多应用,最接近理想漫射照明的是“阴天”照明: http://www.microscan.com/en-us/products/nerlite-machine-vision-lighting/cdi-illuminators.aspx
更简单地说,您可以尝试使用一种或多种“反射”灯,例如工作室摄影中使用的那些。 http://www.photography.com/articles/taking-photos/bounce-lighting/
【讨论】:
以上是关于C++ OpenCV 视觉库是不是适合这种图像分割案例?的主要内容,如果未能解决你的问题,请参考以下文章