OpenCV如何像人眼一样找到主观轮廓

4
当人们看到标记提示形状时,他们立刻感知到形状本身,就像在 https://en.wikipedia.org/wiki/Illusory_contours 中所示。我正在尝试在OpenCV中实现类似的功能,以便在具有非常大噪声的深度图像中检测手的形状。在这个问题中,假设基于肤色的检测不起作用(实际上这是我目前取得的最好结果,但在不断变化的光照条件、阴影或肤色下并不稳健。此外,桌子上还有各种纸张形状(平面和彩色),这会使基于颜色的方法变得混乱。这就是为什么我尝试使用深度相机的原因)。
这是一张已经进行了预处理以获得更好的对比度并去除背景梯度的实时录像样本图片:Hand with heavy background noise 我想将手的确切形状与图片的其余部分隔离开来。对于人眼来说,这是一件微不足道的事情。所以这里是我做过的几次尝试:
这是应用Canny边缘检测后的结果。问题在于手内部的黑色形状比实际手要大,导致检测到的手过大。此外,线条没有连接,我无法检测轮廓。 使用Canny尝试 更新:将Canny和形态学闭合(4x4像素椭圆)结合起来,可以进行轮廓检测,并得到以下结果。仍然非常嘈杂。 带有形态学处理的Canny 更新2: 通过将轮廓绘制到一个空的掩模中,将其保存在缓冲区中,并重新检测合并三个缓冲图像的轮廓,可以稍微增强结果。组合缓冲图像的行是 hand_img = np.array(np.minimum(255, np.multiply.reduce(self.buf)), np.uint8) ,然后再次进行形态学变换(闭运算),最后检测轮廓。结果比上面的图片要好一些,但却有点滞后。

另外,我尝试使用现有的CNN(https://github.com/victordibia/handtracking)来检测手的大致位置(此步骤有效),然后从那里开始泛洪。为了检测轮廓,将结果放入OTSU滤波器中,然后取最大的轮廓,得到以下图片(忽略左侧的黑色矩形)。问题是一些噪声也被泛滥了,结果不太理想:Attempt with flooding

最后,我尝试了MOG2或GMG等背景去除工具。它们被大量快速移动的噪声所困扰。此外,它们切断了手指尖(这对于这个项目至关重要)。最终,它们无法在手部看到足够的细节(8位加上通过equalizeHist进一步减少颜色会产生非常差的灰度分辨率),以可靠地检测小运动。
令人荒谬的是,对于人类来说,在第一张图片中看到手的确切形状是多么简单,而对计算机来说画出形状却异常困难。
您推荐用什么方法来实现精确的手部分割?

因此,广义霍夫变换可能是我正在寻找的内容。然而,这仅存在于cv :: cuda中,而Python显然不存在。又是一条死路。 - Kalsan
1个回答

1
经过两天的紧急测试,解决方案是对预处理良好的图像进行非常谨慎的阈值处理。
以下是步骤:
  1. 尽可能去除噪音。在我的情况下,使用英特尔的 pyrealsense2 进行降噪处理(我使用的是英特尔RealSense深度相机,算法是针对该相机系列编写的,因此效果非常好)。我在每一帧上使用了 rs.temporal_filter() 和直接使用 rs.hole_filling_filter()
  2. 捕获第一帧。除了捕获到桌子的精确距离(用于后续阈值处理),这一步还保存了一张被100x100像素内核模糊的静态图片。由于相机永远不会完美地安装但稍微倾斜,图片上有一个丑陋的灰度梯度,使得操作变得不可能。然后从每个后续帧中减去这张静态图片,消除梯度。顺便说一句:这个梯度去除步骤已经包含在上面问题中展示的截图中。
  3. 现在图片几乎没有噪声了。不要使用 equalizeHist 这不仅会平均增加总体对比度,而且会过度强调剩余的噪声。这是我在几乎所有实验中犯的主要错误。相反,直接应用一个阈值(二进制固定边界)。边界非常薄,将其设置为104而不是205会产生巨大的差异。
  4. 反转颜色(除非在前一步中使用了 BINARY_INV),应用轮廓,取最大轮廓并将其写入掩码。
Voilà!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接