Comment lire la valeur RVB d'un pixel donné en Python?


141

Si j'ouvre une image avec open("image.jpg"), comment puis-je obtenir les valeurs RVB d'un pixel en supposant que j'ai les coordonnées du pixel?

Alors, comment puis-je faire l'inverse? En commençant par un graphique vide, «écrire» un pixel avec une certaine valeur RVB?

Je préférerais ne pas avoir à télécharger de bibliothèques supplémentaires.

Réponses:


214

Il est probablement préférable d'utiliser la bibliothèque d'images Python pour ce faire, ce qui, je le crains, est un téléchargement séparé.

Le moyen le plus simple de faire ce que vous voulez est d'utiliser la méthode load () sur l'objet Image qui renvoie un objet d'accès au pixel que vous pouvez manipuler comme un tableau:

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

Sinon, regardez ImageDraw qui donne une API beaucoup plus riche pour créer des images.


1
Heureusement, l'installation de PIL est très simple sous Linux et Windows (je ne sais pas pour Mac)
heltonbiker

6
@ArturSapek, j'ai installé PIL pipqui était assez simple.
michaelliu

1
J'ai utilisé ceci sur mon Mac (Pypi):easy_install --find-links http://www.pythonware.com/products/pil/ Imaging
Mazyod

15
Pour les futurs lecteurs: pip install pillowinstallera PIL avec succès et assez rapidement (peut-être nécessaire sudosi ce n'est dans un virtualenv).
Christopher Shroba

Pillow.readthedocs.io/en/latest/… affiche les commandes bash dans les étapes d'installation de Windows. Pas vraiment sûr de savoir comment procéder.
Musixauce3000

31

En utilisant Pillow (qui fonctionne avec Python 3.X ainsi que Python 2.7+), vous pouvez effectuer les opérations suivantes:

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

Vous avez maintenant toutes les valeurs de pixel. Si c'est RVB ou un autre mode peut être lu par im.mode. Ensuite, vous pouvez obtenir des pixels (x, y)par:

pixel_values[width*y+x]

Vous pouvez également utiliser Numpy et remodeler le tableau:

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

Une solution complète et simple à utiliser est

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

Fumée testant le code

Vous n'êtes peut-être pas sûr de l'ordre largeur / hauteur / canal. Pour cette raison, j'ai créé ce dégradé:

entrez la description de l'image ici

L'image a une largeur de 100px et une hauteur de 26px. Il a un dégradé de couleur allant de #ffaa00(jaune) à #ffffff(blanc). La sortie est:

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

Choses à noter:

  • La forme est (largeur, hauteur, canaux)
  • Le image[0], d'où la première rangée, a 26 triplets de la même couleur

Pillow prend en charge python 2.7 sur macosx alors que je ne trouve que le support python 2.5 sur PIL. Merci!
Kangourou.H

2
Attention, la liste des paramètres 'reshape' doit être (hauteur, largeur, canaux). et pour les images rgba, vous pouvez inclure image.mode = RGBA avec des canaux = 4
gmarsi

Le point de @gmarsi est-il vrai sur la largeur et la hauteur? Est-il vraiment vrai que les deux sont valides? Vous devez être conscient de la façon dont les données sont produites afin de savoir quelle forme aura le tableau de sortie et où se trouveront les données de pixels de ligne et de colonne de l'image.
Kioshiki le

@Kioshiki J'ai ajouté une section "test de fumée" dans ma réponse, donc c'est plus facile à dire.
Martin Thoma le

24

PyPNG - décodeur / encodeur PNG léger

Bien que la question fasse allusion à JPG, j'espère que ma réponse sera utile à certaines personnes.

Voici comment lire et écrire des pixels PNG à l'aide du module 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 est un seul module Python pur de moins de 4000 lignes, comprenant des tests et des commentaires.

PIL est une bibliothèque d'imagerie plus complète, mais elle est également beaucoup plus lourde.


12

Comme l'a dit Dave Webb:

Voici mon extrait de code de travail imprimant les couleurs des pixels d'une image:

import os, sys
import Image

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

pix = im.load()
print pix[x,y]

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

3

Manipulation d'images est un sujet complexe, et il est préférable si vous n'utilisez une bibliothèque. Je peux recommander gdmodule qui fournit un accès facile à de nombreux formats d'image différents depuis Python.


Quelqu'un sait pourquoi cela a été rejeté? Y a-t-il un problème connu avec libgd ou quelque chose comme ça? (Je ne l'avais jamais regardé, mais c'est toujours agréable de savoir qu'il existe une alternative à PiL)
Peter Hanley

3

Il y a un très bon article sur wiki.wxpython.org intitulé Working With Images . L'article mentionne la possibilité d'utiliser wxWidgets (wxImage), PIL ou PythonMagick. Personnellement, j'ai utilisé PIL et wxWidgets et les deux facilitent la manipulation d'images.


3

Vous pouvez utiliser pygame le module de surfarray. Ce module a une méthode de retour de tableau de pixels 3D appelée pixels3d (surface). J'ai montré l'utilisation ci-dessous:

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

J'espère avoir été utile. Dernier mot: l'écran est verrouillé pour la durée de vie de screenpix.


2

installez PIL en utilisant la commande "sudo apt-get install python-imaging" et exécutez le programme suivant. Il imprimera les valeurs RVB de l'image. Si l'image est grande, redirigez la sortie vers un fichier en utilisant '>' plus tard, ouvrez le fichier pour voir les valeurs RVB

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]

2

Vous pouvez utiliser le module Tkinter, qui est l'interface Python standard de la boîte à outils Tk GUI et vous n'avez pas besoin de téléchargement supplémentaire. Voir https://docs.python.org/2/library/tkinter.html .

(Pour Python 3, Tkinter est renommé tkinter)

Voici comment définir les valeurs RVB:

#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()

Et obtenez RVB:

#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(" ")))

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

1
Bien que cet extrait de code puisse être la solution, inclure une explication contribue vraiment à améliorer la qualité de votre message. N'oubliez pas que vous répondez à la question aux lecteurs à l'avenir, et que ces personnes pourraient ne pas connaître les raisons de votre suggestion de code.
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)

1

Si vous cherchez à avoir trois chiffres sous la forme d'un code de couleur RVB, le code suivant devrait le faire.

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)

Cela peut fonctionner pour vous.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.