Dies ist eine alte Version des Dokuments!
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.
# 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 Cacheordner 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.