【发布时间】:2013-03-11 19:25:09
【问题描述】:
有什么方法可以快速可靠地对可能出现模糊和不均匀亮度的图像进行阈值处理?
示例(模糊但亮度均匀):
由于不能保证图像具有均匀的亮度,因此使用固定阈值是不可行的。自适应阈值可以正常工作,但由于模糊性,它会在特征中造成中断和扭曲(这里,重要的特征是数独数字):
我也尝试过使用直方图均衡(使用 OpenCV 的 equalizeHist 函数)。它在不减少亮度差异的情况下增加对比度。
我发现的最佳解决方案是将图像除以其形态闭合(归功于this post)以使亮度均匀,然后重新归一化,然后使用固定阈值(使用 Otsu 的算法来选择最佳阈值级别):
这是 OpenCV for Android 中的代码:
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(19,19));
Mat closed = new Mat(); // closed will have type CV_32F
Imgproc.morphologyEx(image, closed, Imgproc.MORPH_CLOSE, kernel);
Core.divide(image, closed, closed, 1, CvType.CV_32F);
Core.normalize(closed, image, 0, 255, Core.NORM_MINMAX, CvType.CV_8U);
Imgproc.threshold(image, image, -1, 255, Imgproc.THRESH_BINARY_INV
+Imgproc.THRESH_OTSU);
这很好用,但是关闭操作很慢。减小结构元素的大小会提高速度,但会降低准确性。
编辑:根据 DCS 的建议,我尝试使用高通滤波器。我选择了 Laplacian 滤波器,但我希望使用 Sobel 和 Scharr 滤波器得到类似的结果。该滤波器在不包含特征的区域中拾取高频噪声,并且由于模糊而遭受与自适应阈值相似的失真。它也需要大约与关闭操作一样长的时间。这是一个使用 15x15 过滤器的示例:
编辑 2:根据 AruniRC 的回答,我使用建议参数对图像使用 Canny 边缘检测:
double mean = Core.mean(image).val[0];
Imgproc.Canny(image, image, 0.66*mean, 1.33*mean);
我不确定如何可靠地自动微调参数以获得连接的数字。
【问题讨论】:
-
您可以尝试对高通滤波图像设置阈值,假设亮度变化发生在低频。但是,我不知道这些过滤器操作在移动设备上的速度有多快,而且我认为您需要一个相当大的内核。
-
@DCS 不幸的是,我认为高通滤波器不会起作用。请参阅我对上述帖子的编辑。
-
既然您感兴趣的特征覆盖了几个像素,那么先将图像降低到较低的分辨率如何?然后,您可以返回并以原始分辨率获取更多细节,使用您的低分辨率版本作为遮罩。
-
降低分辨率,用小图确定大图对应区域的亮度如何归一化,归一化后进行滤波。与使用大图像进行归一化相比,它应该有更多的噪音,但它会更快。希望有正确的阈值就足够了。这只是一个想法。
-
这个问题不就是做一个谷歌搜索和对一些技术进行基准测试的问题吗?
标签: opencv image-processing threshold