如何在OpenCV中平滑曲线(轮廓)?
我正在处理黑白图像,就像该链接中的第一个图像一样: http://imageshack.us/g/33/firstwm.png/ 它具有很多噪声",因此我在其上应用了中值滤镜以使其平滑,从而获得了第二张图片.
I am working on a black&white image just like the first one from the link : http://imageshack.us/g/33/firstwm.png/ It has a lot of "noise" so I applied a Median filter over it to smooth it, thus getting the second picture.
cvSmooth(TempImage, TempImage, CV_MEDIAN, 5, 0);
在此之后,我得到了轮廓并将其绘制在另一个图像上,如链接中的第3张图片. 我的问题是轮廓仍然有点像素化(前卫).有没有一种方法可以使黑白图像更加平滑,从而获得更好的轮廓?或对轮廓进行一些处理. 我还尝试了使用不同内核的Dilate和Erode,但问题仍然相同. 谢谢您的帮助.
After this i get the contours and draw them on another image like the 3rd picture from the link. My problem is that the contours are still a little pixelated(edgy). Is there a way to smooth the B&W image even more so to obtain better contours? Or maybe do something with the contours. I have also tried Dilate and Erode with different kernels but the problem remains the same. Thank you for anything that helps.
也尝试过:
cvSmooth(TempImage, TempImage, CV_GAUSSIAN, 9, 9, 3);
cvThreshold(TempImage, TempImage, 127, 255, CV_THRESH_BINARY);
与中值过滤器的结果相同,但是,仍然保留了一些像素化的轮廓.
Same results as median filter, ok, but still leaves some pixelated contours.
如果这是您想要的平滑结果,则可以通过进行高斯模糊,然后进行阈值处理来获得. IE.将cvSmooth
与CV_GAUSSIAN
用作参数.后跟cvThreshold
.
If this is the smoothing result you're after, it can be obtained by doing a Gaussian blur, followed by a thresholding. I.e. using cvSmooth
with CV_GAUSSIAN
as the paramater. Followed by a cvThreshold
.
如果您想要比阈值更平滑的过渡(例如此),则可以得到调整级别(重新映射颜色范围,以便保留一些边缘过渡).
If you want a smoother transition than thresholding (like this), you can get that with adjusting levels (remapping the color range so that you preserve some of the edge transition).
更新要说明如何获得阈值上的平滑(抗锯齿)边缘,请考虑阈值的作用.它基本上处理图像中的每个像素,一次处理一个.如果像素值低于阈值,则将其设置为黑色(0),否则将其设置为白色(255).
update To explain how to get the smooth (anti-aliased) edge on the thresholding, consider what the thresholding does. It basically processes each pixel in the image, one at a time. If the pixel value is lower than the threshold, it is set to black (0), if not it is set to white (255).
因此,阈值运算符非常简单,但是,可以使用任何其他常规映射函数.基本上,它是一个函数f(i)
,其中i
是强度像素值(范围为0-255),而f(i)
是映射值.对于阈值,此功能很简单
The threshold operator is thus very simple, however, any other general mapping function can be used. Basically it's a function f(i)
, where i
is the intensity pixel value (ranged 0-255) and f(i)
is the mapped value. For threshold this function is simple
f(i) = { 0, for i < threshold
255, for i >= threshold
您拥有的是平滑图像(通过cvSmooth使用高斯内核,如果可以的话,它可以为您提供最平滑"的平滑).因此,您在边缘上具有从0到255范围内的值的软过渡.您想要做的是使此过渡小得多,以便获得良好的边缘.如果对它进行弹道射击,则直接从0到255,这与您已经完成的二进制阈值相同.
What you have is a smoothed image (by cvSmooth using a Gaussian kernel, which gives you the "smoothest" smoothing, if that makes sense). Thus you have a soft transition of values on the edges, ranging from 0 to 255. What you want to do is make this transition much smaller, so that you get a good edge. If you go ballistic on it, you go directly from 0 to 255, which is the same as the binary thresholding you've already done.
现在,考虑一个将4个强度值(127 + -4)范围映射到0-255整个范围的函数.即
Now, consider a function that maps, maybe a range of 4 intensity values (127 +- 4) to the full range of 0-255. I.e.
f(i) = { 0, for i < 123
255, for i >= 131
linear mapping, for 123 <= i < 131
您将获得所需的输出.我将快速浏览一下,看看它是否已经在openCV中实现.不过,自己编写代码也不应该太难.
And you get the desired output. I'll take a quick look and see if it is implemented in openCV already. Shouldn't be too hard to code it yourself though.
更新2 轮廓版本将如下所示:
update 2 The contour version would be something like this:
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