概述
局部二值化(Local Binarization)是一种图像处理技术,用于将灰度图像转换为二值图像(黑白图像)。与全局二值化不同,局部二值化不是对整个图像使用单一阈值,而是根据图像中每个像素周围的局部区域特征来动态确定阈值。
局部二值化的基本思想是:对于图像中的每个像素,计算其邻域窗口内的统计特征(如均值、标准差等),然后基于这些局部统计信息计算该像素的阈值。
在OpenCV中已经封装了Niblack算法、Sauvola 算法与Nick 算法,本示例的流程图如下所示:
效果:
Niblack 算法
T(x,y) = m(x,y) + k × σ(x,y)
T(x,y): 像素(x,y)的阈值
m(x,y): 局部窗口内的均值
σ(x,y): 局部窗口内的标准差
k: 经验参数,通常为负值(-0.2 到 -0.1)
Sauvola 算法
T(x,y) = m(x,y) × [1 + k × (σ(x,y)/R - 1)]
R: 动态范围,通常设为128(8位灰度图像的标准差最大值)
k: 经验参数,通常为正值(0.1 到 0.5)
Nick 算法
T(x,y) = m(x,y) + k × σ(x,y)
表面公式与 Niblack 相同,但实现方式和参数范围不同
k: 通常为负值(-0.1 到 -0.2)
在实际应用中,Sauvola 通常是第一个应该尝试的算法。如果发现它在处理特定数据集(尤其是噪声或对比度问题严重)时效果不佳,再考虑切换到 Nick 算法,并投入时间调整其参数,Niblack算法现在主要用于初学者入门学习。
我们现在不是来研究算法的,主要目的是在实际项目中使用的,主要是看如何具体使用这些算法。
实践
在OpenCVSharp中使用这三个算法很方便:
csharp
// Niblack 算法
sw.Start();
CvXImgProc.NiblackThreshold(src, niblack, 255, ThresholdTypes.Binary, kernelSize, -0.2, LocalBinarizationMethods.Niblack);
sw.Stop();
NiblackTime = $"Niblack算法耗时: {sw.ElapsedMilliseconds} 毫秒";
NiblackImage = ConvertMatToBitmapImage(niblack);
// Sauvola 算法
sw.Restart();
CvXImgProc.NiblackThreshold(src, sauvola, 255, ThresholdTypes.Binary, kernelSize, 0.1, LocalBinarizationMethods.Sauvola);
sw.Stop();
SauvolaTime = $"Sauvola算法耗时: {sw.ElapsedMilliseconds} 毫秒";
SauvolaImage = ConvertMatToBitmapImage(sauvola);
// Nick 算法
sw.Restart();
CvXImgProc.NiblackThreshold(src, nick, 255, ThresholdTypes.Binary, kernelSize, -0.14, LocalBinarizationMethods.Nick);
sw.Stop();
NickTime = $"Nick算法耗时: {sw.ElapsedMilliseconds} 毫秒";
NickImage = ConvertMatToBitmapImage(nick);
都是使用CvXImgProc.NiblackThreshold()方法,只是参数略有不同而已。
NiblackThreshold 是一种自适应阈值化方法,它根据图像局部区域的统计特性来计算每个像素的阈值。与全局阈值化不同,这种方法能够更好地处理光照不均匀的图像。
csharp
public static void NiblackThreshold(
InputArray src,
OutputArray dst,
double maxValue,
ThresholdTypes type,
int blockSize,
double k,
LocalBinarizationMethods binarizationMethod = LocalBinarizationMethods.Niblack,
double r = 128)
{
if (src is null)
throw new ArgumentNullException(nameof(src));
if (dst is null)
throw new ArgumentNullException(nameof(dst));
src.ThrowIfDisposed();
dst.ThrowIfNotReady();
NativeMethods.HandleException(
NativeMethods.ximgproc_niBlackThreshold(src.CvPtr, dst.CvPtr, maxValue, (int)type, blockSize, k, (int)binarizationMethod, r));
GC.KeepAlive(src);
GC.KeepAlive(dst);
dst.Fix();
}
理解这个方法的参数:
局部二值化主要用在图像预处理阶段。