Show pageOld revisionsBacklinksBack to top This page is read only. You can view the source, but not change it. Ask your administrator if you think this is wrong. ====== Dithering und Bild-Kodierung ====== Die e-paper Displays zeigen (so weit ich bis jetzt verstanden habe) nur Pixel in Weiss, Schwarz und Rot an. Bilder müssen also entsprechend konvertiert werden. Siehe auch das Erklärvideo zur dreifarbigen E-Ink Technologie: https://www.youtube.com/watch?v=58ns93IoHpQ ===== Dithering ===== Studieren und Implementieren Sie den https://de.wikipedia.org/wiki/Floyd-Steinberg-Algorithmus Verwenden Sie dazu folgende Vorlage: <code python dithering.py> import cv2 import sys import os import numpy as np file = "test.jpg" if len(sys.argv)>1: file = sys.argv[1] if not os.path.exists(file): raise f"Datei {file} nicht gefunden!" def readAndConvert(file): return cv2.cvtColor(cv2.imread(file), cv2.COLOR_BGR2GRAY)/255 # Conversion to float in 0..1 def toBWSimple(img): c = np.copy(img) h,w = c.shape for y in range(h): for x in range(w): if img[y,x]<0.5: c[y,x] = 0 else: c[y,x] = 1.0 return c def floydSteinberg(img): c = np.copy(img) h,w = c.shape # # TODO # return c img = readAndConvert(file) print(img.shape) cv2.imshow('Image', img) cv2.waitKey(1000) c = toBWSimple(img) cv2.imshow('Image', c) cv2.waitKey(1000) c = floydSteinberg(img) cv2.imshow('Image', c) cv2.waitKey(10000) </code> ===== Codierung als Binärdaten ===== Die Auflösung unserer Displays ist 800x480, d.h. es werden für ein Schwarz/Weiss Bild (bzw. Rot/Weiss) 48'000 Bytes benötigt. Die Bits in den einzelnen Bytes werden als Big-Endian interpretiert, die Daten sind Zeilenweise: D.h. die ersten 8 Pixel sind wie folgt codiert: Bit 7, Bit 6, Bit 5, ... , Bit 0 Befüllen Sie folgendes Array mit dem korrekten Werten: <code python> n = 48000 # Oder besser aus der Displaygrösse berechnen data = np.zeros((n,),dtype=np.uint8) </code> ==== Umrechnung in Bytes ==== Variante 1: Multiplikation mit 2 (um eine Stelle nach links zu schieben) und Addition von 1 oder 0 (je nach Bit) Variante 2: Bit Operationen. Um das Bit $n$ einer Binärzahl $b$ zu setzen kann folgendes verwendet werden: <code python> b = b | (1 << n) # Der << Operator ist der Bitshift-Operator, er verschiebt die Bits der Zahl links um n Stellen (d.h. es kann als Multiplikation mit 2^n interpretiert werden) b |= (1 << n) # Kurzform </code> Variante 3: Kombination der obigen Varianten: <code python> b = 0 for bit in bits: # Annahme: bits ist ein Array von Einsen und Nullen b = (b << 1) | bit </code> Wandeln Sie dann das Array ins folgende Format um <code c> const unsigned char myimage[48000] = { 18,0,9,74,170,160,0,0,0,0,0,0,0,0,0,4, .... }; </code> Das könnte dann im Code für das Display gebraucht werden. Später sollen diese Daten natürlich via https direkt vom Server kommen. ==== Schreiben in eine Datei ==== Text: <code python> textDaten = "... whatever ..." with open("data.c", "w") as f: f.write(textDaten) </code> Binär: <code python> binData = np.zeros((100,), dtype=np.uint8) # Array of bytes with open("data.bin", "wb") as f: f.write(binData) </code> ===== Binäre Übertragung von Daten an den ESP32 ===== <code python sendBySerial.py> # On Linux: sudo apt install python3-serial # On Windows: pip install serial import serial import serial.tools.list_ports import re import sys import os import time def getPort(): # From https://stackoverflow.com/questions/12090503/listing-available-com-ports-with-python ports = serial.tools.list_ports.comports() for port, desc, hwid in sorted(ports): print("{}: {} [{}]".format(port, desc, hwid)) return [port for port, desc, hwid in ports if re.search(r"USB", desc) or re.search(r"USB", hwid)][0] def getData(): if len(sys.argv)!=2: raise "Bitte Dateinnamen mit binären Daten angeben." fn = sys.argv[1] if not os.path.exists(fn): raise f"Datei {fn} existiert nicht." if not os.path.getsize(fn)==96000: raise f"Die Datei hat nicht die korrekt Grösse von 96000 Bytes" with open(fn, mode='rb') as file: # b is important -> binary data = file.read() return data data = getData() port = getPort() print(f"Sending data to port {port}") with serial.Serial(port, 115200, timeout=0) as ser: ser.write(data) for i in range(3): s = ser.read(1000) if len(s)>0: print(s,end='') time.sleep(0.01) print(f"Done") </code> ===== Hausaufgaben auf 9. Januar 2023 ===== * Verschlüsselte Zip-Datei mit passwort 'dithering' per e-mail mit: * Python code, der das Dithering ausführt, nach Binary konvertiert und eine 96kB grosse Binärdatei schreibt. * Input-Bild * Output-Datei (binär, 96kB) ==== Überprüfung der Binärdatei ==== <code python readBinary.py> import cv2 import sys import os import numpy as np file = "data.bin" if len(sys.argv)>1: file = sys.argv[1] if not os.path.exists(file): raise f"Datei {file} nicht gefunden!" def readData(file): with open(file, "rb") as f: bindata = f.read() img = np.zeros((480,800,3), dtype=np.uint8) for y in range(480): for x in range(800): bit = 7-x%8 byte = x//8+y*100 bw = (bindata[byte] >> bit) & 1 rw = (bindata[byte+48000] >> bit) & 1 if (bw==1 and rw==1): img[y][x][0] = 255 img[y][x][1] = 255 img[y][x][2] = 255 elif rw==0: img[y][x][2] = 255 return img img = readData(file) cv2.imshow("result", img) cv2.waitKey(5000) </code> lehrkraefte/blc/informatik/efi-2023/images.txt Last modified: 2024/01/09 15:13by Ivo Blöchliger