jak przekonwertować obraz RGB na tablicę numpy?

113

Mam obraz RGB. Chcę przekonwertować go na tablicę numpy. Zrobiłem co następuje

im = cv.LoadImage("abc.tiff")
a = numpy.asarray(im)

Tworzy tablicę bez kształtu. Zakładam, że jest to obiekt iplimage.

Shan
źródło
2
Jeśli cvjest to moduł OpenCV, powinieneś oznaczyć go jako taki. Ten link może pomóc: opencv.willowgarage.com/documentation/python/ ...
Paul

Odpowiedzi:

142

Możesz użyć nowszego interfejsu Pythona OpenCV (jeśli się nie mylę, jest dostępny od OpenCV 2.2). Natywnie używa tablic numpy:

import cv2
im = cv2.imread("abc.tiff",mode='RGB')
print type(im)

wynik:

<type 'numpy.ndarray'>
Andrey Kamaev
źródło
95
Uważaj, cv2.imread () zwraca tablicę numpy w BGR, a nie w RGB.
2017
6
@pnd Twój komentarz jest święty!
Eduardo Pignatelli
4
Na przyszłość: $ pip install opencv-pythonaby zainstalować opencv
Kyle C
2
TypeError: 'mode' is an invalid keyword argument for imread()
Rishabh Agrahari
8
Wydaje się, że OpenCV porzucił modeargument. Zobacz moją odpowiedź poniżej, aby uzyskać zaktualizowaną metodę.
belvederef
73

PIL (Python Imaging Library) i Numpy dobrze ze sobą współpracują.

Używam następujących funkcji.

from PIL import Image
import numpy as np

def load_image( infilename ) :
    img = Image.open( infilename )
    img.load()
    data = np.asarray( img, dtype="int32" )
    return data

def save_image( npdata, outfilename ) :
    img = Image.fromarray( np.asarray( np.clip(npdata,0,255), dtype="uint8"), "L" )
    img.save( outfilename )

„Image.fromarray” jest trochę brzydki, ponieważ przycinam przychodzące dane do [0,255], konwertuję na bajty, a następnie tworzę obraz w skali szarości. Pracuję głównie w kolorze szarym.

Obraz RGB wyglądałby tak:

 outimg = Image.fromarray( ycc_uint8, "RGB" )
 outimg.save( "ycc.tif" )
David Poole
źródło
1
To kończy się błędem TypeError: long() argument must be a string or a number, not 'PixelAccess'i patrząc na dokumentację PixelAccessklasy PIL , nie wydaje się, aby zawierała ona metody, które umożliwiłyby np.arraykonwersję danych źródłowych do ndarrayformatu. Musisz pominąć użycie img.load()i zająć się tylko wynikiem Image.open(...).
ely
Img.load () rozwiązuje dziwny problem z buforowaniem w PIL. Dane nie zostaną załadowane, dopóki nie będą wyraźnie potrzebne. Przykład nadal działa dla mnie z wyjątkiem zmiany opcji „import Image” na „from PIL import Image” podczas pracy z Pillow (widelcem PIL).
David Poole
Głosuj za użyciem tylko PIL, a nie OpenCV. Nie jestem jednak przeciwny OpenCV.
progyammer
54

Możesz również użyć do tego matplotlib .

from matplotlib.image import imread

img = imread('abc.tiff')
print(type(img))

wynik: <class 'numpy.ndarray'>

Rishabh Agrahari
źródło
2
To jest bardzo proste. Podoba mi się :)
jeongmin.cha
@Mrinal Tak, to prawda.
Rishabh Agrahari
19

Na dzień dzisiejszy najlepiej jest użyć:

img = cv2.imread(image_path)   # reads an image in the BGR format
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)   # BGR -> RGB

Zobaczysz imgtablicę numpy typu:

<class 'numpy.ndarray'>
belvederef
źródło
12

Późna odpowiedź, ale wolę imageiomoduł od innych alternatyw

import imageio
im = imageio.imread('abc.tiff')

Podobnie jak cv2.imread()domyślnie tworzy tablicę numpy, ale w postaci RGB.

slizb
źródło
7

Musisz użyć cv.LoadImageM zamiast cv.LoadImage:

In [1]: import cv
In [2]: import numpy as np
In [3]: x = cv.LoadImageM('im.tif')
In [4]: im = np.asarray(x)
In [5]: im.shape
Out[5]: (487, 650, 3)
Justin Peel
źródło
Wielkie dzięki ... Czy mógłbyś mi również pomóc dowiedzieć się, że jeśli utworzę obraz za pomocą 'cv.CreateImage (szerokość, wysokość, kanały)' ... Jak można go przekonwertować na tablicę numpy?
Shan
Myślę, że musisz zamiast tego użyć cv.CreateMat lub cv.CreateMat i skopiować z obrazu na matę za pomocą cv.CvtColor lub czegoś podobnego. Spójrz na link, który Paul zamieścił powyżej.
Justin Peel,
3

Korzystając z odpowiedzi Davida Poole'a, otrzymuję błąd SystemError z plikami PNG w skali szarości i być może innymi plikami. Moje rozwiązanie to:

import numpy as np
from PIL import Image

img = Image.open( filename )
try:
    data = np.asarray( img, dtype='uint8' )
except SystemError:
    data = np.asarray( img.getdata(), dtype='uint8' )

Właściwie img.getdata () działałoby dla wszystkich plików, ale jest wolniejsze, więc używam go tylko wtedy, gdy inna metoda zawodzi.

daign
źródło
2

Format obrazu OpenCV obsługuje interfejs tablicy numpy. Można utworzyć funkcję pomocniczą obsługującą obrazy w skali szarości lub kolorowe. Oznacza to, że konwersja BGR -> RGB może być wygodnie wykonana za pomocą numpy plaster, a nie pełnej kopii danych obrazu.

Uwaga: jest to sztuczka krokowa, więc modyfikacja tablicy wyjściowej spowoduje również zmianę danych obrazu OpenCV. Jeśli chcesz kopię, użyj .copy()metody na tablicy!

import numpy as np

def img_as_array(im):
    """OpenCV's native format to a numpy array view"""
    w, h, n = im.width, im.height, im.channels
    modes = {1: "L", 3: "RGB", 4: "RGBA"}
    if n not in modes:
        raise Exception('unsupported number of channels: {0}'.format(n))
    out = np.asarray(im)
    if n != 1:
        out = out[:, :, ::-1]  # BGR -> RGB conversion
    return out
wim
źródło
1

Przyjąłem również imageio, ale znalazłem następujące maszyny przydatne do przetwarzania wstępnego i końcowego:

import imageio
import numpy as np

def imload(*a, **k):
    i = imageio.imread(*a, **k)
    i = i.transpose((1, 0, 2))  # x and y are mixed up for some reason...
    i = np.flip(i, 1)  # make coordinate system right-handed!!!!!!
    return i/255


def imsave(i, url, *a, **k):
    # Original order of arguments was counterintuitive. It should
    # read verbally "Save the image to the URL" — not "Save to the
    # URL the image."

    i = np.flip(i, 1)
    i = i.transpose((1, 0, 2))
    i *= 255

    i = i.round()
    i = np.maximum(i, 0)
    i = np.minimum(i, 255)

    i = np.asarray(i, dtype=np.uint8)

    imageio.imwrite(url, i, *a, **k)

Powodem jest to, że używam numpy do przetwarzania obrazu, a nie tylko do wyświetlania obrazu. W tym celu uint8 są niewygodne, więc konwertuję na wartości zmiennoprzecinkowe z zakresu od 0 do 1.

Podczas zapisywania obrazów zauważyłem, że musiałem sam wyciąć wartości spoza zakresu, w przeciwnym razie otrzymałem naprawdę szary wynik. (Szary wynik był wynikiem kompresji imageio pełnego zakresu, który był poza [0, 256), do wartości znajdujących się w tym zakresie).

Było też kilka innych dziwactw, o których wspomniałem w komentarzach.

enigmatyczny fizyk
źródło
1

Możesz łatwo uzyskać tablicę numpy obrazu rgb używając numpyiImage from PIL

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

im = Image.open('*image_name*') #These two lines
im_arr = np.array(im) #are all you need
plt.imshow(im_arr) #Just to verify that image array has been constructed properly
joker007
źródło
0

załaduj obraz, używając następującej składni: -

from keras.preprocessing import image

X_test=image.load_img('four.png',target_size=(28,28),color_mode="grayscale"); #loading image and then convert it into grayscale and with it's target size 
X_test=image.img_to_array(X_test); #convert image into array
Disha Doshi
źródło