布拉德利自适应阈值算法

Big*_*ger 10 python python-imaging-library adaptive-threshold

我目前正致力于实现一个名为的阈值算法Bradley Adaptive Thresholding.

我一直在主要关注两个链接,以便弄清楚如何实现这个算法.我也成功地实现了另外两种阈值算法,主要是Otsu的方法平衡直方图阈值处理.

以下是我为了创建Bradley Adaptive Thresholding算法而遵循的两个链接.

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.420.7883&rep=rep1&type=pdf

Bradley自适应阈值Github示例

以下是Python我运行算法并保存图像的源代码部分.我使用Python Imaging Library而不是其他工具来完成我想要做的事情.

def get_bradley_binary(inp_im):
    w, h = inp_im.size
    s, t = (w / 8, 0.15)

    int_im = Image.new('L', (w, h))
    out_im = Image.new('L', (w, h))

    for i in range(w):
        summ = 0
        for j in range(h):
            index = j * w + i

            summ += get_pixel_offs(inp_im, index)

            if i == 0:
                set_pixel_offs(int_im, index, summ)
            else:
                temp = get_pixel_offs(int_im, index - 1) + summ
                set_pixel_offs(int_im, index, temp)

    for i in range(w):
        for j in range(h):
            index = j * w + i

            x1,x2,y1,y2 = (i-s/2, i+s/2, j-s/2, j+s/2)

            x1 = 0 if x1 < 0 else x1
            x2 = w - 1 if x2 >= w else x2
            y1 = 0 if y1 < 0 else y1
            y2 = h - 1 if y2 >= h else y2

            count = (x2 - x1) * (y2 - y1)

            a1 = get_pixel_offs(int_im, y2 * w + x2)
            a2 = get_pixel_offs(int_im, y1 * w + x2)
            a3 = get_pixel_offs(int_im, y2 * w + x1)
            a4 = get_pixel_offs(int_im, y1 * w + x1)

            summ = a1 - a2 - a3 + a4

            temp = get_pixel_offs(inp_im, index)
            if temp * count < summ * (1.0 - t):
                set_pixel_offs(out_im, index, 0)
            else:
                set_pixel_offs(out_im, index, 255)

    return out_im
Run Code Online (Sandbox Code Playgroud)

以下是我的代码部分,它说明了以前没有见过的这些set和get方法的实现.

def get_offs(image, x, y):
    return y * image.size[0] + x

def get_xy(image, offs):
    return (offs % image.size[0], int(offs / image.size[0]))

def set_pixel_xy(image, x, y, data):
    image.load()[x, y] = data

def set_pixel_offs(image, offs, data):
    x, y = get_xy(image, offs)
    image.load()[x, y] = data

def get_pixel_offs(image, offs):
    return image.getdata()[offs]

def get_pixel_xy(image, x, y):
    return image.getdata()[get_offs(image, x, y)]
Run Code Online (Sandbox Code Playgroud)

最后,这里是输入和输出图像.这些是我在为您提供的第一个链接中的原始研究论文中使用的相同图像.注意:输出图像几乎完全是白色的,可能很难看到,但无论如何我提供它以防万一有人真的想要它作为参考.

输入图像 输出图像

der*_*icw 11

您无法以PIL的方式创建积分图像,因为您正在打包数据的图像不能接受超过255的值.积分图像中的值变得非常大,因为它们是上面和下面像素的总和.左边(见白皮书第3页,下面).

在此输入图像描述

它们会比255大得多,所以你需要每像素32位来存储它们.

您可以通过在"L"模式下创建PIL图像,然后将像素设置为1000000或某个较大的数字来测试此项.然后,当您回读该值时,它将返回255.

>>> from PIL import Image
>>> img = Image.new('L', (100,100))
>>> img.putpixel((0,0), 100000)
>>> print(list(img.getdata())[0])
255
Run Code Online (Sandbox Code Playgroud)

编辑:阅读PIL文档后,如果以"I"模式而不是"L"模式创建积分图像,则可以使用PIL.这应该提供每像素32位.

出于这个原因,我推荐Numpy而不是PIL.

下面是使用Numpy而不是PIL重写阈值函数,我得到正确/预期的结果.请注意,我使用uint32数组创建了积分图像.我在Github上使用了与您用于翻译的完全相同的C示例:

import numpy as np

def adaptive_thresh(input_img):

    h, w = input_img.shape

    S = w/8
    s2 = S/2
    T = 15.0

    #integral img
    int_img = np.zeros_like(input_img, dtype=np.uint32)
    for col in range(w):
        for row in range(h):
            int_img[row,col] = input_img[0:row,0:col].sum()

    #output img
    out_img = np.zeros_like(input_img)    

    for col in range(w):
        for row in range(h):
            #SxS region
            y0 = max(row-s2, 0)
            y1 = min(row+s2, h-1)
            x0 = max(col-s2, 0)
            x1 = min(col+s2, w-1)

            count = (y1-y0)*(x1-x0)

            sum_ = int_img[y1, x1]-int_img[y0, x1]-int_img[y1, x0]+int_img[y0, x0]

            if input_img[row, col]*count < sum_*(100.-T)/100.:
                out_img[row,col] = 0
            else:
                out_img[row,col] = 255

    return out_img
Run Code Online (Sandbox Code Playgroud)

产量