如何将 PIL 图像转换为 numpy 数组?
Posted
技术标签:
【中文标题】如何将 PIL 图像转换为 numpy 数组?【英文标题】:How to convert a PIL Image into a numpy array? 【发布时间】:2010-09-27 22:31:19 【问题描述】:好的,我正在尝试将 PIL 图像对象来回转换为 numpy 数组,这样我可以进行比 PIL 的 PixelAccess
对象允许的更快的逐像素转换。我已经想出了如何通过以下方式将像素信息放置在有用的 3D numpy 数组中:
pic = Image.open("foo.jpg")
pix = numpy.array(pic.getdata()).reshape(pic.size[0], pic.size[1], 3)
但是在我完成了所有很棒的转换之后,我似乎无法弄清楚如何将它加载回 PIL 对象中。我知道 putdata()
方法,但似乎无法让它发挥作用。
【问题讨论】:
请注意pic.size[0]
和pic.size[1]
应该交换(即reshape(pic.size[1], pic.size[0], 3)
),因为size
是width x height
或x * y
,而矩阵排序是rows x columns
。
【参考方案1】:
你并不是说putdata()
的行为不正常。我假设你在做
>>> pic.putdata(a)
Traceback (most recent call last):
File "...blablabla.../PIL/Image.py", line 1185, in putdata
self.im.putdata(data, scale, offset)
SystemError: new style getargs format but argument is not a tuple
这是因为putdata
需要一个元组序列,而你给它一个 numpy 数组。这个
>>> data = list(tuple(pixel) for pixel in pix)
>>> pic.putdata(data)
可以,但速度很慢。
从 PIL 1.1.6 开始,"proper" way to convert between images and numpy arrays 很简单
>>> pix = numpy.array(pic)
尽管结果数组的格式与您的不同(在本例中为 3-d 数组或行/列/rgb)。
然后,在对数组进行更改后,您应该可以使用pic.putdata(pix)
或使用Image.fromarray(pix)
创建新图像。
【讨论】:
首先,不应该是pic.putdata(data)吗?并且 numpy.asarray(pic) 会生成一个只读数组,因此您需要调用 numpy.array(pic),而您没有回答问题...从您提供的链接来看,它似乎是 pic = Image.fromarray(像素)。修正你的答案,我会接受的。 感谢...Image.fromarray
没有在 PIL 文档中列出 (!) 所以如果不是因为这个,我永远不会找到它。
该页面将numpy.asarray(pic)
列为“正确”的转换方式,而不是numpy.array(pic)
。根据this answer array
将复制而asarray
不会(但随后asarray
结果将是只读的)。
这里有一个警告(来自我自己的错误):您还需要考虑数据的规模和范围。在许多用例中,您会使用 0-255 字节渲染图像,但您可能希望这些图像在 numpy 数组中转换为例如 0.0-1.0。来自 uint8 的一些单位转换可以做到这一点,但在这种情况下,它不会......所以检查一下 :)
第二个答案更好。【参考方案2】:
以数组形式打开I
:
>>> I = numpy.asarray(PIL.Image.open('test.jpg'))
对I
做一些处理,然后将其转换回图像:
>>> im = PIL.Image.fromarray(numpy.uint8(I))
来源:Filter numpy images with FFT, Python
如果您出于某种原因想要明确地执行此操作,有 pil2array() 和 array2pil() 函数使用 getdata() on this page in correlation.zip。
【讨论】:
@ArditS.: 你是先import Image
吗?你有安装 PIL 吗?
是否需要uint8
转换?
numpy.asarray(Image.open(filename))
似乎适用于 .jpg 图像,但不适用于 .png。结果显示为array(<PngImagePlugin.PngImageFile image mode=LA size=500x500 at 0x3468198>, dtype=object)
。 PngImagePlugin.PngImageFile
对象似乎没有明显命名的方法来解决这个问题。我想我应该将此作为一个新问题提出,但这与该线程非常相关。有人知道这里出了什么问题吗?
@Rebs:这就是 why 这么快的原因:getdata()
返回一个类似对象的序列 (pillow.readthedocs.io/en/3.4.x/reference/…),但枕头图像实现了 @987654336 @ 其中numpy
可以用来访问图像的原始字节,而无需通过迭代器(参见github.com/python-pillow/Pillow/blob/… 和docs.scipy.org/doc/numpy/reference/arrays.interface.html)。你甚至可以只使用numpy.array(PIL.Image.open('test.jpg'))
@jez 在将 Image 对象转换为 numpy 之前检查它是否已关闭。同样的事情发生在我身上,我发现我在某个地方关闭了图像对象。【参考方案3】:
我在 Python 3.5 中使用 Pillow 4.1.1(PIL 的继任者)。 Pillow 和 numpy 之间的转换很简单。
from PIL import Image
import numpy as np
im = Image.open('1.jpg')
im2arr = np.array(im) # im2arr.shape: height x width x channel
arr2im = Image.fromarray(im2arr)
需要注意的一点是 Pillow 风格的 im
是列优先的,而 numpy 风格的 im2arr
是行优先的。但是,函数Image.fromarray
已经考虑到了这一点。也就是上面例子中的arr2im.size == im.size
和arr2im.mode == im.mode
。
在处理转换后的 numpy 数组时,我们应该注意 HxWxC 数据格式,例如将im2arr = np.rollaxis(im2arr, 2, 0)
或im2arr = np.transpose(im2arr, (2, 0, 1))
转换为CxHxW 格式。
【讨论】:
这是关于最简洁的示例,包括导入语句(感谢您提供的详细信息)。让我们对此答案进行投票以提高知名度。 我发现当我将 PIL 绘制的图像转换为 numpy 数组时,在数组上使用 matplotlib imshow 时,它显示它颠倒了,需要np.flipud
来修复。虽然我的 PIL 图像是使用 ImageDraw.Draw
从头开始创建的。我认为必须小心他们的坐标原点来自哪里。
祝福你!!这个答案找了半天。它解决了我将绘图图像恢复到原始轴后的原始轴的问题。【参考方案4】:
您需要通过这种方式将图像转换为 numpy 数组:
import numpy
import PIL
img = PIL.Image.open("foo.jpg").convert("L")
imgarr = numpy.array(img)
【讨论】:
这种转换方式会保留图像但会导致颜色丢失。无论如何要避免颜色损失? @moondra 如果我理解您的问题,您可以将.convert("L")
替换为.convert("RGB")
"L" 生成灰度图像【参考方案5】:
转换Numpy to PIL
图像和PIL to Numpy
import numpy as np
from PIL import Image
def pilToNumpy(img):
return np.array(img)
def NumpyToPil(img):
return Image.fromarray(img)
【讨论】:
【参考方案6】:我今天使用的例子:
import PIL
import numpy
from PIL import Image
def resize_image(numpy_array_image, new_height):
# convert nympy array image to PIL.Image
image = Image.fromarray(numpy.uint8(numpy_array_image))
old_width = float(image.size[0])
old_height = float(image.size[1])
ratio = float( new_height / old_height)
new_width = int(old_width * ratio)
image = image.resize((new_width, new_height), PIL.Image.ANTIALIAS)
# convert PIL.Image into nympy array back again
return array(image)
【讨论】:
【参考方案7】:如果您的图像以 Blob 格式存储(即在数据库中),您可以使用 Billal Begueradj 解释的相同技术将图像从 Blob 转换为字节数组。
就我而言,我需要将图像存储在 db 表的 blob 列中:
def select_all_X_values(conn):
cur = conn.cursor()
cur.execute("SELECT ImageData from PiecesTable")
rows = cur.fetchall()
return rows
然后我创建了一个辅助函数来将我的数据集更改为 np.array:
X_dataset = select_all_X_values(conn)
imagesList = convertToByteIO(np.array(X_dataset))
def convertToByteIO(imagesArray):
"""
# Converts an array of images into an array of Bytes
"""
imagesList = []
for i in range(len(imagesArray)):
img = Image.open(BytesIO(imagesArray[i])).convert("RGB")
imagesList.insert(i, np.array(img))
return imagesList
之后,我可以在我的神经网络中使用 byteArrays。
plt.imshow(imagesList[0])
【讨论】:
【参考方案8】:def imshow(img):
img = img / 2 + 0.5 # unnormalize
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()
您可以将图像转换为 numpy 通过在挤出特征(非标准化)后将图像解析为 numpy() 函数
【讨论】:
这是用于 numpy 和张量之间的转换,例如火炬。这个问题是关于 PIL 的。以上是关于如何将 PIL 图像转换为 numpy 数组?的主要内容,如果未能解决你的问题,请参考以下文章