如何将PIL图像转换为numpy数组?


256

好吧,我想将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()方法,但似乎无法使其正常工作。


6
请注意,pic.size[0]pic.size[1]应被交换(即reshape(pic.size[1], pic.size[0], 3)),因为sizewidth x heightx * y,当矩阵排序rows x columns

Answers:


286

您并不是在说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开始,在图像和numpy数组之间进行转换“正确”方法很简单

>>> pix = numpy.array(pic)

尽管结果数组的格式与您的格式不同(在这种情况下为3维数组或行/列/ rgb)。

然后,在对阵列进行更改之后,您应该可以执行任一操作pic.putdata(pix)或使用创建新图像Image.fromarray(pix)


2
首先,它不应该是pic.putdata(data)吗?并且numpy.asarray(pic)产生一个只读数组,因此您需要调用numpy.array(pic),但您没有回答这个问题...从您提供的链接中可以看到pic = Image.fromarray( pix)。修正您的答案,我会接受。
akdom

2
谢谢。。。Image.fromarray未在PIL文档中列出(!),所以如果不是这个原因,我将永远找不到。
内森·里德

13
该页面列出numpy.asarray(pic)了“正确”的转换方式,而不是numpy.array(pic)。按照这个答案 array将复制,而asarray不会(但是asarray结果将是只读的)。
亚瑟·塔卡

1
警告(由于我自己的错误):您还需要考虑数据的规模和范围。在许多用例中,您会渲染0-255字节的图像,但是您可能希望它们在numpy数组中转换为例如0.0-1.0。一些来自uint8的单位转换可以做到这一点,但是在这种情况下,它就没有..所以检查一下:)
BjornW

第二个答案更好。
内森

193

I以数组形式打开:

>>> I = numpy.asarray(PIL.Image.open('test.jpg'))

对进行一些处理I,然后将其转换回图像:

>>> im = PIL.Image.fromarray(numpy.uint8(I))

使用FFT,Python过滤numpy图像

如果出于某种原因要明确地执行此操作,则此页面上的correlation.zip中有使用getdata()的pil2array()和array2pil()函数。


2
@ArditS .:您是import Image第一个吗?您是否已安装PIL?
endlith 2013年

5
uint8转换是否必要?
尼尔·特拉夫特

4
numpy.asarray(Image.open(filename))似乎适用于.jpg图像,但不适用于.png。结果显示为array(<PngImagePlugin.PngImageFile image mode=LA size=500x500 at 0x3468198>, dtype=object)。该对象似乎没有明显命名的方法PngImagePlugin.PngImageFile来解决此问题。猜猜我应该将其作为一个新问题提出,但这与该主题非常相关。有人知道这是怎么回事吗?
jez 2015年

3
@Rebs:这里的原因,为什么这是如此之快:getdata()返回状物体(序列pillow.readthedocs.io/en/3.4.x/reference/...),但枕头形象实现了__array_interface__numpy可用来访问原始字节无需通过迭代器即可查看图像(请参见github.com/python-pillow/Pillow/blob/…docs.scipy.org/doc/numpy/reference/arrays.interface.html)。您甚至可以使用numpy.array(PIL.Image.open('test.jpg'))
tdp2110

3
@jez在将Image对象转换为numpy之前,请检查其是否关闭。同样的事情发生在我身上,我发现我在某个地方关闭了图像对象。
李少华

64

我在Python 3.5中使用Pillow 4.1.1(PIL的后继产品)。枕头和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)

需要注意的一件事是,枕头样式im是专栏为主的,而numpy 样式是专栏的im2arr。但是,该功能Image.fromarray已经考虑了这一点。即,arr2im.size == im.sizearr2im.mode == im.mode在上面的例子。

在处理转换后的numpy数组时,例如在进行转换im2arr = np.rollaxis(im2arr, 2, 0)im2arr = np.transpose(im2arr, (2, 0, 1))转换为CxHxW格式时,我们应注意HxWxC数据格式。


2
这是关于最干净的示例,其中包括import语句(感谢您提供详细信息)。让我们对这个答案进行投票以提高知名度。
戴维·帕克斯

我发现,当我将PIL绘制的图像转换为numpy数组时,在该数组上使用matplotlib imshow时,它颠倒了,需要np.flipud进行修复。尽管我的PIL映像是使用从头开始创建的ImageDraw.Draw。我认为必须小心其坐标的原点。
CMCDragonkai

祝福你!!我一直在寻找这个答案半天。它解决了我将绘图图像后的原始轴恢复为原始轴的问题。
叮当

16

您需要通过以下方式将图像转换为numpy数组:

import numpy
import PIL

img = PIL.Image.open("foo.jpg").convert("L")
imgarr = numpy.array(img) 

这种转换方式可以保留图像,但会导致颜色损失。无论如何要避免颜色损失?
Moondra's

7
@moondra如果我理解您的问题,则可以替换.convert("L") .convert("RGB")
Billal Begueradj

3

我今天使用的示例:

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)

0

如果图像以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])


-1
def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

您可以通过在压缩特征后将图像解析为numpy()函数来将图像转换为numpy(非规范化)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.