Bagaimana cara membaca nilai RGB dari piksel tertentu dengan Python?

146

Jika saya membuka gambar dengan open("image.jpg"), bagaimana saya bisa mendapatkan nilai RGB dari sebuah piksel dengan asumsi saya memiliki koordinat piksel?

Lalu, bagaimana cara melakukan kebalikan dari ini? Dimulai dengan grafik kosong, 'tulis' piksel dengan nilai RGB tertentu?

Saya lebih suka jika saya tidak perlu mengunduh perpustakaan tambahan apa pun.

Josh Hunt
sumber

Jawaban:

220

Mungkin yang terbaik adalah menggunakan Python Image Library untuk melakukan ini yang saya khawatirkan adalah unduhan terpisah.

Cara termudah untuk melakukan apa yang Anda inginkan adalah melalui metode load () pada objek Image yang mengembalikan objek akses piksel yang dapat Anda manipulasi seperti 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

Atau, lihat ImageDraw yang memberikan API yang lebih kaya untuk membuat gambar.

Dave Webb
sumber
1
Untungnya menginstal PIL sangat mudah di Linux dan Windows (tidak tahu tentang Mac)
heltonbiker
7
@ArturSapek, saya menginstal PIL pipyang cukup mudah.
michaelliu
1
Saya menggunakan ini di Mac saya (Pypi):easy_install --find-links http://www.pythonware.com/products/pil/ Imaging
Mazyod
17
Untuk pembaca selanjutnya: pip install pillowakan menginstal PIL dengan sukses dan cukup cepat (mungkin perlu sudojika tidak di virtualenv).
Christopher Shroba
pillow.readthedocs.io/en/latest/… menunjukkan perintah bash di langkah-langkah instalasi windows. Tidak begitu yakin bagaimana melanjutkannya.
Musixauce3000
37

Menggunakan Pillow (yang bekerja dengan Python 3.X serta Python 2.7+), Anda dapat melakukan hal berikut:

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

Sekarang Anda memiliki semua nilai piksel. Jika RGB atau mode lain dapat dibaca im.mode. Kemudian Anda bisa mendapatkan piksel (x, y)dengan:

pixel_values[width*y+x]

Alternatifnya, Anda bisa menggunakan Numpy dan membentuk kembali array:

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

Solusi lengkap dan mudah digunakan adalah

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

Asap menguji kode

Anda mungkin tidak yakin tentang urutan lebar / tinggi / saluran. Untuk alasan ini saya telah membuat gradien ini:

masukkan deskripsi gambar di sini

Gambar memiliki lebar 100px dan tinggi 26px. Ini memiliki gradien warna dari #ffaa00(kuning) ke #ffffff(putih). Outputnya adalah:

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

Hal yang perlu diperhatikan:

  • Bentuknya adalah (lebar, tinggi, saluran)
  • Jadi image[0], baris pertama, memiliki 26 tripel dengan warna yang sama
Martin Thoma
sumber
Pillow mendukung python 2.7 di macosx sementara saya hanya menemukan dukungan python 2.5 di PIL. Terima kasih!
Kangaroo.H
2
Hati-hati, daftar params 'membentuk kembali' harus (tinggi, lebar, saluran). dan untuk gambar rgba Anda dapat menyertakan image.mode = RGBA dengan saluran = 4
gmarsi
Apakah poin oleh @gmarsi benar pada lebar dan tinggi? Benarkah keduanya valid? Anda perlu mengetahui bagaimana data dikeluarkan sehingga Anda tahu bentuk apa yang akan dimiliki larik keluaran dan di mana data piksel baris dan kolom dari gambar tersebut akan berada.
Kioshiki
@Kiiki Saya telah menambahkan bagian "pengujian asap" dalam jawaban saya sehingga lebih mudah untuk mengatakannya.
Martin Thoma
24

PyPNG - dekoder / encoder PNG ringan

Meskipun pertanyaannya mengisyaratkan JPG, saya harap jawaban saya bermanfaat bagi sebagian orang.

Berikut cara membaca dan menulis piksel PNG menggunakan modul 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 adalah modul Python murni tunggal yang panjangnya kurang dari 4000 baris, termasuk tes dan komentar.

PIL adalah pustaka gambar yang lebih komprehensif, tetapi juga lebih berat secara signifikan.

Constantin
sumber
11

Seperti yang dikatakan Dave Webb:

Berikut adalah cuplikan kode kerja saya yang mencetak warna piksel dari sebuah gambar:

import os, sys
import Image

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

pix = im.load()
print pix[x,y]
Lachlan Phillips
sumber
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
Peter V.
sumber
3

Manipulasi gambar adalah topik yang kompleks, dan lebih baik jika Anda tidak menggunakan perpustakaan. Saya dapat merekomendasikan gdmodule yang menyediakan akses mudah ke berbagai format gambar dari dalam Python.

Greg Hewgill
sumber
Adakah yang tahu mengapa ini tidak disukai? Apakah ada masalah yang diketahui dengan libgd atau sesuatu? (Saya belum pernah melihatnya, tetapi selalu menyenangkan mengetahui ada alternatif untuk PiL)
Peter Hanley
3

Ada artikel yang sangat bagus di wiki.wxpython.org berjudul Bekerja Dengan Gambar . Artikel tersebut menyebutkan kemungkinan menggunakan wxWidgets (wxImage), PIL atau PythonMagick. Secara pribadi, saya telah menggunakan PIL dan wxWidgets dan keduanya membuat manipulasi gambar cukup mudah.

Jon Cage
sumber
3

Anda dapat menggunakan modul surfarray pygame . Modul ini memiliki metode pengembalian larik piksel 3d yang disebut piksel3d (permukaan). Saya telah menunjukkan penggunaan di bawah ini:

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

Semoga bermanfaat Kata terakhir: layar dikunci seumur hidup screenpix.

Ozgur Sonmez
sumber
2

instal PIL menggunakan perintah "sudo apt-get install python-imaging" dan jalankan program berikut. Ini akan mencetak nilai RGB gambar. Jika gambarnya besar, alihkan output ke file menggunakan '>' kemudian buka file untuk melihat nilai 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]
pengguna3423024
sumber
2

Anda dapat menggunakan modul Tkinter, yang merupakan antarmuka standar Python ke perangkat Tk GUI dan Anda tidak perlu mengunduh tambahan. Lihat https://docs.python.org/2/library/tkinter.html .

(Untuk Python 3, Tkinter diganti namanya menjadi tkinter)

Berikut adalah cara mengatur nilai 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()

Dan dapatkan 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
sumber
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
sumber
1
Meskipun potongan kode ini dapat menjadi solusinya, menyertakan penjelasan sangat membantu untuk meningkatkan kualitas posting Anda. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa mendatang, dan orang-orang itu mungkin tidak tahu alasan saran kode Anda.
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)
pengguna8374199
sumber
1

Jika Anda ingin memiliki tiga digit dalam bentuk kode warna RGB, kode berikut harus melakukannya.

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)

Ini mungkin berhasil untuk Anda.

Anupam Hayat Shawon
sumber