我正在尝试在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()
答案 0 :(得分:3)
我不知道为什么MatPlotLib不会绘制你的图像,但我可以告诉你threshold
函数的一些问题。
您编写newArray = imageArray
但这只是意味着newArray
是同一数组的另一个名称。这意味着您的threshold
函数会覆盖原始图像,这可能非常不方便(特别是在测试时)。您可能需要获取图像的副本:
newArray = imageArray.copy()
在这组内容中:
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
方法,但这不是必要的,我将在下面解释。)
在这一行:
balance = reduce(lambda x , y: x + y , eachPix[:3]/float(len(balanceAr)))
看起来好像你的目的是计算balanceAr
的平均值,但是你搞砸了,只是将eachPix[:3]
的一个替换为balanceAr
}}。显然,这会计算出错误的结果。
当然,您需要的是:
balance = balanceAr.mean()
在下一组线条中,您将平均颜色通道中的像素替换为白色的balance
,将较低的平均值替换为黑色。同样,您应该对此操作进行矢量化。您可以计算掩码数组,对于高于平均值的像素,True
的布尔数组:
mask = balanceAr > balance
构造一个合适大小的空图像:
result = np.empty(imageArray.shape)
将遮罩中的像素设置为白色,将其他像素设置为黑色:
result[mask] = (255, 255, 255, 255)
result[~mask] = (0, 0, 0, 255)
更仔细地考虑这个算法,很明显你实际上并不需要取颜色通道的平均值。除以3总是相同的,因此可以简单地省略,我们可以使用颜色通道的 sum 。 (拨打numpy.sum
而不是numpy.mean
。)
把所有这些放在一起,这是我编程的方式:
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
图像的颜色通道总和有点像图像的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