Python,Numpy Stack溢出

时间:2014-02-27 23:04:26

标签: python image-processing numpy stack-overflow

我正在尝试在python中进行一些图像处理,但是我遇到了堆栈溢出的问题。读了一下之后,我编辑了np.array以获取额外的参数dtype ='int64'。 (之前它工作正常,前提是我没有调用阈值方法)

这解决了异常错误,但是当我尝试绘制图像以绘制它时,它不起作用。也不例外,它只是一无所获。错误不在阈值方法中,因为即使我将其注释掉并运行它,它仍然没有绘制。我有什么想法吗?

以下完整代码:

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import time
import math

def threshold(imageArray):
     balanceAr = []
     newArray = imageArray


     for eachRow in imageArray:
         for eachPix in eachRow:
            avgNum = reduce(lambda x, y: x + y, eachPix[:3])/float(len(eachPix[:3]))
            balanceAr.append(avgNum)

     balance = reduce(lambda x , y: x + y , eachPix[:3]/float(len(balanceAr)))

    for eachRow in newArray:
         for eachPix in eachRow:
            if reduce(lambda x , y: x + y, eachPix[:3])/float(len(eachPix[:3])) > balance:
                eachPix[0] = 255
                eachPix[1] = 255
                eachPix[2] = 255
                eachPix[3] = 255
            else:
                eachPix[0] = 0
                eachPix[1] = 0
                eachPix[2] = 0
                eachPix[3] = 255


y = Image.open('images/numbers/y0.5.png')
yar = np.asarray(y, dtype='int64')

threshold(yar)


fig = plt.figure()
ax3 = plt.subplot2grid((8,6), (0,3), rowspan=4, colspan=3)

ax3.imshow(yar)

plt.show()

1 个答案:

答案 0 :(得分:3)

我不知道为什么MatPlotLib不会绘制你的图像,但我可以告诉你threshold函数的一些问题。

  1. 您编写newArray = imageArray但这只是意味着newArray是同一数组的另一个名称。这意味着您的threshold函数会覆盖原始图像,这可能非常不方便(特别是在测试时)。您可能需要获取图像的副本:

    newArray = imageArray.copy()
    
  2. 在这组内容中:

    balanceAr = []
    for eachRow in imageArray:
        for eachPix in eachRow:
            avgNum = reduce(lambda x, y: x + y, eachPix[:3])/float(len(eachPix[:3]))
            balanceAr.append(avgNum)
    

    您正在计算(展平的)数组balanceAr,其条目是每个像素的前三个通道的平均值。您可以通过循环图像中的每个像素来实现此目的。但是,当您可以矢量化代码并在一次操作中计算所有像素的结果时,NumPy效率最高。在这种情况下,您可以使用NumPy's fancy indexing获取图像的前三个通道:

    colour_channels = imageArray[...,:3]
    

    然后调用numpy.mean获取每个像素的平均值:

    balanceAr = colour_channels.mean(axis=-1)
    

    (这构造了一个二维数组:如果你真的想要一个扁平版本,你可以调用flatten方法,但这不是必要的,我将在下面解释。)

  3. 在这一行:

    balance = reduce(lambda x , y: x + y , eachPix[:3]/float(len(balanceAr)))
    

    看起来好像你的目的是计算balanceAr的平均值,但是你搞砸了,只是将eachPix[:3]一个替换为balanceAr }}。显然,这会计算出错误的结果。

    当然,您需要的是:

    balance = balanceAr.mean()
    
  4. 在下一组线条中,您将平均颜色通道中的像素替换为白色的balance,将较低的平均值替换为黑色。同样,您应该对此操作进行矢量化。您可以计算掩码数组,对于高于平均值的像素,True的布尔数组:

    mask = balanceAr > balance
    

    构造一个合适大小的空图像:

    result = np.empty(imageArray.shape)
    

    将遮罩中的像素设置为白色,将其他像素设置为黑色:

    result[mask] = (255, 255, 255, 255)
    result[~mask] = (0, 0, 0, 255)
    
  5. 更仔细地考虑这个算法,很明显你实际上并不需要取颜色通道的平均值。除以3总是相同的,因此可以简单地省略,我们可以使用颜色通道的 sum 。 (拨打numpy.sum而不是numpy.mean。)

  6. 把所有这些放在一起,这是我编程的方式:

    import numpy as np
    
    WHITE = np.array((255, 255, 255, 255), dtype=np.uint8)
    BLACK = np.array((  0,   0,   0, 255), dtype=np.uint8)
    
    def threshold2(img, high=WHITE, low=BLACK):
        """Return a new image whose pixels are `high` where pixels in `img`
        have a higher sum of colour channels than the average for the
        image, and `low` elsewhere.
    
        """
        colsum = img[...,:3].sum(axis=-1)
        mask = colsum > colsum.mean()
        result = np.empty(img.shape, dtype=np.uint8)
        result[mask] = high
        result[~mask] = low
        return result
    

    这比您的代码快200倍:

    >>> from timeit import timeit
    >>> img = np.random.randint(0, 256, (400, 400, 4))
    >>> timeit(lambda:threshold2(img), number=1) # mine
    0.05198820028454065
    >>> timeit(lambda:threshold(img), number=1) # yours
    10.539333346299827
    
  7. 图像的颜色通道总和有点像图像的luminance,除了它没有考虑到对通道的不同生理反应(绿色被认为是比红色更明亮,被认为比蓝色更明亮。也许您应该使用0.2126 R + 0.7152 G + 0.0722 B 而不是 R + G < / EM> +

    如果这是对的,你需要这样的东西:

    # sRGB luminosity coefficients, plus 0 for the alpha channel
    LUMINOSITY = np.array((0.2126, 0.7152, 0.0722, 0))
    
    def threshold3(img, high=WHITE, low=BLACK, luminosity=LUMINOSITY):
        """Return a new image whose pixels are `high` where pixels in `img`
        have a higher luminance than the average for the image, and `low`
        elsewhere. The optional `luminosity` argument provides the
        multipliers for the red, green and blue channels.
    
        """
        luminance = (img * luminosity).sum(axis=-1)
        mask = luminance > luminance.mean()
        result = np.empty(img.shape, dtype=np.uint8)
        result[mask] = high
        result[~mask] = low
        return result