lehrkraefte:blc:informatik:efi-2023:images

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
lehrkraefte:blc:informatik:efi-2023:images [2024/01/09 13:04] – [Hausaufgaben auf 9. Januar 2023] Ivo Blöchligerlehrkraefte:blc:informatik:efi-2023:images [2024/01/09 14:13] (current) – [Überprüfung der Binärdatei] Ivo Blöchliger
Line 1: Line 1:
 +====== 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>