web-dev-qa-db-fra.com

Obtention de la liste des valeurs de pixel de PIL

Les gars, je cherche un peu d'aide. Je suis un programmeur débutant et l'un des problèmes que je rencontre à la minute consiste à convertir une image en noir et blanc .jpg en une liste que je peux ensuite moduler en signal audio. Cela fait partie d'un projet plus récent pour créer un programme python SSTV.

J'ai importé le module PIL et j'essaie d'appeler la fonction intégrée: list(im.getdata()). Quand je l'appelle, python se bloque. Existe-t-il un moyen de décomposer l'image (toujours 320x240) en 240 lignes pour faciliter les calculs? Ou est-ce que j'appelle simplement la mauvaise fonction?.

Si quelqu'un a des suggestions, veuillez vous en aller. Si quelqu'un a déjà utilisé Python pour générer des sons modulés, j'accepterais volontiers toutes les "perles de sagesse" qu'ils sont disposés à communiquer ... Merci d'avance.

25
Dave

Python ne devrait pas planter lorsque vous appelez getdata (). L'image est peut-être corrompue ou il y a un problème avec votre installation de PIL. Essayez-le avec une autre image ou publiez l'image que vous utilisez.

Cela devrait décomposer l'image comme vous le souhaitez:

from PIL import Image
im = Image.open('um_000000.png')

pixels = list(im.getdata())
width, height = im.size
pixels = [pixels[i * width:(i + 1) * width] for i in xrange(height)]
53
Nadia Alramli

Si vous avez numpy installé, vous pouvez essayer:

data = numpy.asarray(im)

(Je dis "essayer" ici, car on ne sait pas pourquoi getdata() ne fonctionne pas pour vous et je ne sais pas si asarray utilise getdata, mais cela vaut la peine de le tester.)

32
tom10

Je suppose que vous obtenez une erreur comme .. TypeError: 'PixelAccess' object is not iterable...?

Voir la documentation de Image.load pour savoir comment accéder aux pixels.

Fondamentalement, pour obtenir la liste des pixels dans une image, utilisez PIL:

from PIL import Image
i = Image.open("myfile.png")

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 ajoute chaque pixel au all_pixels - si le fichier est une image RVB (même s'il ne contient qu'une image en noir et blanc), il s'agira d'un tuple, par exemple:

(255, 255, 255)

Pour convertir l’image en monochrome, il suffit de faire la moyenne des trois valeurs. Ainsi, les trois dernières lignes de code deviendraient ..

cpixel = pixels[x, y]
bw_value = int(round(sum(cpixel) / float(len(cpixel))))
# the above could probably be bw_value = sum(cpixel)/len(cpixel)
all_pixels.append(bw_value)

Ou pour obtenir la luminance (moyenne pondérée):

cpixel = pixels[x, y]
luma = (0.3 * cpixel[0]) + (0.59 * cpixel[1]) + (0.11 * cpixel[2])
all_pixels.append(luma)

Ou pur noir et blanc 1-bit regardant:

cpixel = pixels[x, y]
if round(sum(cpixel)) / float(len(cpixel)) > 127:
    all_pixels.append(255)
else:
    all_pixels.append(0)

La PIL contient probablement des méthodes pour effectuer de telles conversions RGB -> BW plus rapidement, mais cela fonctionne et n'est pas particulièrement lent.

Si vous souhaitez uniquement effectuer des calculs sur chaque ligne, vous pouvez ignorer l'ajout de tous les pixels à une liste intermédiaire. Par exemple, pour calculer la valeur moyenne de chaque ligne:

from PIL import Image
i = Image.open("myfile.png")

pixels = i.load() # this is not a list
width, height = i.size
row_averages = []
for y in range(height):
    cur_row_ttl = 0
    for x in range(width):
        cur_pixel = pixels[x, y]
        cur_pixel_mono = sum(cur_pixel) / len(cur_pixel)
        cur_row_ttl += cur_pixel_mono

    cur_row_avg = cur_row_ttl / width
    row_averages.append(cur_row_avg)

print "Brighest row:",
print max(row_averages)
13
dbr

Ou si vous voulez compter les pixels blancs ou noirs

C'est aussi une solution:

from PIL import Image
import operator

img = Image.open("your_file.png").convert('1')
black, white = img.getcolors()

print black[0]
print white[0]
3
Martijn van Wezel

Pas PIL, mais scipy.misc.imread pourrait encore être intéressant:

import scipy.misc
im = scipy.misc.imread('um_000000.png', flatten=False, mode='RGB')
print(im.shape)

donne

(480, 640, 3)

il en va de même (hauteur, largeur, canaux). Donc, vous pouvez le parcourir en

for y in range(im.shape[0]):
    for x in range(im.shape[1]):
        color = Tuple(im[y][x])
        r, g, b = color
1
Martin Thoma

Comme je l'ai mentionné plus haut, le problème semble être la conversion du format de liste interne de PIL en un type de liste python standard. J'ai trouvé Image.tostring () beaucoup plus rapide et, selon vos besoins, cela pourrait être suffisant. Dans mon cas, je devais calculer le résumé CRC32 des données d’image, et cela me convenait parfaitement.

Si vous devez effectuer des calculs plus complexes, vous aurez peut-être besoin d'une réponse tom10 impliquant numpy.

1
jesjimher
data = numpy.asarray(im)

Avis : Dans PIL, img est RGBA. En cv2, img est BGRA.

Ma solution robuste:

def cv_from_pil_img(pil_img):
    assert pil_img.mode=="RGBA"
    return cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGBA2BGRA)
0
sunshine

On dirait que PILlow a peut-être changé tostring() en tobytes(). Lors de la tentative d'extraction de pixels RGBA pour les obtenir dans une texture OpenGL, les éléments suivants ont fonctionné pour moi (au sein de l'appel glTexImage2D que j'ai omis pour être bref).

from PIL import Image
img = Image.open("mandrill.png").rotate(180).transpose(Image.FLIP_LEFT_RIGHT)

# use img.convert("RGBA").tobytes() as texels
0
Dr. D.