之前接触过全局二值化(OTSU算法),还有OPENCV提供的自适应二值化,最近又了解到一种新的局部二值化算法,Sauvola算法。
转载自:http://www.dididongdong.com/archives/4048
值得注意的是,计算r×r邻域内像素值的时候,一种优化的策略是,使用OPENCV提供的积分图,计算整张图像的积分图,那么计算r×r区域内的均值可以在常数时间内实现。
CV_EXPORTS_W void integral( InputArray src, OutputArray sum, int sdepth = -1 );
我们常见的图像二值化算法大致可分为全局阈值方法与局部阈值方法这两种类型。其中OTSU算法是全局阈值的代表,而Sauvola算法则是局部阈值方法的标杆。Sauvola算法的输入是灰度图像,它以当前像素点为中心,根据当前像素点邻域内的灰度均值与标准方差来动态计算该像素点的阈值。
假定当前像素点的坐标为(x,y),以该点为中心的领域为r*r,g(x,y)表示(x,y)处的灰度值,Sauvola算法的步骤为:
来自参考《基于光照不均匀图像的自适应二值化方法研究》郭佳
引用
在二值化的操作中,用的比较多的就是全局阈值话OTSU(大津法)和局部阈值NiBlack,Niblack方法是一种简单有效的动态阈值分割方法,修改得到最佳参数之后的效果比大津法要好,因为大津法是根据整个图像来确定一个阈值,而Niblack则是在不同的R*R区域会有不同的阈值。
Niblack的基本思想是:对于图像的每一个像素点,在rxr领域空问里,计算该像素点领域方位内其他像素点的均值和方差。然后利用公式(1)进行二值化。
其中,T(x,y)是阈值,k是预先设定的修正值,图像为f(x,y),均值为m(x,y),方差为s(x,y)。
使用Niblack法的优点在于:
对每一个像素点都独立的跟据此像素点的邻域的情况来计算门限,对于和邻域均值m(x,y)相近的像素点判断为背景而反之判断为前景;而具体相近到什么程度由标准差s(X’y)和修正系数k来决定,这保证了这种的方法的灵活性。
使用Niblack法的不足在于:
由于要利用域r×r模板遍历图像,导致边界区域(r-1)/2的像素范围内无法求取阈值;同时当进行图像遍历时,如果域r×r范围内都是背景,经NIBLACK计算后必有一部分被确定为目标,产生伪噪声。
总之,用Niblack方法进行图像分割时,选择的处理模板窗口R*R大小的选择很关键,选择的空间太小,则噪声抑制的效果不理想,目标主体不够突出,选择的空间太大,则目标的细节会被去除而丢失信息。
参考
1.第一次做MathOCR遇到的参考文献:
《图片中印刷体数学公式的自动识别》陈颂光
2.中文的的链接来自,追溯不到原文:
https://livezingy.com/derivations-of-sauvola-formula/
3.英文文献:值得参考的标准
Efficient implementation of local adaptive thresholding techniques using integral images
PDF链接为:https://pdfs.semanticscholar.org/8130/a9499715d22468492c3786c34ba1ba0b4ed3.pdf
4.Matlab代码参考
http://freesourcecode.net/matlabprojects/59687/sauvola-local-image-thresholding-in-matlab#.Wzsk2oq-vcs
5,https://www.cnblogs.com/guopengfei/p/4766526.html
//求区域内均值 integral即为积分图 float fastMean(cv::Mat& integral, int x, int y, int window) { int min_y = std::max(0, y - window / 2); int max_y = std::min(integral.rows - 1, y + window / 2); int min_x = std::max(0, x - window / 2); int max_x = std::min(integral.cols - 1, x + window / 2); int topright = integral.at<int>(max_y, max_x); int botleft = integral.at<