Làm cách nào để chuyển đổi một hình ảnh PIL thành một mảng numpy?


257

Được rồi, tôi đang đùa giỡn với việc chuyển đổi một đối tượng hình ảnh PIL qua lại thành một mảng gọn gàng để tôi có thể thực hiện một số pixel nhanh hơn bằng cách chuyển đổi pixel so với PixelAccessđối tượng của PIL cho phép. Tôi đã tìm ra cách đặt thông tin pixel vào một mảng gọn gàng 3D hữu ích bằng cách:

pic = Image.open("foo.jpg")
pix = numpy.array(pic.getdata()).reshape(pic.size[0], pic.size[1], 3)

Nhưng dường như tôi không thể tìm ra cách tải nó trở lại vào đối tượng PIL sau khi tôi đã thực hiện tất cả các biến đổi tuyệt vời của mình. Tôi biết putdata()phương pháp này, nhưng dường như không thể khiến nó hành xử.


6
Lưu ý rằng pic.size[0]pic.size[1]nên được hoán đổi (ví dụ. reshape(pic.size[1], pic.size[0], 3)), Vì sizewidth x heighthoặc x * y, trong khi thứ tự ma trận là rows x columns.
sương mù

Câu trả lời:


286

Bạn không nói chính xác putdata()là không cư xử. Tôi cho rằng bạn đang làm

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

Điều này là do putdatamong đợi một chuỗi các bộ dữ liệu và bạn đang cung cấp cho nó một mảng gọn gàng. Điều này

>>> data = list(tuple(pixel) for pixel in pix)
>>> pic.putdata(data)

sẽ làm việc nhưng nó rất chậm.

Kể từ PIL 1.1.6, cách "thích hợp" để chuyển đổi giữa các hình ảnh và mảng numpy chỉ đơn giản là

>>> pix = numpy.array(pic)

mặc dù mảng kết quả có định dạng khác với mảng của bạn (mảng 3-d hoặc hàng / cột / rgb trong trường hợp này).

Sau đó, sau khi bạn thực hiện các thay đổi cho mảng, bạn sẽ có thể thực hiện pic.putdata(pix)hoặc tạo một hình ảnh mới với Image.fromarray(pix).


2
Đầu tiên, không nên là pic.putdata (dữ liệu)? Và numpy.asarray (pic) tạo ra một mảng chỉ đọc, vì vậy bạn cần gọi numpy.array (pic) và bạn đã không trả lời câu hỏi ... từ liên kết mà bạn cung cấp có vẻ là pic = Image.fromarray ( pix). Sửa câu trả lời của bạn và tôi sẽ chấp nhận nó.
akdom

2
Cảm ơn vì điều này ... Image.fromarraykhông được liệt kê trong tài liệu PIL (!) Vì vậy tôi chưa bao giờ tìm thấy nó nếu nó không dành cho việc này.
Nathan Reed

13
Trang đó liệt kê numpy.asarray(pic)là cách "thích hợp" để chuyển đổi, không numpy.array(pic). Theo câu trả lời array này sẽ tạo một bản sao trong khi asarraysẽ không (nhưng sau đó asarraykết quả sẽ chỉ đọc).
Arthur Tacca

1
Một cảnh báo ở đây (từ sai lầm của riêng tôi): bạn cũng cần xem xét quy mô và phạm vi của dữ liệu. Trong nhiều giai đoạn bạn sẽ kết xuất hình ảnh với 0-255 byte, nhưng bạn có thể mong đợi những hình ảnh này sẽ được chuyển đổi thành ví dụ 0,0-1,0 trong mảng numpy. Một số chuyển đổi đơn vị từ uint8 thực hiện điều này, nhưng trong trường hợp này, nó không .. vì vậy hãy kiểm tra nó :)
BjornW

Câu trả lời thứ hai là tốt hơn.
Nathan

193

Mở Idưới dạng một mảng:

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

ISau đó, thực hiện một số nội dung để chuyển đổi nó thành hình ảnh:

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

Lọc các hình ảnh lộn xộn với FFT, Python

Nếu bạn muốn làm điều đó một cách rõ ràng vì một số lý do, có các hàm pil2array () và Array2pil () sử dụng getdata () trên trang này trong tệp tương quan.zip .


2
@ArditS.: Bạn đã import Imageđầu tiên? Bạn đã cài đặt PIL chưa?
endolith

5
uint8chuyển đổi cần thiết?
Neil Traft

4
numpy.asarray(Image.open(filename))dường như hoạt động cho hình ảnh .jpg nhưng không phải cho .png. Kết quả hiển thị như array(<PngImagePlugin.PngImageFile image mode=LA size=500x500 at 0x3468198>, dtype=object). Dường như không có phương pháp được đặt tên rõ ràng của PngImagePlugin.PngImageFileđối tượng để giải quyết điều này. Đoán tôi nên hỏi đây là một câu hỏi mới nhưng nó rất phù hợp với chủ đề này. Có ai hiểu chuyện gì đang xảy ra ở đây không?
Jez

3
@Rebs: đây là lý do tại sao điều này là để nhanh hơn nhiều: getdata()trả về một chuỗi như đối tượng ( pillow.readthedocs.io/en/3.4.x/reference/... ), nhưng một hình ảnh gối cụ các __array_interface__numpycó thể sử dụng để truy cập vào các byte thô của một hình ảnh mà không phải thông qua một trình vòng lặp (xem github.com/python-pfl/Pvel/blob/ và và docs.scipy.org / doc / numpy / report / narays.interface.html ). Bạn thậm chí có thể chỉ cần sử dụngnumpy.array(PIL.Image.open('test.jpg'))
tdp2110

3
@jez Kiểm tra xem đối tượng Image có bị đóng không trước khi bạn chuyển đổi nó thành numpy. Điều tương tự cũng xảy ra với tôi và tôi thấy tôi đã đóng đối tượng hình ảnh ở đâu đó.
Shaohua Li

65

Tôi đang sử dụng Gối 4.1.1 (sự kế thừa của PIL) trong Python 3.5. Việc chuyển đổi giữa Gối và numpy rất đơn giản.

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)

Một điều cần chú ý là kiểu Gối imlà cột chính trong khi kiểu numpy im2arrlà hàng chính. Tuy nhiên, chức năng Image.fromarrayđã xem xét điều này. Đó là, arr2im.size == im.sizearr2im.mode == im.modetrong ví dụ trên.

Chúng ta nên quan tâm đến định dạng dữ liệu HxWxC khi xử lý các mảng numpy được chuyển đổi, ví dụ: thực hiện chuyển đổi im2arr = np.rollaxis(im2arr, 2, 0)hoặc im2arr = np.transpose(im2arr, (2, 0, 1))thành định dạng CxHxW.


2
Đây là về ví dụ rõ ràng nhất, bao gồm các báo cáo nhập khẩu (cảm ơn vì chi tiết đó). Hãy bỏ phiếu cho câu trả lời này để tăng khả năng hiển thị.
David

Tôi thấy rằng khi tôi chuyển đổi một hình ảnh được vẽ PIL thành một mảng numpy, khi sử dụng matplotlib imshow trên mảng, nó cho thấy nó bị lộn ngược đòi hỏi np.flipudphải sửa. Mặc dù hình ảnh PIL của tôi đã được tạo từ đầu bằng cách sử dụng ImageDraw.Draw. Tôi nghĩ người ta phải cẩn thận nguồn gốc tọa độ của chúng đến từ đâu.
CMCDragonkai

Ban phước cho bạn !! Tôi đã tìm kiếm câu trả lời này trong nửa ngày. Nó giải quyết vấn đề của tôi về việc khôi phục trục ban đầu sau hình ảnh cốt truyện về hình gốc.
Tinkerbell

16

Bạn cần chuyển đổi hình ảnh của mình thành một mảng khó hiểu theo cách này:

import numpy
import PIL

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

Cách chuyển đổi này giữ lại hình ảnh nhưng dẫn đến mất màu. Dù sao để tránh mất màu?
Moondra

7
@moondra Nếu tôi hiểu câu hỏi của bạn, bạn có thể thay thế .convert("L") bằng.convert("RGB")
Billal Begueradj

3

Ví dụ, tôi đã sử dụng ngày hôm nay:

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

Nếu hình ảnh của bạn được lưu trữ ở định dạng Blob (tức là trong cơ sở dữ liệu), bạn có thể sử dụng kỹ thuật tương tự được Billal Begueradj giải thích để chuyển đổi hình ảnh của bạn từ Blobs sang một mảng byte.

Trong trường hợp của tôi, tôi cần hình ảnh của mình được lưu trữ trong cột blob trong bảng db:

def select_all_X_values(conn):
    cur = conn.cursor()
    cur.execute("SELECT ImageData from PiecesTable")    
    rows = cur.fetchall()    
    return rows

Sau đó tôi đã tạo một hàm trợ giúp để thay đổi tập dữ liệu của mình thành 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

Sau này, tôi đã có thể sử dụng byteArrays trong Mạng thần kinh của mình.

plt.imshow(imagesList[0])

0

Chuyển đổi Numpy to PILhình ảnh và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)

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

Bạn có thể chuyển đổi hình ảnh thành numpy bằng cách phân tích hình ảnh thành hàm numpy () sau khi loại bỏ các tính năng (không chuẩn hóa)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.