如何在OpenCV中平滑曲线(轮廓)?

11

我正在处理一张类似于此链接中的黑白图像的第一张图片:http://imageshack.us/g/33/firstwm.png/。它有很多“噪声”,所以我对其应用了一个中值滤波器来平滑它,从而得到了第二张图片。

cvSmooth(TempImage, TempImage, CV_MEDIAN, 5, 0);

在这之后,我获得了轮廓并将它们绘制在另一张图像上,就像链接中的第三张图片一样。

我的问题是,轮廓仍然有点像素化(有棱角)。是否有一种方法可以使黑白图像更加平滑,以获得更好的轮廓?或者通过对轮廓进行处理来解决问题。

我还尝试了不同内核的膨胀和腐蚀,但问题仍然存在。

感谢任何帮助。

编辑:

cvSmooth(TempImage, TempImage, CV_GAUSSIAN, 9, 9, 3);
cvThreshold(TempImage, TempImage, 127, 255, CV_THRESH_BINARY);

中值滤波可以得到相同的结果,但仍会留下一些像素化的轮廓。


1
将其通过高斯核,然后阈值处理应该能够平滑边缘。也许这就是您想要的结果? - swalog
我假设你所说的“噪声”是指你在第二个例子中似乎已经去除的高频分量。这个输出结果是你想要的吗?如果只需要二进制输出,那么硬阈值可能是最接近的东西。 - swalog
是的,期望的输出是尽可能地消除噪声,使轮廓更加平滑。我已经尝试了高斯+阈值,并按照您的建议进行了尝试,但结果与中值滤波器相同。 - Adrian
也许增加高斯核大小可以消除剩余的像素轮廓?如果您想要抗锯齿边缘,则应执行我建议的重新映射。 - swalog
你能否解释一下如何进行重新映射,或者给个例子吗?抗锯齿边缘正是我需要的,这就是我所说的平滑 :) - Adrian
1个回答

8

enter image description here

如果您想要平滑的效果,可以通过进行高斯模糊,然后进行阈值处理来实现。即使用cvSmoothCV_GAUSSIAN作为参数,然后再使用cvThreshold

如果您想要比阈值处理更平滑的过渡效果(如此处所示),您可以通过调整级别来实现(重新映射颜色范围,以保留一些边缘过渡)。

更新:为了解释如何在阈值处理中获得平滑(抗锯齿)边缘,请考虑阈值处理的操作。它基本上是逐个像素地处理图像。如果像素值低于阈值,则将其设置为黑色(0),否则将其设置为白色(255)。

因此,阈值运算符非常简单,但是可以使用任何其他通用映射函数。基本上,这是一个函数f(i),其中i是强度像素值(范围为0-255),f(i)是映射值。对于阈值,这个函数很简单。

 f(i) = {   0, for i  < threshold
          255, for i >= threshold

你所拥有的是经过平滑处理的图像(使用高斯核进行了cvSmooth,这使得平滑效果最好),因此在边缘上你会得到从0到255变化的软性值转换。你需要做的是将这种转换变得更小,以便获得良好的边缘效果。如果你过度处理它,你会直接从0到255转换为二进制阈值处理。
现在,考虑一下一个函数,它将127 +- 4的范围内的四个强度值映射到完整的0-255范围内。也就是说,
         f(i) = {   0,  for i  < 123
                  255,  for i >= 131
       linear mapping,  for 123 <= i < 131

希望你能获得期望的输出结果。我会快速查看,看看是否已经在openCV中实现了该功能。不过自己编写应该也不算太难。

更新2 轮廓版本的代码大概是这样的:

              f(i) = { 255,  for        i < 122
   linear mapping (255->0),  for 122 <= i < 126
                         0,  for 126 <= i < 127
   linear mapping (0->255),  for 127 <= i < 131
                       255,  for 131 <= i

哦,我现在明白你的意思了,我可以使用cvLUT而不是cvThreshold。但是现在我想一想,在应用cvFindContours获取轮廓后,我会回到像素化的轮廓:(。无论如何,感谢您的回复,如果几天内没有更好的答案出现,我将把您的标记为正确答案。 - Adrian
考虑到平滑操作后您已经拥有了平滑渐变边缘。使用cvLUT和正确的表格值仍然可以得到一个漂亮的轮廓图像。简而言之,它将具有三个范围,从白色到黑色(线条开始),从黑色到黑色(线条内部)和从黑色到白色(线条结束)。它遵循与上述相同的结构。所有这些范围之外的值也都映射为白色。因此,您最终会得到一个漂亮的轮廓图像 :) - swalog
请参见答案中的更新2。我只是猜测一些好的值,所以您可能需要尝试调整它 :) - swalog

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