como converter uma imagem RGB para numpy array?

113

Eu tenho uma imagem RGB. Eu quero convertê-lo em matriz numpy. Eu fiz o seguinte

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

Ele cria uma matriz sem forma. Presumo que seja um objeto iplimage.

Shan
fonte
2
Se cvfor o módulo OpenCV, você deve marcá-lo como tal. Este link pode ajudar: opencv.willowgarage.com/documentation/python/…
Paul,

Respostas:

142

Você pode usar a interface python OpenCV mais recente (se não me engano, ela está disponível desde o OpenCV 2.2). Ele usa matrizes numpy nativamente:

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

resultado:

<type 'numpy.ndarray'>
Andrey Kamaev
fonte
94
Esteja ciente de que cv2.imread () retorna um array numpy em BGR e não em RGB.
PND
6
@pnd seu comentário é sagrado!
Eduardo Pignatelli
4
Para referência futura: $ pip install opencv-pythonpara instalar o opencv
Kyle C
2
TypeError: 'mode' is an invalid keyword argument for imread()
Rishabh Agrahari
8
OpenCV parece ter abandonado o modeargumento. Veja minha resposta abaixo para um método atualizado.
belvederef
73

PIL (Python Imaging Library) e Numpy funcionam bem juntos.

Eu uso as seguintes funções.

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 )

O 'Image.fromarray' é um pouco feio porque recortei os dados recebidos para [0,255], converti em bytes e, em seguida, crio uma imagem em tons de cinza. Eu trabalho principalmente em cinza.

Uma imagem RGB seria algo como:

 outimg = Image.fromarray( ycc_uint8, "RGB" )
 outimg.save( "ycc.tif" )
David Poole
fonte
1
Isso falha com um erro TypeError: long() argument must be a string or a number, not 'PixelAccess'e , examinando a documentação da PixelAccessclasse PIL , não parece oferecer métodos que permitiriam np.arrayconverter seus dados subjacentes em um ndarrayformato. Você precisa omitir o uso de img.load()e lidar apenas com o resultado de Image.open(...).
ely
O img.load () contorna um problema estranho de cache no PIL. Os dados não seriam carregados até que fossem explicitamente necessários. O exemplo ainda funciona para mim, com exceção de alterar "import Image" para "from PIL import Image" ao trabalhar com Pillow (o fork PIL).
David Poole
Voto positivo para usar apenas PIL e não OpenCV. Não sou contra o OpenCV.
progyammer
54

Você também pode usar matplotlib para isso.

from matplotlib.image import imread

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

resultado: <class 'numpy.ndarray'>

Rishabh Agrahari
fonte
2
Isso é muito simples. Eu gosto :)
jeongmin.cha
@Mrinal Sim, é verdade.
Rishabh Agrahari de
19

A partir de hoje, sua melhor aposta é usar:

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

Você verá imgque será uma matriz numpy do tipo:

<class 'numpy.ndarray'>
Belvederef
fonte
12

Resposta tardia, mas passei a preferir o imageiomódulo às outras alternativas

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

Semelhante a cv2.imread(), ele produz uma matriz numpy por padrão, mas no formato RGB.

Slizb
fonte
7

Você precisa usar cv.LoadImageM em vez de 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
fonte
Muito obrigado ... Você também poderia me ajudar a descobrir que se eu criar uma imagem usando 'cv.CreateImage (largura, altura, canais)' ... Como ela poderia ser convertida em array numpy?
Shan,
Eu acho que você precisa usar cv.CreateMat em vez disso ou usar cv.CreateMat e copiar da imagem para o tapete usando cv.CvtColor ou algo semelhante. Dê uma olhada no link que Paul postou acima.
Justin Peel,
3

Ao usar a resposta de David Poole, recebo um SystemError com PNGs em escala de cinza e talvez outros arquivos. Minha solução é:

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

Na verdade, img.getdata () funcionaria para todos os arquivos, mas é mais lento, então eu o uso apenas quando o outro método falha.

digno
fonte
2

O formato de imagem OpenCV suporta a interface numpy array. Uma função auxiliar pode ser criada para suportar imagens em tons de cinza ou coloridas. Isso significa que a conversão BGR -> RGB pode ser feita convenientemente com uma fatia numpy, não uma cópia completa dos dados da imagem.

Nota: este é um truque de passos largos, portanto, modificar a matriz de saída também mudará os dados da imagem OpenCV. Se você quiser uma cópia, use o .copy()método no array!

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

Eu também adotei a imageio, mas achei a seguinte máquina útil para pré e pós-processamento:

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)

O raciocínio é que estou usando o numpy para processamento de imagens, não apenas para exibição de imagens. Para este propósito, uint8s são estranhos, então eu converto em valores de ponto flutuante que variam de 0 a 1.

Ao salvar imagens, percebi que eu mesmo tive que cortar os valores fora do intervalo, ou então acabei com uma saída realmente cinza. (A saída cinza foi o resultado da compressão de imageio em toda a faixa, que estava fora de [0, 256), para valores que estavam dentro da faixa.)

Havia algumas outras curiosidades também, que mencionei nos comentários.

Físico enigmático
fonte
1

Você pode obter uma matriz numpy de imagem rgb facilmente usando numpyeImage 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
fonte
0

carregue a imagem usando a seguinte sintaxe: -

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
fonte