Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

ws2122:asciia:ascii-animation.py

Dies ist eine alte Version des Dokuments!


ASCII-Animation.py

import cv2 # muss extra installiert werden mit: pip install opencv-python
import os
from os import system
import shutil
import readchar # muss extra installiert werden mit: pip install readchar
import time
import timeit
import pyfiglet # muss extra installiert werden mit: pip install pyfiglet
import colorama
from colorama import Fore, Back, Style
colorama.init()
import threading
import sys
import AsciiBildConverter as abc
import Abbruch as abh
abh.Abbruchsignal()

An dieser Stelle werden lediglich externe Bibliotheken und unsere Hilfsdateien importiert. Beachtet werden muss nur, dass cv2 (opencv), readchar und pyfiglet standardmäßig nicht bei Python installiert sind.

# Methode für korrekte Eingabe der Ja/Nein Abfragen, ArtZahl ist für welche Eingabe gemeint ist (beliebig erweiterbar)
def Eingabepruefung(pruefe, ArtZahl):
    while True:
        if pruefe == "j" or pruefe == "n":
            if pruefe == "j":
                return True
            elif pruefe == "n":
                return False
        else:
            if ArtZahl == 0:
                print ("Das war keine gültige Taste. Drücke j für Invertierung oder n für Normal: ")
                pruefe = readchar.readkey().lower()
            elif ArtZahl == 1:
                print("Das war keine gültige Taste. Drücke j für Ja (Farbauswahl) oder n für Nein (Default-Farbe): ")
                pruefe = readchar.readkey().lower()
 
# Methode für korrekte Eingabe der Farben
def FarbAnalyse(Farbe):
    while True:
        if Farbe == "BLACK" or Farbe == "RED" or Farbe == "GREEN" or Farbe == "YELLOW" or Farbe == "BLUE" or Farbe == "MAGENTA" or Farbe == "CYAN" or Farbe == "WHITE":
            return Farbe
        else:
            Farbe = input("Das war keine gültige Farbe. Gib erneut eine Farbe ein: ").upper()

Diese Methoden prüfen, ob die Nutzereingaben (zu Farbauswahl, Farben, Invertierung) gültig sind und verlangen bei Ungültigkeit neue Eingaben.

# Methode für langsames Drucken der Buchstaben
def LangsamesDrucken(text):
    for a in text:
        print(a, end='')
        sys.stdout.flush()
        time.sleep(0.08)

Die Methode ist für das langsame Ausgeben der Buchstaben vom Intro-Text zuständig (Schreibmaschinenstil).

def BilderAusVideo(): # Wird mit neuem Thread gleichzeitg zum Konvertieren ausgeführt
    cap = cv2.VideoCapture(videoname)
    frameNummer = 0
    while True: # Endlos-Schleife bis break
        if abh.thread_Pause == False:
            success, frame = cap.read() # success ist, ob das Einlesen des Bildes erfolgreich war
            if success:
                cv2.imwrite("Bildercache/frame%d.jpg" % frameNummer, frame) # Speicherung der Frames (im Unterordner)
            else:
                break
            frameNummer = frameNummer+1
        else:
            time.sleep(0.2)
        if abh.thread_kill:
            break

Diese Funktion ist für das Speichern der Frames aus dem Video zuständig. Weiter unten wird ein zusätzlicher Thread für die Methode ausgeführt, sodass das Umwandeln der Frames zu ASCII und die anschließende Ausgabe gleichzeitig passieren kann.

# main
_ = system("cls") # Cleart Bildshirm
for a in range(8):
    print("")
 
asciiBanner = pyfiglet.figlet_format("Ascii-Animation")
print(asciiBanner)
 
LangsamesDrucken("Willkommen bei der ASCII-Animation!")
time.sleep(0.5)
print("\nGib hier den korrekten Dateinamen des Videos, inklusive der Dateiendung, ein. Die Datei muss sich im selben Ordner befinden!: ")
videoname = input()
 
print("Sollen die Zeichen invertiert sein? Drücke j für Invertierung oder n für Normal: ")
invertierung = readchar.readkey().lower()
booleanInvertierung = Eingabepruefung(invertierung, 0) # Zahl ist für Ordnung in der Methode
time.sleep(0.2)
print("Willst du eine Farbauswahl für die Zeichen und dem Hintergrund haben? Drücke j für Ja oder n für Nein (Default-Farbe): ")
farbeJa_Nein = readchar.readkey().lower()
booleanFarbe = Eingabepruefung(farbeJa_Nein, 1) # Zahl ist für Ordnung in der Methode
 
if booleanFarbe:
    print("Mögliche Farben für die Zeichen und den Hintergrund: black, red, green, yellow, blue, magenta, cyan, white")
    vorFarbe = input("Gib die Farbe der Zeichen ein: ").upper() # Vordergrundfarbe-Eingabe (Zeichenfarbe)
    vorFarbe = FarbAnalyse(vorFarbe) # analysiert, ob richtiger Farbwert
    hinFarbe = input("Gib die Farbe des Hintergrunds ein: ").upper() # Hintergrundfarbe-Eingabe
    hinFarbe = FarbAnalyse(hinFarbe) # analysiert, ob richtiger Farbwert
else:
    vorFarbe = "WHITE"
    hinFarbe = "BLACK"
 
# Übertrag der Farbwerte zu Abbruch (für globale Variable)
abh.AbbruchFarbeZuweisung (vorFarbe, hinFarbe)

Das ist der Anfang der Main-Methode. Hier ist eine Benutzeroberfläche für das Einlesen der Videodatei und eine Abfrage der veränderlichen Eigenschaften (Invertierung, Farbwahl).

ordnerName = 'Bildercache'
if os.path.exists(ordnerName):
    shutil.rmtree(ordnerName)
os.makedirs(ordnerName)

Der Datei erstellt den Ordner für die Bilder, mit einem Fehlerabfang, falls dieser schon existiert.

cap = cv2.VideoCapture(videoname)
anzahlFrames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
fps = int(cap.get(cv2.CAP_PROP_FPS))
 
# übertragt FPS und Variable für Invertierung oder nicht (für globale Variable)
abc.UebertrageZuConverter(fps, booleanInvertierung) 
 
# Thread für fast gleichzeitiges Ausführen von Bilder aus Video und Konvertieren
t1 = threading.Thread(target=BilderAusVideo, args=())
t1.start() # Thread Start

Hier werden die Videoinformationen verarbeitet und gespeichert. Außerdem startet hier der zusätzliche Thread mit der Methode „BilderAusVideo“ (siehe oben). Dadurch passiert der Teil ab hier bis unten zum „t1.join()“ parallel zu der Methode aus dem Threading.

zeit = 0
while (zeit <= 100):
    print("Loading...",zeit,"%", end="\r")
    zeit += 1
    time.sleep(0.05) # 0.05 -> 5 Sekunden warten

Hier ist ein Ladebalken für die Vorlaufszeit, damit erst ein paar Frames aus dem Video genommen werden, bevor das Umwandeln zu ASCII passiert.

# für Hintergrundfarbe und Zeichenfarbe
print(getattr(Fore, vorFarbe) + getattr(Back, hinFarbe), end="\r") # getattr ändert char/string in Attribut
 
# Wandelt frames in ASCII um, bis alle Dateien umgewandelt wurden                                                                   
for i in range (anzahlFrames):
    start = timeit.default_timer()
    abc.Umwandlung(i)
    ende = timeit.default_timer()
    dauer = ende - start # Messung der Berechnungszeit für die Umwandlung
    pause = 1/fps - (dauer + 0.003)
    if pause < 0:
        pause = 0
    # Einstellung der Frames pro Sekunde durch Pausieren zwischen jedem Bild (hier ~30 FPS)
    time.sleep(pause)
t1.join() # Thread Ende bei erfolgreichen Abschließen der Schleifen
 
shutil.rmtree('Bildercache') # Löscht kompletten Bildercache
print(Style.RESET_ALL)

Die for-Schleife geht alle Frames durch und ruft jedes mal die Datei „AsciiBildConverter“ auf, in der ein „normales“ Bild zu einem ASCII-Bild umgewandelt wird. Dabei haben wir noch einen Timer implementiert, welcher die Zeit misst, damit die Videowiedergabe annähernd wie die vom Originalvideo ist. Allerdings ist das immer noch nicht optimal, weil die Berechnung dafür auch Mikrosekunden benötigt. Am Programmende wird der Cache mit den Bildern gelöscht.

ws2122/asciia/ascii-animation.py.1648307700.txt.gz · Zuletzt geändert: 2022/03/26 16:15 von MoscarTU