¿Cómo leer el valor RGB de un píxel dado en Python?

140

Si abro una imagen con open("image.jpg"), ¿cómo puedo obtener los valores RGB de un píxel suponiendo que tengo las coordenadas del píxel?

Entonces, ¿cómo puedo hacer lo contrario de esto? Comenzando con un gráfico en blanco, ¿'escribir' un píxel con un cierto valor RGB?

Preferiría si no tuviera que descargar ninguna biblioteca adicional.

Josh Hunt
fuente

Respuestas:

213

Probablemente sea mejor usar la biblioteca de imágenes de Python para hacer esto, lo cual me temo que es una descarga por separado.

La forma más fácil de hacer lo que desea es a través del método load () en el objeto Imagen que devuelve un objeto de acceso de píxeles que puede manipular como una matriz:

from PIL import Image

im = Image.open('dead_parrot.jpg') # Can be many different formats.
pix = im.load()
print im.size  # Get the width and hight of the image for iterating over
print pix[x,y]  # Get the RGBA Value of the a pixel of an image
pix[x,y] = value  # Set the RGBA Value of the image (tuple)
im.save('alive_parrot.png')  # Save the modified pixels as .png

Alternativamente, mira ImageDraw, que ofrece una API mucho más rica para crear imágenes.

Dave Webb
fuente
1
Afortunadamente, instalar PIL es muy sencillo en Linux y Windows (no sé sobre Mac)
heltonbiker
66
@ArturSapek, instalé PIL por lo pipque fue bastante fácil.
michaelliu
1
Usé esto en mi Mac (Pypi):easy_install --find-links http://www.pythonware.com/products/pil/ Imaging
Mazyod
15
Para futuros lectores: pip install pillowinstalará PIL con éxito y con bastante rapidez (puede ser necesario, sudosi no en un virtualenv).
Christopher Shroba
pillow.readthedocs.io/en/latest/… muestra los comandos bash en los pasos de instalación de Windows. No estoy realmente seguro de cómo proceder.
Musixauce3000
31

Con Pillow (que funciona con Python 3.X y Python 2.7+), puede hacer lo siguiente:

from PIL import Image
im = Image.open('image.jpg', 'r')
width, height = im.size
pixel_values = list(im.getdata())

Ahora tiene todos los valores de píxeles. Si es RGB u otro modo puede leerse im.mode. Entonces puedes obtener píxeles (x, y)por:

pixel_values[width*y+x]

Alternativamente, puede usar Numpy y remodelar la matriz:

>>> pixel_values = numpy.array(pixel_values).reshape((width, height, 3))
>>> x, y = 0, 1
>>> pixel_values[x][y]
[ 18  18  12]

Una solución completa y fácil de usar es

# Third party modules
import numpy
from PIL import Image


def get_image(image_path):
    """Get a numpy array of an image so that one can access values[x][y]."""
    image = Image.open(image_path, "r")
    width, height = image.size
    pixel_values = list(image.getdata())
    if image.mode == "RGB":
        channels = 3
    elif image.mode == "L":
        channels = 1
    else:
        print("Unknown mode: %s" % image.mode)
        return None
    pixel_values = numpy.array(pixel_values).reshape((width, height, channels))
    return pixel_values


image = get_image("gradient.png")

print(image[0])
print(image.shape)

Prueba de humo en el código

Es posible que no esté seguro sobre el orden de ancho / alto / canal. Por esta razón, he creado este gradiente:

ingrese la descripción de la imagen aquí

La imagen tiene un ancho de 100 px y una altura de 26 px. Tiene un degradado de color que va de #ffaa00(amarillo) a #ffffff(blanco). El resultado es:

[[255 172   5]
 [255 172   5]
 [255 172   5]
 [255 171   5]
 [255 172   5]
 [255 172   5]
 [255 171   5]
 [255 171   5]
 [255 171   5]
 [255 172   5]
 [255 172   5]
 [255 171   5]
 [255 171   5]
 [255 172   5]
 [255 172   5]
 [255 172   5]
 [255 171   5]
 [255 172   5]
 [255 172   5]
 [255 171   5]
 [255 171   5]
 [255 172   4]
 [255 172   5]
 [255 171   5]
 [255 171   5]
 [255 172   5]]
(100, 26, 3)

Cosas a tener en cuenta:

  • La forma es (ancho, alto, canales)
  • El image[0], de ahí la primera fila, tiene 26 triples del mismo color.
Martin Thoma
fuente
Pillow admite python 2.7 en macosx, mientras que solo encuentro python 2.5 en PIL ¡Gracias!
Canguro
2
Tenga cuidado, la lista de parámetros de 'remodelación' debe ser (altura, ancho, canales). y para las imágenes rgba puede incluir image.mode = RGBA con canales = 4
gmarsi
¿Es cierto el punto de @gmarsi en el ancho y la altura? ¿Es realmente el caso de que ambos son válidos? Debe saber cómo se emiten los datos para saber qué forma tendrá la matriz de salida y dónde estarán los datos de píxeles de fila y columna de la imagen.
Kioshiki hace
@Kioshiki He agregado una sección de "prueba de humo" en mi respuesta para que sea más fácil saberlo.
Martin Thoma hace
24

PyPNG - decodificador / codificador ligero de PNG

Aunque la pregunta apunta a JPG, espero que mi respuesta sea útil para algunas personas.

Aquí le mostramos cómo leer y escribir píxeles PNG con el módulo PyPNG :

import png, array

point = (2, 10) # coordinates of pixel to be painted red

reader = png.Reader(filename='image.png')
w, h, pixels, metadata = reader.read_flat()
pixel_byte_width = 4 if metadata['alpha'] else 3
pixel_position = point[0] + point[1] * w
new_pixel_value = (255, 0, 0, 0) if metadata['alpha'] else (255, 0, 0)
pixels[
  pixel_position * pixel_byte_width :
  (pixel_position + 1) * pixel_byte_width] = array.array('B', new_pixel_value)

output = open('image-with-red-dot.png', 'wb')
writer = png.Writer(w, h, **metadata)
writer.write_array(output, pixels)
output.close()

PyPNG es un único módulo Python puro de menos de 4000 líneas de largo, que incluye pruebas y comentarios.

PIL es una biblioteca de imágenes más completa, pero también es significativamente más pesada.

Constantin
fuente
12

Como dijo Dave Webb:

Aquí está mi fragmento de código de trabajo que imprime los colores de píxeles de una imagen:

import os, sys
import Image

im = Image.open("image.jpg")
x = 3
y = 4

pix = im.load()
print pix[x,y]
Lachlan Phillips
fuente
6
photo = Image.open('IN.jpg') #your image
photo = photo.convert('RGB')

width = photo.size[0] #define W and H
height = photo.size[1]

for y in range(0, height): #each pixel has coordinates
    row = ""
    for x in range(0, width):

        RGB = photo.getpixel((x,y))
        R,G,B = RGB  #now you can use the RGB value
Pedro V
fuente
3

La manipulación de imágenes es un tema complejo, y es mejor si usted no utiliza una biblioteca. Puedo recomendar gdmodule que proporciona un fácil acceso a muchos formatos de imagen diferentes desde Python.

Greg Hewgill
fuente
Alguien sabe por qué esto fue rechazado? ¿Hay algún problema conocido con libgd o algo así? (Nunca lo había visto, pero siempre es bueno saber que hay una alternativa a PiL)
Peter Hanley
3

Hay un muy buen artículo en wiki.wxpython.org titulado Working With Images . El artículo menciona la posibilidad de usar wxWidgets (wxImage), PIL o PythonMagick. Personalmente, he usado PIL y wxWidgets y ambos hacen que la manipulación de imágenes sea bastante fácil.

Jon Cage
fuente
3

Puede utilizar pygame 's surfarray módulo. Este módulo tiene un método de retorno de matriz de píxeles 3d llamado píxeles3d (superficie). He mostrado el uso a continuación:

from pygame import surfarray, image, display
import pygame
import numpy #important to import

pygame.init()
image = image.load("myimagefile.jpg") #surface to render
resolution = (image.get_width(),image.get_height())
screen = display.set_mode(resolution) #create space for display
screen.blit(image, (0,0)) #superpose image on screen
display.flip()
surfarray.use_arraytype("numpy") #important!
screenpix = surfarray.pixels3d(image) #pixels in 3d array:
#[x][y][rgb]
for y in range(resolution[1]):
    for x in range(resolution[0]):
        for color in range(3):
            screenpix[x][y][color] += 128
            #reverting colors
screen.blit(surfarray.make_surface(screenpix), (0,0)) #superpose on screen
display.flip() #update display
while 1:
    print finished

Espero haber sido de ayuda. Última palabra: la pantalla está bloqueada durante toda la vida de screenpix.

Ozgur Sonmez
fuente
2

instale PIL usando el comando "sudo apt-get install python-imaging" y ejecute el siguiente programa. Imprimirá valores RGB de la imagen. Si la imagen es grande, redirija la salida a un archivo usando '>' luego abra el archivo para ver los valores RGB

import PIL
import Image
FILENAME='fn.gif' #image can be in gif jpeg or png format 
im=Image.open(FILENAME).convert('RGB')
pix=im.load()
w=im.size[0]
h=im.size[1]
for i in range(w):
  for j in range(h):
    print pix[i,j]
usuario3423024
fuente
2

Puede utilizar el módulo Tkinter, que es la interfaz estándar de Python para el kit de herramientas Tk GUI y no necesita una descarga adicional. Ver https://docs.python.org/2/library/tkinter.html .

(Para Python 3, Tkinter se renombra a tkinter)

Aquí se explica cómo configurar los valores RGB:

#from http://tkinter.unpythonic.net/wiki/PhotoImage
from Tkinter import *

root = Tk()

def pixel(image, pos, color):
    """Place pixel at pos=(x,y) on image, with color=(r,g,b)."""
    r,g,b = color
    x,y = pos
    image.put("#%02x%02x%02x" % (r,g,b), (y, x))

photo = PhotoImage(width=32, height=32)

pixel(photo, (16,16), (255,0,0))  # One lone pixel in the middle...

label = Label(root, image=photo)
label.grid()
root.mainloop()

Y obtén RGB:

#from http://www.kosbie.net/cmu/spring-14/15-112/handouts/steganographyEncoder.py
def getRGB(image, x, y):
    value = image.get(x, y)
    return tuple(map(int, value.split(" ")))
chenlian
fuente
2
from PIL import Image
def rgb_of_pixel(img_path, x, y):
    im = Image.open(img_path).convert('RGB')
    r, g, b = im.getpixel((x, y))
    a = (r, g, b)
    return a
Idan Rotbart
fuente
1
Si bien este fragmento de código puede ser la solución, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo la pregunta para los lectores en el futuro, y que esas personas podrían no conocer los motivos de su sugerencia de código.
Narendra Jadhav
1
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

img=mpimg.imread('Cricket_ACT_official_logo.png')
imgplot = plt.imshow(img)
usuario8374199
fuente
1

Si está buscando tener tres dígitos en forma de código de color RGB, el siguiente código debería hacer exactamente eso.

i = Image.open(path)
pixels = i.load() # this is not a list, nor is it list()'able
width, height = i.size

all_pixels = []
for x in range(width):
    for y in range(height):
        cpixel = pixels[x, y]
        all_pixels.append(cpixel)

Esto puede funcionar para usted.

Anupam Hayat Shawon
fuente