OpenCVSharp:使用三种不同的局部二值化算法

概述

局部二值化(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中使用这三个算法很方便:

 // 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 是一种自适应阈值化方法,它根据图像局部区域的统计特性来计算每个像素的阈值。与全局阈值化不同,这种方法能够更好地处理光照不均匀的图像。

 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();
 }

理解这个方法的参数:

局部二值化主要用在图像预处理阶段。

posted @ 2025-11-19 13:50  mingupupup  阅读(36)  评论(0)    收藏  举报