¿Cómo convertir una imagen RGB a una matriz numpy?

Respuestas:

142

Puede usar la interfaz Python OpenCV más nueva (si no me equivoco, está disponible desde OpenCV 2.2). Utiliza de forma nativa matrices numpy:

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

resultado:

<type 'numpy.ndarray'>
Andrey Kamaev
fuente
94
Tenga en cuenta que cv2.imread () devuelve una matriz numpy en BGR, no RGB.
PND
6
@pnd ¡tu comentario es sagrado!
Eduardo Pignatelli
4
Para referencia futura: $ pip install opencv-pythonpara instalar opencv
Kyle C
2
TypeError: 'mode' is an invalid keyword argument for imread()
Rishabh Agrahari
8
OpenCV parece haber abandonado el modeargumento. Vea mi respuesta a continuación para obtener un método actualizado.
belvederef
73

PIL (Python Imaging Library) y Numpy funcionan bien juntos.

Utilizo las siguientes funciones.

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 )

El 'Image.fromarray' es un poco feo porque recorto los datos entrantes a [0,255], los convierto a bytes y luego creo una imagen en escala de grises. Principalmente trabajo en gris.

Una imagen RGB sería algo como:

 outimg = Image.fromarray( ycc_uint8, "RGB" )
 outimg.save( "ycc.tif" )
David Poole
fuente
1
Esto falla con un error, TypeError: long() argument must be a string or a number, not 'PixelAccess'y al mirar la documentación de la PixelAccessclase de PIL , no parece ofrecer métodos que permitan np.arrayconvertir sus datos subyacentes en un ndarrayformato. Debe omitir el uso de img.load()y tratar solo con el resultado de Image.open(...).
Ely
Img.load () soluciona un extraño problema de almacenamiento en caché en PIL. Los datos no se cargarían hasta que se necesitaran explícitamente. El ejemplo todavía me funciona con la excepción de cambiar "importar imagen" a "de imagen de importación PIL" cuando se trabaja con Pillow (la bifurcación de PIL).
David Poole
Voto a favor por usar solo PIL y no OpenCV. Sin embargo, no estoy en contra de OpenCV.
progyammer
54

También puede usar matplotlib para esto.

from matplotlib.image import imread

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

salida: <class 'numpy.ndarray'>

Rishabh Agrahari
fuente
2
Esto es muy simple. Me gusta :)
jeongmin.cha
@Mrinal Sí, lo hace.
Rishabh Agrahari
19

A partir de hoy, su mejor opción es utilizar:

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

Verás que imghabrá una gran variedad de tipos:

<class 'numpy.ndarray'>
Belvederef
fuente
12

Respuesta tardía, pero he llegado a preferir el imageiomódulo a las otras alternativas

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

Similar a cv2.imread(), produce una matriz numpy por defecto, pero en forma RGB.

Slizb
fuente
7

Necesita usar cv.LoadImageM en lugar 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
fuente
Muchas gracias ... ¿Podrían ayudarme también a descubrir que si creo una imagen usando 'cv.CreateImage (ancho, alto, canales)' ... cómo podría convertirse en una matriz numpy?
Shan
Creo que necesitas usar cv.CreateMat en su lugar o usar cv.CreateMat y copiar de la imagen al tapete usando cv.CvtColor o algo similar. Eche un vistazo al enlace que Paul publicó arriba.
Justin Peel
3

Cuando uso la respuesta de David Poole, obtengo un SystemError con PNG en escala de grises y tal vez otros archivos. Mi solucion es:

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

En realidad img.getdata () funcionaría para todos los archivos, pero es más lento, así que lo uso solo cuando falla el otro método.

daign
fuente
2

El formato de imagen OpenCV admite la interfaz de matriz numpy. Se puede crear una función auxiliar para admitir imágenes en escala de grises o en color. Esto significa que la conversión BGR -> RGB se puede realizar cómodamente con una gran cantidad de cortes, no con una copia completa de los datos de la imagen.

Nota: este es un truco de paso, por lo que modificar la matriz de salida también cambiará los datos de la imagen OpenCV. Si quieres una copia, usa el .copy()método en la matriz.

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

También adopté imageio, pero encontré la siguiente maquinaria útil para el procesamiento previo y posterior:

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)

La razón es que estoy usando numpy para el procesamiento de imágenes, no solo para la visualización de imágenes. Para este propósito, los uint8 son incómodos, así que los convierto a valores de punto flotante que van de 0 a 1.

Al guardar imágenes, noté que tenía que cortar los valores fuera de rango yo mismo, o de lo contrario terminé con una salida realmente gris. (La salida gris fue el resultado de imageio comprimiendo el rango completo, que estaba fuera de [0, 256), a valores que estaban dentro del rango).

También hubo un par de rarezas más, que mencioné en los comentarios.

enigmático fisico
fuente
1

Puede obtener una gran variedad de imágenes rgb fácilmente usando numpyyImage 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
fuente
0

cargue la imagen usando la siguiente sintaxis: -

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
fuente