18

Ich verwende die Python Imaging Library, um ein Schwarzweißbild mit einer Nachschlagetabelle einzufärben, die die Farbbeziehungen definiert. Die Nachschlagtabelle ist einfach eine 256-Element-Liste von RGB-Tupel:Verwenden der Image.point() - Methode in PIL zum Bearbeiten von Pixeldaten

>>> len(colors) 
256 
>>> colors[0] 
(255, 237, 237) 
>>> colors[127] 
(50, 196, 33) 
>>> 

Meine erste Version verwendet, um die getpixel() und putpixel() Methoden:

for x in range(w): 
     for y in range(h): 
      pix = img.getpixel((x,y)) 
      img.putpixel((x,y), colors[pix[0]]) 

Das war schrecklich langsam. Ein profile Bericht wies auf die putpixel und getpixel Verfahren als die Schuldigen hin. Eine kleine Untersuchung (d. H. Lesen Sie die Dokumente) und ich finde "Beachten Sie, dass diese Methode relativ langsam ist." re: putpixel. (tatsächliche Laufzeit: 53s in putpixel und 50s getpixel für ein 1024x1024-Bild)

Basierend auf dem Vorschlag in der Dokumentation, verwenden ich im.load() und direkten Pixelzugriff statt:

pixels = img.load() 
    for x in range(w): 
     for y in range(h): 
      pix = pixels[x, y] 
      pixels[x, y] = colors[pix[0]]     

Verarbeitung beschleunigt durch eine Größenordnung, aber ist immer noch langsam: etwa 3,5 s ein 1024x1024 Bild zu verarbeiten.

Eine gründlichere Untersuchung der PIL docs scheint Image.point() ist genau für diesen Zweck anzeigen soll:

im.point(table) => Bild

im.point(function) => Bild

Gibt eine Kopie des Bildes, in dem jedes Pixel durch die gegebene Tabelle abgebildet wurde. Die Tabelle sollte 256 Werte pro Band im Bild enthalten. Wenn stattdessen eine Funktion verwendet wird, sollte ein einzelnes Argument verwendet werden. Die Funktion wird einmal für jeden möglichen Pixelwert aufgerufen, und die resultierende Tabelle wird auf alle Bänder des Bildes angewendet.

Ich habe einige Zeit mit der Schnittstelle hacken verbracht, aber kann nicht scheinen, es richtig zu machen. Verzeihen Sie meine Unwissenheit, aber Pils Unterlagen sind kurz und ich habe nicht viel Erfahrung in der Bildverarbeitung. Ich habe ein wenig gegoogelt und ein paar Beispiele gefunden, aber nichts, was die Verwendung für mich "klick" machte. So, endlich, meine Fragen:

  • Ist Image.point() das richtige Werkzeug für diesen Job?
  • Welches Format/welche Struktur erwartet Image.point() die Tabelle?
  • Kann jemand eine Beispielimplementierung ausarbeiten? Jede Iteration, die ich bisher probiert habe, endete mit einem schwarzen Bild.

Antwort

15

Ist Image.point() das richtige Werkzeug für diesen Job?

Ja, Image.point() für diesen Job ist perfekt

Welches Format/Struktur hat Image.point() erwarten die Tabelle?

Sie sollten die Liste abflachen so statt [(12, 140, 10), (10, 100, 200), ...] Verwendung:

[12, 140, 10, 10, 100, 200, ...] 

Hier ist ein kurzes Beispiel ich gerade versucht:

im = im.point(range(256, 0, -1) * 3) 

alt text alt text

Und durch die So, wenn Sie mehr Kontrolle über Farben brauchen und Sie glauben, dass Image.point nicht für Sie ist, können Sie auch Image.getdata und Image.putdata verwenden, um Farben schneller zu ändern als load und putpixel. Es ist langsamer als Image.point obwohl.

gibt Ihnen die Liste aller Pixel, ändern Sie sie und schreiben Sie sie zurück mit Image.putdata. So einfach ist das. Aber versuchen Sie es zuerst mit Image.point.


EDIT

Ich habe einen Fehler in der ersten Erklärung gemacht, werde ich das jetzt richtig erklären:

Die Farbtabelle ist eigentlich wie dieses

[0, 1, 2, 3, 4, 5, ...255, 0, 1, 2, 3, ....255, 0, 1, 2, 3, ...255] 

Jedes Band Bereich neben dem anderen. Um die Farbe zu ändern (0, 0, 0) bis (10, 100, 10) es so werden muß:

[10, 1, 2, 3, 4, 5, ...255, 100, 1, 2, 3, ....255, 10, 1, 2, 3, ...255] 

Um die Farbliste in das richtige Format versuchen, diese Transformation:

table = sum(zip(*colors),()) 

Ich denke, mein erstes Beispiel sollte das Format für Sie demonstrieren.

+0

die Liste glätten? ok, aber wie geht das? Ich möchte Pixel mit dem Wert 0 -> (12, 140, 10) und Pixel mit dem Wert 255 -> (254, 237, 220). –

+4

Sie wissen, ich denke, dies könnte der einzige Ort im Internet sein, wo das erwartete Format dieser Tabelle beschrieben wird. // Ich habe nur img.point() mit der Lookup-Tabelle arbeiten, dank Ihrer Beschreibung. Die Ergebnisse sind nicht genau das, was ich erwartet habe, aber ich habe genug, um herumzuhacken und es herauszufinden. Vielen Dank! –

+0

@ J.J., Das Format ist nicht wirklich offensichtlich. Ich habe bei meiner ersten Erklärung einen Fehler gemacht und jetzt habe ich es behoben. Ich hoffe, ich habe es diesmal richtig verstanden. Ich werde schlafen, damit ich keine Fragen mehr beantworten kann. –

3

ich denke, es könnte mehr typisch sein point auf einem Band-für-Band-Basis wie so (direkt vom tutorial PIL angehoben):

# split the image into individual bands 
source = im.split() 

R, G, B = 0, 1, 2 

# select regions where red is less than 100 
mask = source[R].point(lambda i: i < 100 and 255) 

# process the green band 
out = source[G].point(lambda i: i * 0.7) 

# paste the processed band back, but only where red was < 100 
source[G].paste(out, None, mask) 

# build a new multiband image 
im = Image.merge(im.mode, source) 
+0

das Tabellenformat macht mehr Sinn mit einer einzelnen Band, das ist sicher. Ich muss vielleicht diese Route benutzen, um den Alpha-Kanal mit einem speziellen Fall zu behandeln ... –

+0

es ist glatt und schnell danke. – Conex

Verwandte Themen