Ich habe einen Haufen Bilddaten im Format RGB 565, also 16 Bit packed (RRRRRGGG GGGBBBBB). Jetzt könnte man immer 2 Byte einlesen und daraus 3 Byte machen, aber ich hatte gehofft, dass PIL das für mich schneller machen kann.
Leider verstehe ich den Decoder (http://www.pythonware.com/library/pil/h ... it-decoder) nicht:
Wie stellt man die Bitverteilung ein?
Was bedeutet "mode" in Image.fromstring()?
Danke schonmal.
PIL, Image.fromstring, 16 bit RGB 565, bit decoder
- b.esser-wisser
- User
- Beiträge: 272
- Registriert: Freitag 20. Februar 2009, 14:21
- Wohnort: Bundeshauptstadt B.
So Versteh ich die PIL-Docu auch, aber es gibt ja Binär-Dateien und das struct-Modul:565 geht also anscheinend nicht.
Code: Alles auswählen
import struct
BILD = r"pfad/zu/bild"
packed_pixel = struct.Struct("H") # Nofalls <H oder >H ausprobieren
def read_portion(fd, size):
while True:
data = fd.read(size)
if not data: raise StopIteration
yield data
img_buffer = []
with open(BILD, "rb") as img_fd:
for pixel in read_portion(img_fd, 2):
pixel_word = packed_pixel.unpack(pixel)
red, green, blue = (
(pixel_word >> 11) & 0x1F,
(pixel_word >> 5) & 0x3F,
pixel_word & 0x1F,
)
img_buffer.extend((red, green, blue))
img = "".join(img_buffer)
- debuggen (ist ungetestet)
- in List-comprehension umwandeln (Aus spass an der Freud)
- Profilen, schneller machen
hth, Jörg
Tante Edit: ungenutzten Code entfernt,
lebenswichtige Details eingebaut
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
Mit dem `array`-Modul kann man mehr Daten auf einmal umwandeln. Ist vielleicht effizienter.
- b.esser-wisser
- User
- Beiträge: 272
- Registriert: Freitag 20. Februar 2009, 14:21
- Wohnort: Bundeshauptstadt B.
Ja, array.array.fromfile() hilft hier vielleicht - sollte mal jemand bench'en , ich glaube allerdings, dass die Berechnung gruselig langsam ist - enthält die Standard-lib nichts für Bitfelder?
Edit: Doch, ctypes (Vorsicht, hässlich!):
Der Trick ist aber böse, nicht verständlich, u.U. nicht protabel, etc. pp.
Allerdings wüsste ich schon gern, ob es einen Geschwindigkeitsunterschied gibt.
hth, Jörg
Edit: Doch, ctypes (Vorsicht, hässlich!):
Code: Alles auswählen
import array, ctypes
class RGBField(ctypes.Structure):
_fields_ = (
("red", ctypes.c_uint, 5),
("green", ctypes.c_uint, 6),
("blue", ctypes.c_uint, 5),
)
_pack_ = 1
class RGBUnion(ctypes.Union):
_fields_ = (("raw", ctypes.c_ushort), ("done", RGBField))
img_buffer = array.array("H", (0, 7, 7<<5, 7<<11, 0xffff))
pixel_converter = RGBUnion()
for pixel in img_buffer:
pixel_converter.raw = pixel
print pixel_converter.done.red, \
pixel_converter.done.green, \
pixel_converter.done.blue
Allerdings wüsste ich schon gern, ob es einen Geschwindigkeitsunterschied gibt.
hth, Jörg
@b.esser-wisser: In Python wird das wahrscheinlich wirklich langsam sein. Da würde ich `psyco` ausprobieren, oder eine C-Bibliothek schreiben und die über `ctypes` anbinden. Alternativ vielleicht auch eine entsprechende Funtkion in Cython schreiben.
um von 565 auf 888 RGB zu wandeln muss man die Schiebeoperationen so auslegen, dass das MSB links steht:
.join() erwartet anscheinend String-Elemente, die Umwandlung lässt sich bestimmt noch eleganter machen ("Funktion auf jedes Element der Liste").
Danke für die Hilfe.
Code: Alles auswählen
red,green,blue = ( chr((pixel >> 8) & 0b11111000),
chr((pixel >> 3) & 0b11111000),
chr((pixel << 3) & 0b11111000))
Danke für die Hilfe.
- b.esser-wisser
- User
- Beiträge: 272
- Registriert: Freitag 20. Februar 2009, 14:21
- Wohnort: Bundeshauptstadt B.
Stimmt natürlich - dann ist der eventuelle Vorteil von meinem ctypes-Versuch erstmal dahin - das lesen, entpacken und schieben muss ja in C passieren.whaeva hat geschrieben: um von 565 auf 888 RGB zu wandeln muss man die Schiebeoperationen so auslegen, dass das MSB links steht[...]
Mit numpy geht das ziemlich fix:
Die 5*10**7 Bildpunkte werden bei mir in weniger als 3 Sekunden umgerechnet.
MfG
HWK
Code: Alles auswählen
import numpy, time
def output(a):
for x in a:
print bin(x)[2:].rjust(24, '0')
print
def convert(a):
return (((a & 0xF800) << 8) |
((a & 0x7E0) << 5) |
(a & 0x1F) << 3)
a = numpy.array([numpy.random.randint(0xFFFF) for _ in xrange(20)])
output(a)
output(convert(a))
a = numpy.arange(50000000)
t = time.clock()
convert(a)
print time.clock() - t
MfG
HWK
Sorry, Doppelpost, damit der letzte nicht zu lang wird.
Ein Beispiel aus dem wirklichen Leben (JPG-Datei mit über 7 Megapixel) zeigt eine ziemlich gute Performance. Da ich hier die 24-Bit-Ausgangsdaten erst in 32- und dann 16-Bit umwandele, was bei den Daten des OPs ja entfällt, dürfte das ganze noch unter 1 Sekunde liegen, so dass sich Tricks mit C etc. erübrigen dürften.Das ist die Ausgabe:MfG
HWK
Ein Beispiel aus dem wirklichen Leben (JPG-Datei mit über 7 Megapixel) zeigt eine ziemlich gute Performance. Da ich hier die 24-Bit-Ausgangsdaten erst in 32- und dann 16-Bit umwandele, was bei den Daten des OPs ja entfällt, dürfte das ganze noch unter 1 Sekunde liegen, so dass sich Tricks mit C etc. erübrigen dürften.
Code: Alles auswählen
import Image, numpy, time
def output(a):
for x in a:
print bin(x)[2:].rjust(32, '0')
print
def rgba_to_rgb565(x):
return (((x & 0xF80000) >> 8) |
((x & 0xFC00) >> 5) |
((x & 0xF8) >> 3))
def rgb565_to_rgb888(x):
return (((x & 0xF800) << 8) |
((x & 0x7E0) << 5) |
((x & 0x1F) << 3))
t0 = time.clock()
im = Image.open('test.jpg')
old_data = numpy.fromstring(im.convert('RGBA').tostring(), numpy.uint32)
t1 = time.clock()
print im.size[0] * im.size[1]
#output(old_data[:10])
print t1 - t0
data = rgba_to_rgb565(old_data)
t2 = time.clock()
#output(data[:10])
print t2 - t1
data = rgb565_to_rgb888(data)
t3 = time.clock()
#output(data[:10])
print t3 - t2
print t3 - t0
print all(data == old_data & 0xF8FCF8)
Code: Alles auswählen
7077888
0.498221421996
0.388644925542
0.392511897462
1.279378245
True
HWK
Dadurch gehen allerdings 3 Bits verloren. Doch lieber alle auf 5 bits rechts schieben/maskieren und dann mit 8.25 multiplizieren, um auf den RGB Wertebereich zu skalieren.um von 565 auf 888 RGB zu wandeln muss man die Schiebeoperationen so auslegen, dass das MSB links steht
Egal wie, aus 5-Bit-Genauigkeit kann man halt keine 8-Bit-Genauigkeit machen. Wenn ich Deinen Vorschlag richtig verstanden habe, verschiebst Du die linksbündigen Werte erst um 3 nach rechts und multiplizierst dann mit ungefähr 8, d.h. verschiebst wieder um 3 nach links?!
MfG
HWK
MfG
HWK
ungefähr 8 bedeutet ja float-Berechnung - die wird anschließend wieder gerundet.
Natürlich lässt sich die Genauigkeit nicht erhöhen, aber wie gesagt, man muss auf den Wertebereich skalieren, sonst wird das Bild entweder nicht ganz hell oder nicht ganz dunkel (die Bits werden ja nie gesetzt).
Natürlich lässt sich die Genauigkeit nicht erhöhen, aber wie gesagt, man muss auf den Wertebereich skalieren, sonst wird das Bild entweder nicht ganz hell oder nicht ganz dunkel (die Bits werden ja nie gesetzt).
Das Skalieren geschieht doch aber durch das Verschieben. Da die Anfangsgenauigkeit nicht 8 Bit beträgt, werden natürlich die Sprünge zwischen 2 Farben zahlenmäßig größer. Von 5- auf 8-Bit-Genauigkeit nämlich 8er- statt 1er-Schritte. Die Farbunterschiede sollten doch aber gleich bleiben. Dass die niederen Bits nicht verwendet werden, geht m.E. nicht anders. Wenn ich Dein Verfahren richtig verstanden habe, kostet es nur Zeit und bringt keine Verbesserung.
MfG
HWK
MfG
HWK