How to read the RGB value of a given pixel in Python?
If I open an image with
open("image.jpg"), how can I get the RGB values of a pixel assuming I have the coordinates of the pixel?
Then, how can I do the reverse of this? Starting with a blank graphic, 'write' a pixel with a certain RGB value?
I would prefer if I didn't have to download any additional libraries.
It's probably best to use the Python Image Library to do this which I'm afraid is a separate download.
The easiest way to do what you want is via the load() method on the Image object which returns a pixel access object which you can manipulate like an array:
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
Alternatively, look at ImageDraw which gives a much richer API for creating images.
Read more... Read less...
Using Pillow (which works with Python 3.X as well as Python 2.7+), you can do the following:
from PIL import Image im = Image.open('image.jpg', 'r') width, height = im.size pixel_values = list(im.getdata())
Now you have all pixel values. If it is RGB or another mode can be read by
im.mode. Then you can get pixel
(x, y) by:
Alternatively, you can use Numpy and reshape the array:
>>> pixel_values = numpy.array(pixel_values).reshape((width, height, 3)) >>> x, y = 0, 1 >>> pixel_values[x][y] [ 18 18 12]
A complete, simple to use solution is
# 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) print(image.shape)
Smoke testing the code
You might be uncertain about the order of width / height / channel. For this reason I've created this gradient:
The image has a width of 100px and a height of 26px. It has a color gradient going from
#ffaa00 (yellow) to
#ffffff (white). The output is:
[[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)
Things to note:
- The shape is (width, height, channels)
image, hence the first row, has 26 triples of the same color
PyPNG - lightweight PNG decoder/encoder
Although the question hints at JPG, I hope my answer will be useful to some people.
Here's how to read and write PNG pixels using PyPNG module:
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 + point * 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 is a single pure Python module less than 4000 lines long, including tests and comments.
PIL is a more comprehensive imaging library, but it's also significantly heavier.
As Dave Webb said:
Here is my working code snippet printing the pixel colours from an image:
import os, sys import Image im = Image.open("image.jpg") x = 3 y = 4 pix = im.load() print pix[x,y]
photo = Image.open('IN.jpg') #your image photo = photo.convert('RGB') width = photo.size #define W and H height = photo.size 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