Programming lesson
Bildkompression mit Run-Length Encoding (RLE) in Python – Tutorial für COP3502C
Lerne in diesem Tutorial, wie du mit Python Run-Length Encoding (RLE) für Bilddaten implementierst. Perfekt für Studierende der COP3502C – inklusive Encoding, Decoding und Hex-Konvertierung.
Einleitung: Warum RLE in der Bildverarbeitung?
Stell dir vor, du entwickelst ein Pixel-Art-Spiel wie Minecraft oder einen Retro-Plattformer. Jedes Bild besteht aus tausenden Pixeln – und viele davon wiederholen sich. Genau hier kommt Run-Length Encoding (RLE) ins Spiel: eine verlustfreie Kompression, die wiederholte Werte als Paar aus Anzahl und Wert speichert. In der COP3502C Hausaufgabe 3 und 4 implementierst du genau diese Technik in Python.
Dieses Tutorial führt dich Schritt für Schritt durch die Kernfunktionen: vom Encoding und Decoding über die Umwandlung in Hexadezimal-Strings bis zur Ausgabe im Menü. Keine Sorge – du musst keine echten Bilddateien öffnen, sondern arbeitest nur mit Python-Listen. Los geht's!
Grundlagen: Was ist RLE?
RLE ersetzt aufeinanderfolgende gleiche Werte durch ein Tupel (Länge, Wert). Beispiel: [15, 15, 15, 4, 4, 4, 4, 4, 4] wird zu [3, 15, 6, 4]. Das spart Speicherplatz – besonders bei Pixelgrafiken mit großen einfarbigen Flächen.
Trend-Beispiel: Denk an das Wordle-Spiel von 2026: Die grünen, gelben und grauen Kästchen wiederholen sich oft. Mit RLE könntest du das Spielfeld effizient speichern!
Die 8 Kernfunktionen im Detail
In deiner Abgabe musst du folgende Methoden implementieren. Wir gehen jede durch – mit Code und Erklärung.
1. to_hex_string(data) – Daten in Hex umwandeln
Diese Funktion übersetzt eine Liste von Zahlen (0–15) in einen Hex-String ohne Trennzeichen. Beispiel: [3, 15, 6, 4] → "3f64".
def to_hex_string(data):
return ''.join(hex(val)[2:] for val in data)Der hex()-Aufruf liefert einen String wie 0xf; mit [2:] schneidest du das 0x ab.
2. count_runs(flat_data) – Anzahl der Läufe zählen
Zählt, wie oft sich der Wert in der flachen Liste ändert. Jeder Wechsel beginnt einen neuen Lauf.
def count_runs(flat_data):
if not flat_data:
return 0
runs = 1
for i in range(1, len(flat_data)):
if flat_data[i] != flat_data[i-1]:
runs += 1
return runsTeste: count_runs([15,15,15,4,4,4,4,4,4]) → 2.
3. encode_rle(flat_data) – Flache Daten in RLE codieren
Erzeugt eine Liste mit abwechselnd Länge und Wert für jeden Lauf.
def encode_rle(flat_data):
if not flat_data:
return []
rle = []
count = 1
for i in range(1, len(flat_data)):
if flat_data[i] == flat_data[i-1]:
count += 1
else:
rle.extend([count, flat_data[i-1]])
count = 1
rle.extend([count, flat_data[-1]])
return rleBeispiel: encode_rle([15,15,15,4,4,4,4,4,4]) → [3,15,6,4].
4. get_decoded_length(rle_data) – Decodierte Länge berechnen
Summiere alle Längen-Einträge (jeder zweite Wert ab Index 0).
def get_decoded_length(rle_data):
return sum(rle_data[i] for i in range(0, len(rle_data), 2))Beispiel: get_decoded_length([3,15,6,4]) → 9.
5. decode_rle(rle_data) – RLE in flache Daten decodieren
Das Herzstück: Erzeuge aus (Länge, Wert)-Paaren die ursprüngliche Liste.
def decode_rle(rle_data):
flat = []
for i in range(0, len(rle_data), 2):
length = rle_data[i]
value = rle_data[i+1]
flat.extend([value] * length)
return flatTeste: decode_rle([3,15,6,4]) → [15,15,15,4,4,4,4,4,4].
6. string_to_data(data_string) – Hex-String in Zahlenliste
Die Umkehrung von to_hex_string. Jedes Zeichen wird einzeln in eine Zahl 0–15 umgewandelt.
def string_to_data(data_string):
return [int(ch, 16) for ch in data_string]Beispiel: string_to_data("3f64") → [3,15,6,4].
7. to_rle_string(rle_data) – RLE-Daten in lesbaren String
Formatiere jedes (Länge, Wert)-Paar als LängeWert (Länge dezimal, Wert hex) und trenne mit :.
def to_rle_string(rle_data):
parts = []
for i in range(0, len(rle_data), 2):
length = str(rle_data[i])
value = hex(rle_data[i+1])[2:]
parts.append(length + value)
return ':'.join(parts)Beispiel: to_rle_string([15,15,6,4]) → "15f:64".
8. string_to_rle(rle_string) – RLE-String in Datenliste
Parst den menschenlesbaren String zurück in die RLE-Liste.
def string_to_rle(rle_string):
rle = []
for part in rle_string.split(':'):
# Länge ist alles außer dem letzten Zeichen, Wert ist das letzte Zeichen
length = int(part[:-1])
value = int(part[-1], 16)
rle.extend([length, value])
return rleBeispiel: string_to_rle("15f:64") → [15,15,6,4].
Das Menü im Standalone-Modus
Dein Programm muss ein interaktives Menü bieten. Hier ein Ausschnitt:
def main():
print("Willkommen zum RLE-Bildeditor!")
# Farbtest anzeigen
ConsoleGfx.test_rainbow()
while True:
print("Menü:")
print("1. Datei laden")
print("2. Testbild laden")
print("3. RLE-String lesen")
print("4. RLE-Hex-String lesen")
print("5. Flat-Hex-String lesen")
print("6. Bild anzeigen")
print("7. RLE-String anzeigen")
print("8. RLE-Hex-Werte anzeigen")
print("9. Flat-Hex-Werte anzeigen")
print("0. Beenden")
choice = input("Option: ")
# ... VerarbeitungDie Optionen 1–5 laden Daten in eine interne Variable, Optionen 6–9 zeigen sie an.
Tipps für die Abgabe
- Teste jede Funktion einzeln – am besten mit den Beispielen aus der Aufgabenstellung.
- Achte auf die genaue Ausgabe – Groß-/Kleinschreibung und Trennzeichen müssen stimmen.
- Nutze die
ConsoleGfx-Klasse – sie kümmert sich um die Farbdarstellung. - Trend-Tipp: Stell dir vor, du speicherst die Highscores deines selbst programmierten Flappy Bird-Klons – RLE kann auch dort wiederholte Werte komprimieren.
Häufige Fehler und Lösungen
- Falsche Hex-Konvertierung: Vergiss nicht, dass
int('f', 16)15 ergibt – aberint('F', 16)ebenfalls. Deine Funktion sollte beides akzeptieren. - Index-Fehler bei leerer Liste: Prüfe zu Beginn auf leere Eingaben.
- RLE-String-Parsing: Wenn die Länge mehrstellig ist (z.B.
15f), klapptpart[:-1]nur, wenn der Wert einstellig ist. Da Werte 0–15 sind, ist das immer der Fall.
Fazit
Mit diesen acht Funktionen bist du bestens gerüstet für die COP3502C Hausaufgabe 3 und 4. RLE ist nicht nur für Pixelgrafiken nützlich – es wird auch in modernen KI-Anwendungen zur effizienten Speicherung von Trainingsdaten eingesetzt. Viel Erfolg beim Coden!