Ditheren in Python

Wat is ditheren?

Ditheren (ook wel rasteren) is een techniek waarmee je plaatjes zo goed mogelijk kunt weergeven als je maar weinig kleuren tot je beschikking hebt. Je kunt dit bijvoorbeeld toepassen als je een zwart-wit scherm hebt waar je een foto van jezelf op wilt weergeven. Ditheren in zwart-wit lukt met bijna elk beeldverwerkingsprogramma, maar als je drie of zeven kleuren hebt, met een vast palet kan dat vaak niet. Toch is het niet erg moeilijk een programma hiervoor te maken. Ook in python gaat dat goed. Python draait op bijna elk computertype, inclusief de Raspberry Pi. De Python programma's die ik hier beschrijf kun je zelf op je eigen computer uitvoeren. De paletten die in deze programma's zijn opgenomen zijn afgestemd op zeven kleuren e-Paper displays. Waarschijnlijk kloppen ook de alternatieve paletten voor drie-kleuren ePaper. De resultaten voor drie-kleuren displays zijn vaak niet geweldig, maar dat hangt sterk af van het plaatje dat je wilt weergeven. De resultaten voor zeven kleuren displays zijn verrassend goed.
Voor vier-grijstinten e-Paper heb ik een bibliotheek gevonden die anders werkt. Je kan met vier kleuren ook zonder ditheren redelijk goede resultaten krijgen.

e-Paper displays

Om de plaatjes op de e-paper displays te krijgen gebruik ik geen Arduino, maar een ESP8266 of ESP32 processor, die ik programmeer met de Arduino IDE.
Het voordeel van de ESP's is dat je de plaatjes gemakkelijk in het flash geheugen kunt zetten. Ik gebruik daarvoor de voorbeelden uit de GxEPD2.h bibliotheek. Deze en ook de meeste andere software-bibliotheken kunnen alleen plaatjes in bmp-formaat verwerken. Helaas is dat een inefficiënt formaat. Omdat grotere e-Paper displays en alle zeven-kleuren displays veel pixels hebben, moet je kiezen voor opslag in 1 bit per pixel voor zwart-wit plaatjes, en voor 4 bits per pixel voor plaatjes die in drie of zeven kleuren zijn. Ook als je een SD kaartje gebruikt raad ik dat aan.
Als je Python nog niet geïnstalleerd hebt, vink dan bij het installeren aan dat het Python aan het pad moet worden toegevoegd! De Python programma's maken gebruik van de software bibliotheek PIL (pillow), die moet je dus installeren. Gebruik met Windows een zogenaamde opdrachtprompt en bij linux een terminal en type in: pip3 install pillow (gevolgd door een return). Bij gebruik van Thonny kan het gemakkelijk via hulpmiddelen→plug-ins beheren. Thonny gebruikt dan zijn eigen versie.
Ik heb een viertal programma's gemaakt:
  1. Dither.py
    Dit programma leest een plaatje in en laat vervolgens het resultaat zien op je scherm. Hierbij wordt je standaard fotobewerkingsprogramma gebruikt, of anders vraagt het programma het. Je kunt het plaatje desgewenst opslaan vanuit dat programma, maar als je het voor e-Paper gebruikt dan kun je het beste eerst het aantal kleuren terugbrengen tot 16. Zorg er dan wel voor dat er niet opnieuw geditherd wordt, dus zoek naar een optie als dichtstbijzijnde kleur. Boven het programma zie je een aantal paletten staan, die commentaar zijn. Je kunt ze dus makkelijk gebruiken door het hekje weg te halen. Als je het zwart-witte palet gebruikt, sla het bestand dan op als twee kleurenplaatje.
  2. DitherNaarBMP16.py
    Dit programma dithert een plaatje in 7 kleuren en slaat dat meteen in een efficiënt bmp-bestand weg. Het programma gebruikt dezelfde naam als je oorspronkelijke bestand, maar dan met de extensie '.bmp'. Als je bmp-bestanden gebruikt dan wordt het oorspronkelijke bestand overschreven. Foto's en dergelijke zijn nooit bmp-bestanden en ik controleer dat dan ook niet. Het is niet moeilijk om dit zelf toe te voegen aan het programma. Als alles goed gegaan is dan leest het programma het bmp-bestand en laat dat in jouw fotobewerkingsprogramma zien. Je weet dan dat alles goed gegaan is. Sla het plaatje niet opnieuw op! Als je een foutmelding krijgt, dan kan het toch goed gegaan zijn, maar lukt het niet het resultaat te tonen.
    Als je het programma wil gebruiken voor een drie-kleuren display, pas het palet dan aan. In het algemeen krijg je met drie kleuren geen goede resultaten en kun je beter met de hand, bijvoorbeeld de lippen inkleuren. Maar uitzonderingen bevestigen deze regel.
    Helaas gebruikt het programma van de GxEPD2.h bibliotheek een bmp leesroutine, die ervan uitgaat dat er geen palet kan zijn van 7 kleuren. Ik zou dat in de bibliotheek kunnen oplossen, maar daar heeft u dan niets aan. In plaats daarvan heb ik het Python programma aangepast. Het schrijft nu altijd een palet weg van 16 kleuren. De bmp-bestanden worden hierdoor 36 bytes groter dan strikt nodig zou zijn, maar dat is te verwaarlozen.
  3. DitherZWnaarBMP.py
    Dit programma dithert een plaatje in zwart en wit en slaat dat heel efficiënt op in twee-kleuren bmp-formaat. Als je een zwart wit foto wil weergeven in twee andere kleuren, pas het palet dan aan voor de regel import os. Dat is alleen zinvol als je het resultaat op een kleurenscherm weergeeft.
  4. DitherNaar
Het kan zijn dat mijn Python code om bmp weg te schrijven veel efficiënter kan, maar het kost sowieso niet veel tijd.
Al deze programma's kunnen met bijna alle soorten plaatjesbestanden werken, maar alleen als die per pixel de rood, groen en blauw component opslaan. De meeste foto's zijn in jpeg en dat gaat automatisch goed. Als je toch een plaatje kiest dat hier niet aan voldoet dan krijg je een foutmelding en stopt het programma.
Als je de naam van je foto inclusief het pad opgeeft, dan moet je misschien de backslash \ vervangen door \\. Dus 'c:\\Plaatjes\\foto.jpg', maar ik heb dat nooit nodig gehad.
WAARSCHUWING: ik kwam er achter dat Thonny op mijn oude computer een verkeerd pad meestuurt naar mijn standaard beeldbewerkingprogramma. Misschien loop jij ook tegen dit probleem op. Het gaat wel goed met Idle, Sublime Text 3 en Visual Studio Code. Met Ubuntu ben ik geen problemen tegengekomen.

Theorie achter het ditheren in kleur of zwart-wit

Voor het ditheren gebruik ik het zogenaamde Floyd–Steinberg algoritme. Ik leg het kort uit: stel je palet bevat zeven kleuren, zoals bij een e-Paper. Je loopt het hele plaatje pixel voor pixel door. De eerste pixel vervang je door een kleur uit het palet dat zo dicht mogelijk ligt bij de echte kleur van de pixel. De afwijking tussen de oude kleur en de nieuwe kleur tel je op bij de kleuren van de naastliggende pixels, die je nog niet gehad hebt. Dat gebeurt via een bepaalde verdeelsleutel. Doordat de naastliggende pixels hierdoor een andere kleur hebben gekregen, is de kans dat ze niet de dichtst bijliggende paletkleur aannemen, maar juist een andere, die ervoor zorgt dat het geheel er beter uitziet. Een voorbeeld: je hebt twee pixels naast elkaar met de kleur oranje. Je palet heeft alleen geel en rood. Voor de eerste pixel wordt geel gekozen. De naastliggende pixel krijgt de afwijking erbij en wordt dus iets roder. Voor deze pixel wordt nu rood gekozen. Als je van afstand kijkt dan zie je ongeveer de goede kleur.

Resultaten

Als je onderstaande resultaten bekijkt pas dan op voor Moiré patronen (een soort ruitjes over het plaatje): vergroot je browser paginaweergave tot het patroon weg is (CTRL + of CTRL muiswiel werkt vaak). Ik heb de geditherde plaatjes zo opgeslagen dat je ze kunt downloaden (als bmp) en direct kunt gebruiken met de GxEPD2 bibliotheek.


Je ziet achtereenvolgens: het origineel, geditherd in zwart en wit, geditherd in rood, zwart en wit, geditherd in geel, zwart en wit en geditherd in zwart, blauw, rood, groen, oranje, geel, wit.
Afbeelding: https://wallpaperaccess.com/woman-beautiful-nature

Al de kleuren dichter bij de paletkleuren liggen wordt het resultaat nog beter:

Deze papegaai ziet er ook op het zeven-kleuren e-Paper erg goed uit!
Afbeelding op veel plaatsen te downloaden, onder andere https://wallpaperscraft.com/download/parrot_macaw_bird_132019/2072x2590

Hieronder een paar afbeeldingen van e-Papers met door dit programma geditherde plaatjes erop.

photo by Thais Silva from Pexels photo by Thais Silva from Pexels photo by Thais Silva from Pexels photo by Thais Silva from Pexels
Links: 7-kleuren 5,85" e-Paper met drie plaatjes (Photo's by Thaís Silva, Daria Shevtsova, and Luriko Yamaguchi from Pexels), daarnaast een 4" display. Rechts: zwart-wit e_Paper. De witte strip onder het 4" e-paper display is een fabricagefout.