首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Bradley-Roth自适应阈值算法-如何获得更好的性能?

Bradley-Roth自适应阈值算法-如何获得更好的性能?
EN

Stack Overflow用户
提问于 2015-10-13 07:23:51
回答 2查看 2.5K关注 0票数 6

我有以下图像阈值处理代码,使用Bradley-Roth图像阈值方法。

代码语言:javascript
复制
from PIL import Image
import copy
import time
def bradley_threshold(image, threshold=75, windowsize=5):
    ws = windowsize
    image2 = copy.copy(image).convert('L')
    w, h = image.size
    l = image.convert('L').load()
    l2 = image2.load()
    threshold /= 100.0
    for y in xrange(h):
        for x in xrange(w):
            #find neighboring pixels
            neighbors =[(x+x2,y+y2) for x2 in xrange(-ws,ws) for y2 in xrange(-ws, ws) if x+x2>0 and x+x2<w and y+y2>0 and y+y2<h]
            #mean of all neighboring pixels
            mean = sum([l[a,b] for a,b in neighbors])/len(neighbors)
            if l[x, y] < threshold*mean:
                l2[x,y] = 0
            else:
                l2[x,y] = 255
    return image2

i = Image.open('test.jpg')
windowsize = 5
bradley_threshold(i, 75, windowsize).show()

windowsize较小且图像较小时,此方法工作得很好。我一直在使用这张图片进行测试:

当使用窗口大小为5的时候,我遇到了大约5到6秒的处理时间,但是如果我将窗口大小增加到20,并且算法在每个方向上检查20个像素的平均值,我就会得到该图像的时间超过1分钟。

如果我使用一个大小为2592x1936的图像,而窗口大小仅为5,则需要近10分钟才能完成。

那么,我该如何改善这些时间呢?numpy数组会更快吗?im.getpixel是否比将图像加载到像素访问模式更快?有没有其他的提速小贴士?提前谢谢。

EN

回答 2

Stack Overflow用户

发布于 2015-10-13 07:52:38

使用%prun在IPython中分析您的代码会产生如下结果:

代码语言:javascript
复制
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    50246    2.009    0.000    2.009    0.000 <ipython-input-78-b628a43d294b>:15(<listcomp>)
    50246    0.587    0.000    0.587    0.000 <ipython-input-78-b628a43d294b>:17(<listcomp>)
        1    0.170    0.170    2.829    2.829 <ipython-input-78-b628a43d294b>:5(bradley_threshold)
    50246    0.058    0.000    0.058    0.000 {built-in method sum}
    50257    0.004    0.000    0.004    0.000 {built-in method len}

也就是说,几乎所有的运行时间都是由Python循环(慢)和非向量化算法(慢)造成的。因此,如果您使用numpy数组重写,我希望会有很大的改进;或者,如果您不知道如何向量化您的代码,则可以使用cython。

票数 4
EN

Stack Overflow用户

发布于 2016-05-26 19:44:07

好的,我来晚了一点。不管怎样,让我分享一下我的想法:

你可以通过使用动态编程来计算均值来加速它,但是让scipy和numpy来做所有的脏活要容易得多,而且速度也快得多。(请注意,我在代码中使用了Python3,因此在代码中将xrange更改为range )。

代码语言:javascript
复制
#!/usr/bin/env python3

import numpy as np
from scipy import ndimage
from PIL import Image
import copy
import time

def faster_bradley_threshold(image, threshold=75, window_r=5):
    percentage = threshold / 100.
    window_diam = 2*window_r + 1
    # convert image to numpy array of grayscale values
    img = np.array(image.convert('L')).astype(np.float) # float for mean precision 
    # matrix of local means with scipy
    means = ndimage.uniform_filter(img, window_diam)
    # result: 0 for entry less than percentage*mean, 255 otherwise 
    height, width = img.shape[:2]
    result = np.zeros((height,width), np.uint8)   # initially all 0
    result[img >= percentage * means] = 255       # numpy magic :)
    # convert back to PIL image
    return Image.fromarray(result)

def bradley_threshold(image, threshold=75, windowsize=5):
    ws = windowsize
    image2 = copy.copy(image).convert('L')
    w, h = image.size
    l = image.convert('L').load()
    l2 = image2.load()
    threshold /= 100.0
    for y in range(h):
        for x in range(w):
            #find neighboring pixels
            neighbors =[(x+x2,y+y2) for x2 in range(-ws,ws) for y2 in range(-ws, ws) if x+x2>0 and x+x2<w and y+y2>0 and y+y2<h]
            #mean of all neighboring pixels
            mean = sum([l[a,b] for a,b in neighbors])/len(neighbors)
            if l[x, y] < threshold*mean:
                l2[x,y] = 0
            else:
                l2[x,y] = 255
    return image2

if __name__ == '__main__':
    img = Image.open('test.jpg')

    t0 = time.process_time()
    threshed0 = bradley_threshold(img)
    print('original approach:', round(time.process_time()-t0, 3), 's')
    threshed0.show()

    t0 = time.process_time()
    threshed1 = faster_bradley_threshold(img)
    print('w/ numpy & scipy :', round(time.process_time()-t0, 3), 's')
    threshed1.show()

这使得它在我的机器上运行得更快:

代码语言:javascript
复制
$ python3 bradley.py 
original approach: 3.736 s
w/ numpy & scipy : 0.003 s

注:请注意,我在scipy中使用的均值在边界上的表现与您的代码中的均值略有不同(对于均值计算窗口不再完全包含在图像中的位置)。然而,我认为这不应该是一个问题。

另一个较小的区别是,来自for循环的窗口并不完全位于像素的中心,因为xrange(-ws,ws)与ws=5的偏移量产生-5,-4-,...,3,4,并导致平均值为-0.5。这可能不是故意的。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33091755

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档