2011-09-14 336 views
10

我工作在黑色&白色图像就像链接中的第一个: http://imageshack.us/g/33/firstwm.png/ 它有很多“噪音”,所以我在它上面应用了一个中值滤镜来平滑它,从而得到第二张图片。我如何平滑OpenCV中的曲线(轮廓)?

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

在此之后我得到的轮廓,并吸引他们像是从连接第3图像对其它图像。 我的问题是轮廓仍然有点像素(前卫)。有没有办法让B图像变得更光滑以获得更好的轮廓?或者也许用轮廓做点什么。 我也尝试过使用不同内核的Dilate和Erode,但问题依然存在。 谢谢你的帮助。

编辑: 也试过:

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

的结果相同中值滤波,好的,但仍有一些像素化轮廓。

+1

将其通过高斯核,然后进行阈值应理顺出了边线。也许这是你想要的结果? – swalog

+0

我假设你所说的“噪音”是你在第二个例子中似乎已经删除的高频成分。 [this](http://i.imgur.com/33GIT.png)是否需要输出?如果只需要二进制输出,[硬阈值](http://i.imgur.com/VelRg.png)将是最接近的事情。 – swalog

+0

是的,所需的输出是消除噪音,以尽可能平滑的轮廓,我已经尝试了高斯+阈值也在你的建议,但得到与中值滤波相同的结果。 – Adrian

回答

8

enter image description here

如果这是你以后的平滑效果,可以通过做一个高斯模糊,随后阈值获得。即使用cvSmoothCV_GAUSSIAN作为参数。接着是cvThreshold

如果你想要比阈值更平滑的过渡(如this),可以通过调整层次(重新映射颜色范围以保留一些边缘过渡)来获得。

更新要解释如何在阈值上获得平滑(抗锯齿)边缘,请考虑阈值的作用。它基本上处理图像中的每个像素,一次一个。如果像素值低于阈值,则设置为黑色(0),否则设置为白色(255)。

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

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

你有什么是(使用高斯内核,它给你的“平滑”平滑,如果是有道理的由cvSmooth)平滑图像。因此,您可以在边缘上进行软转换,范围从0到255.您想要做的是将此转换变得更小,以便获得良好的边缘。如果你使用弹道,你直接从0到255,这与你已经完成的二进制阈值相同。

现在,考虑一个函数,可以将4个强度值(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 
+0

哦,我现在明白你在说什么,因为我可以使用cvLUT而不是cvThreshold。但现在我应用cvFindContours来获取轮廓后我想到了它,我会回到像素化的轮廓:(无论如何,感谢反应,如果几天后没有更好的答案弹出,我会将你的标记为正确 – Adrian

+0

考虑到在平滑操作后你确实有平滑的渐变边缘,仍然可以使用cvLUT和正确的表格值得到一个漂亮的轮廓图像,总之它有三个范围,从白色到黑色从黑色到黑色(在行内)和从黑色到白色(行尾),如果跟上面的结构相同,所有的值都映射到白色,所以你最终看起来很漂亮轮廓:) – swalog

+0

请参阅答案中的更新2。我也只是猜测好价值,所以你可能想玩弄它:) – swalog