C#,图像二值化(23)——局部阈值的绍沃拉算法(Sauvola Thresholding)及源程序

1、局部阈值的绍沃拉算法(Sauvola Thresholding)

Niblack和Sauvola阈值算法

Niblack和Sauvola阈值是局部阈值技术,对于背景不均匀的图像非常有用,尤其是对于文本识别1、2。代替为整个图像计算单个全局阈值,通过使用考虑到局部邻域(由以像素为中心的窗口定义)的平均值和标准偏差的特定公式,为每个像素计算多个阈值。

Niblack and Sauvola Thresholding

Niblack and Sauvola thresholds are local thresholding techniques that are useful for images where the background is not uniform, especially for text recognition 1, 2. Instead of calculating a single global threshold for the entire image, several thresholds are calculated for every pixel by using specific formulae that take into account the mean and standard deviation of the local neighborhood (defined by a window centered around the pixel).

利用积分图像实现Sauvola方法

团队成员:瓦哈布·阿夫塔布、费赞·扎法尔、萨阿德·拉扎、拉贾·乌迈尔

在本项目中,我们开发了一种二值化退化或历史文档的方法。该方法是文档图像二值化研究论文的自适应阈值方法的实现(底部给出了链接)。首先将图像转换为灰度以应用阈值技术,然后使用Sauvola方法使用相邻窗口像素的平均值和标准差来计算阈值。积分图像不需要对所有像素求和以在一个窗口中找到平均值和标准偏差,而是使用4次数学运算即可有效地计算平均值和平均偏差。这使得该方法更加高效,并且大大减少了运行时间,而不依赖于窗口大小,并且不会对原始Sauvola方法的质量产生任何影响。

图像二值化:

图像二值化是拍摄灰度图像并将其转换为黑白图像的过程,本质上是将图像中包含的信息从256个灰度级减少到2个灰度级:黑白二值图像。保存所有或最大子组件(如文本、背景和图像)是扫描文档预处理中最重要的步骤。二值化计算区分对象和背景像素的阈值。如我们所知,灰度图像像素值的范围为[0-255]。因此,在转换为灰度之后,如果图像像素值高于阈值,则将其转换为白色,即255,如果低于阈值,则转换为黑色,即0,从而使所有像素为0或255,因此称为二进制。

二值化技术:

如所讨论的,二值化根据阈值将具有许多阴影的图像转换为黑白图像。有许多方法来计算阈值,全局阈值是一种方法,其中使用全局阈值(通常为127)来对整个图像进行二值化。许多其他自适应阈值技术也被使用,如otsu,以基于区域阈值对图像进行二值化,即为不同区域计算不同的阈值。这些方法在对高质量图像应用阈值时有效。然而,当处理降级图像时,这项任务变得困难。

Sauvola方法:

在Sauvola的二值化方法中,使用以像素(x,y)为中心的w×w窗口中像素强度的平均值m(x,y)和标准偏差s(x,x)来计算阈值t(x,Z):

其中k是[0.2,0.5]范围内的控制因子,R是预定的图像灰度值。原论文作者建议k=0.2,R=125。局部平均值m(x,y)和标准偏差s(x,y)根据像素的局部邻域中的对比度来调整阈值的值。当图像的某些区域存在高对比度时,s(x,y)≈R,这导致t(x,y)≈m(x,x)。这与Niblack方法的结果相同。然而,当当地社区的对比度很低时,就会出现差异。在这种情况下,阈值t(x,y)低于平均值,从而成功地去除了背景中相对较暗的区域。参数k控制局部窗口中的阈值的值,使得k的值越高,阈值与局部平均值m(x,y)越低。由于该方法适用于低对比度,并且可以解决图像中的阴影、亮度、降级、噪声、污迹、污渍等问题,因此它为我们提供了一个完美的解决方案。然而,为了计算阈值t(x,y),必须计算每个像素的局部平均值和标准偏差。以天真的方式计算m(x,y)和s(x,y)会导致N×N图像的计算复杂度为O(W^2 x N^2),这使得该过程非常缓慢。

Efficient Implementation of Sauvola Method Using Integral Images

Team members: Wahab Aftab, Faizan Zafar, Saad Raza, Raja Umair

In this Project, we developed a method to binarize degraded or historical documents. The method is the implementation of the Adaptive Thresholding Methods for Documents Image Binarization Research Paper (link given at the bottom). The image is first converted to grayscale to apply a thresholding technique, then Sauvola method is used to compute the threshold using mean and standard deviation of neighbouring window pixels. Instead of summing over all the pixels to find mean and standard deviation withtin a window, integral images are used to efficienty compute mean and standard deviation with as little as 4 mathematical operations. This makes the method much more efficient and reduces runtime drastically without relying on window size and it doesn't have any impact on original Sauvola method quality.

Image Binarization:

Image binarization is the process of taking a grayscale image and converting it to black-and-white, essentially reducing the information contained within the image from 256 shades of gray to 2: black and white, a binary image. It's the most important step in pre-processing of scanned documents to save all or maximum subcomponents such us text, background and image. Binarization computes the threshold value that differentiate object and background pixels. As we know grayscale image pixel values range from [0-255] So after conversion to grayscale, image pixel values are converted to white i.e 255 if they are above threshold value and to black i.e 0 if they are below the threshold making all the pixels either 0 or 255 hence the term binary.

Binarization Techniques:

As discussed, binarization converts the image with many shades into an image of black and white depending on the threshold value. There are many methods to compute the threshold value, global thresholding is one method where a global threshold (typically 127) is used to binarize entire image. Many other adaptive thresholding techniques are also used like otsu to binarize image based on region wise thresholding i.e different thresholdss are computed for different regions. These methods work when applying thresholding onto good quality image. However, this task becomes difficult when it deals with degraded image.

Sauvola's Method:

In Sauvola’s binarization method, the threshold t(x, y) is computed using the mean m(x, y) and standard deviation s(x, y) of the pixel intensities in a w × w window centered around the pixel (x, y):

where k is a control factor in the range of [0.2, 0.5] and R is a predetermined image graylevel value. The author of the original paper suggested k=0.2, R= 125. The local mean m(x, y) and standard deviation s(x, y) adapt the value of the threshold according to the contrast in the local neighborhood of the pixel. When there is high contrast in some region of the image, s(x, y) ≈ R which results in t(x, y) ≈ m(x, y). This is the same result as in Niblack’s method. However, the difference comes in when the contrast in the local neighborhood is quite low. In that case the threshold t(x, y) goes below the mean value thereby successfully removing the relatively dark regions of the background. The parameter k controls the value of the threshold in the local window such that the higher the value of k, the lower the threshold from the local mean m(x, y). Since this method is good for low contrast and can tackle problems like Shadows, Luminance, Degradation, Noise, smudge, stains etc in an image, So it provided us with a perfect solution for our problem. However, in order to compute the threshold t(x, y), local mean and standard deviation have to be computed for each pixel. Computing m(x, y) and s(x, y) in a naive way results in a computational complexity of O(W^2 x N^2) for an N × N image which makes the process very slow.

2、局部阈值的绍沃拉算法(Sauvola Thresholding)源代码

二值算法综述请阅读:

C#,图像二值化(01)——二值化算法综述与二十三种算法目录

https://blog.csdn.net/beijinghorn/article/details/128425225?spm=1001.2014.3001.5502

支持函数请阅读:

C#,图像二值化(02)——用于图像二值化处理的一些基本图像处理函数之C#源代码

https://blog.csdn.net/beijinghorn/article/details/128425984?spm=1001.2014.3001.5502

namespace Legalsoft.Truffer.Binarization
{
public static partial class BinarizationHelper
{
    #region 灰度图像二值化 局部算法 Sauvola 算法

    /// <summary>
    /// 局部算法
    /// 实现Sauvola算法实现图像二值化
    /// https://blog.csdn.net/weixin_43211480/article/details/106748822
    /// </summary>
    /// <param name="data"></param>
    /// <param name="kernel">以当前像素点为中心的邻域的宽度</param>
    /// <param name="k">使用者自定义的修正系数</param>
    public static void Sauvola_Algorithm(byte[,] data, int kernel = 15, double k = 0.3)
    {
        int height = data.GetLength(0);
        int width = data.GetLength(1);

        //邻域边界距离中心点的距离
        int whalf = kernel / 2;
        //int MAXVAL = 256;

        int[,] integral_image = new int[width, height];
        int[,] integral_sqimg = new int[width, height];
        int[,] rowsum_image = new int[width, height];
        int[,] rowsum_sqimg = new int[width, height];
        for (int y = 0; y < height; y++)
        {
            rowsum_image[0, y] = data[y, 0];
            rowsum_sqimg[0, y] = data[y, 0] * data[y, 0];
        }

        for (int x = 1; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                //计算图像范围内任意宽度窗口(邻域)的灰度值之和
                rowsum_image[x, y] = rowsum_image[x - 1, y] + data[y, x];

                //计算图像范围内任意宽度窗口(邻域)的灰度值平方之和
                rowsum_sqimg[x, y] = rowsum_sqimg[x - 1, y] + data[y, x] * data[y, x];
            }
        }

        for (int x = 0; x < width; x++)
        {
            integral_image[x, 0] = rowsum_image[x, 0];
            integral_sqimg[x, 0] = rowsum_sqimg[x, 0];
        }

        for (int x = 0; x < width; x++)
        {
            for (int y = 1; y < height; y++)
            {
                //计算图像范围内任意宽度窗口(邻域)的灰度值的积分
                integral_image[x, y] = integral_image[x, y - 1] + rowsum_image[x, y];

                //计算图像范围内任意宽度窗口(邻域)的灰度值平方的积分
                integral_sqimg[x, y] = integral_sqimg[x, y - 1] + rowsum_sqimg[x, y];
            }
        }

        byte[,] dump = (byte[,])data.Clone();
        for (int x = 0; x < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                int xmin = Math.Max(0, x - whalf);
                int ymin = Math.Max(0, y - whalf);
                int xmax = Math.Min(width - 1, x + whalf);
                int ymax = Math.Min(height - 1, y + whalf);
                double area = (xmax - xmin + 1) * (ymax - ymin + 1);
                if (area <= 0)
                {
                    throw new Exception("Binarize: area can't be 0 here");
                }

                double diff = 0.0;
                double sqdiff = 0.0;
                if (xmin == 0 && ymin == 0)
                {
                    diff = integral_image[xmax, ymax];
                    sqdiff = integral_sqimg[xmax, ymax];
                }
                else if (xmin == 0 && ymin > 0)
                {
                    diff = integral_image[xmax, ymax] - integral_image[xmax, ymin - 1];
                    sqdiff = integral_sqimg[xmax, ymax] - integral_sqimg[xmax, ymin - 1];
                }
                else if (xmin > 0 && ymin == 0)
                {
                    diff = integral_image[xmax, ymax] - integral_image[xmin - 1, ymax];
                    sqdiff = integral_sqimg[xmax, ymax] - integral_sqimg[xmin - 1, ymax];
                }
                else
                {
                    double diagsum = integral_image[xmax, ymax] + integral_image[xmin - 1, ymin - 1];
                    double idiagsum = integral_image[xmax, ymin - 1] + integral_image[xmin - 1, ymax];
                    //以(i,j)为中心点的w邻域内灰度值的积分
                    diff = diagsum - idiagsum;

                    double sqdiagsum = integral_sqimg[xmax, ymax] + integral_sqimg[xmin - 1, ymin - 1];
                    double sqidiagsum = integral_sqimg[xmax, ymin - 1] + integral_sqimg[xmin - 1, ymax];
                    //以(i,j)为中心点的w邻域内灰度值平方的积分
                    sqdiff = sqdiagsum - sqidiagsum;
                }

                //以(i,j)为中心点的w邻域内的灰度均值
                double mean = diff / area;

                //以(i,j)为中心点的w邻域内的标准方差
                double std = Math.Sqrt((sqdiff - diff * diff / area) / (area - 1));

                //根据Sauvola计算公式和以(i,j)为中心点的w邻域内的灰度均值与标准方差来计算当前点(i,j)的二值化阈值
                double threshold = mean * (1 + k * ((std / 128) - 1));

                //根据当前点的阈值对当前像素点进行二值化
                data[y, x] = (byte)((dump[y, x] < threshold) ? 0 : 255);
            }
        }
    }

    #endregion
}
}

3、局部阈值的绍沃拉算法(Sauvola Thresholding)计算效果

POWER BY 315SOFT.COM & TRUFFER.CN

与联高《原本》算法比起来,效果差的很多。

猜你喜欢

转载自blog.csdn.net/beijinghorn/article/details/128667220