【问题标题】:How to convert a PIL Image into a numpy array?如何将 PIL 图像转换为 numpy 数组?
【发布时间】: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)),因为sizewidth x heightx * y,而矩阵排序是rows x columns

标签: python image numpy python-imaging-library numpy-ndarray


【解决方案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.sizearr2im.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 的。
        猜你喜欢
        • 2017-06-25
        • 2019-11-29
        • 2021-12-09
        • 1970-01-01
        • 1970-01-01
        • 2012-06-13
        • 2020-02-17
        • 2011-02-15
        • 1970-01-01
        相关资源
        最近更新 更多