Python、Numpy 堆栈溢出

标签 python image-processing numpy stack-overflow

我正在尝试在 python 中进行一些图像操作,但我在堆栈溢出方面遇到了一些麻烦。阅读了一些内容后,我编辑了 np.array 以获取额外的参数 dtype='int64'。 (之前工作得很好,前提是我没有调用阈值方法)

这解决了异常错误,但是当我尝试绘制图像来绘制它时,它不起作用。也不异常(exception),它什么也没绘制。该错误不在阈值方法中,因为即使我将其注释掉并运行它,它仍然不会绘制。你知道我做错了什么吗?

完整代码如下:

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()

最佳答案

我不知道为什么 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,其条目是每个像素的前三个 channel 的平均值。您可以通过循环图像中的每个像素来完成此操作。但是,当您可以对代码进行向量化并在一次操作中计算所有像素的结果时,NumPy 的效率最高。在这种情况下,您可以使用 NumPy's fancy indexing获取图像的前三个 channel :

    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. 在下一组行中,将图像中平均颜色 channel 高于平衡的像素替换为白色,将低于平均颜色 channel 的像素替换为黑色。同样,您应该向量化此操作。您可以计算一个掩码数组,这是一个对于高于平均值的像素为True的 bool 数组:

    mask = balanceAr > balance
    

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

    result = np.empty(imageArray.shape)
    

    将蒙版中的像素设置为白色,将其他像素设置为黑色:

    result[mask] = (255, 255, 255, 255)
    result[~mask] = (0, 0, 0, 255)
    
  5. 更仔细地考虑这个算法,很明显您实际上不需要取颜色 channel 的平均值。除以 3 总是相同的,因此可以简单地省略它,并且我们可以使用颜色 channel 的总和来代替。 (调用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. 图像颜色 channel 的总和有点像 luminance图像的不同之处在于它没有考虑对 channel 的不同生理 react (绿色被认为比红色更亮,而红色被认为比蓝色更亮)。也许您应该使用 0.2126 R + 0.7152 G + 0.0722 B 而不是 R + G + B

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

    # 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
    

关于Python、Numpy 堆栈溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22082602/

相关文章:

python - math.fsum 用于多维数组

python - 按百分位数对 python 字典进行排名

python - 在 AWS Lambda 中访问 GET 参数

python - 异步 SQLite python

algorithm - 将RGB图像读入二进制并在Matlab中显示为RGB

image-processing - FFMPEG:图像/视频的色度键/绿屏过滤器

python - Multiprocessing Manager().dict() 更新失败

python - 文本文件中的整数值未更改

Kinect 游戏的图像转换

arrays - numpy.array(list) 很慢