ASCII-Art-Animation mit OpenCV

PythonPythonBeginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

In diesem Projekt werden wir OpenCV verwenden, um Bilder und Videos zu verarbeiten und ASCII-Art-Animationen zu erstellen.

  • OpenCV-Kompilierung
  • Bild- und Videoverarbeitung mit OpenCV
  • Prinzipien der Umwandlung von Bildern in ASCII-Art
  • Daemon-Threads
  • Cursor-Positionierung und Escape-Codierung

👀 Vorschau

Vorschau der ASCII-Art-Animation

🎯 Aufgaben

In diesem Projekt lernst du:

  • Wie man Bilder und Videos mit OpenCV in ASCII-Art-Animationen umwandelt.
  • Wie man ASCII-Art-Animationen im Terminal mit Cursor-Positionierung und Escape-Codierung abspielt.
  • Wie man ASCII-Art-Animationsdaten exportiert und lädt.

🏆 Errungenschaften

Nach Abschluss dieses Projekts kannst du:

  • OpenCV verwenden, um Bilder und Videos zu verarbeiten.
  • Bilder in ASCII-Art umwandeln.
  • ASCII-Art-Animationen abspielen.
  • ASCII-Art-Animationsdaten exportieren und laden.

Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/ModulesandPackagesGroup(["Modules and Packages"]) python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python(("Python")) -.-> python/FunctionsGroup(["Functions"]) python(("Python")) -.-> python/ObjectOrientedProgrammingGroup(["Object-Oriented Programming"]) python(("Python")) -.-> python/FileHandlingGroup(["File Handling"]) python/FunctionsGroup -.-> python/arguments_return("Arguments and Return Values") python/ModulesandPackagesGroup -.-> python/importing_modules("Importing Modules") python/ModulesandPackagesGroup -.-> python/using_packages("Using Packages") python/ModulesandPackagesGroup -.-> python/standard_libraries("Common Standard Libraries") python/ObjectOrientedProgrammingGroup -.-> python/classes_objects("Classes and Objects") python/ObjectOrientedProgrammingGroup -.-> python/inheritance("Inheritance") python/FileHandlingGroup -.-> python/file_reading_writing("Reading and Writing Files") python/FileHandlingGroup -.-> python/file_operations("File Operations") python/AdvancedTopicsGroup -.-> python/threading_multiprocessing("Multithreading and Multiprocessing") subgraph Lab Skills python/arguments_return -.-> lab-298850{{"ASCII-Art-Animation mit OpenCV"}} python/importing_modules -.-> lab-298850{{"ASCII-Art-Animation mit OpenCV"}} python/using_packages -.-> lab-298850{{"ASCII-Art-Animation mit OpenCV"}} python/standard_libraries -.-> lab-298850{{"ASCII-Art-Animation mit OpenCV"}} python/classes_objects -.-> lab-298850{{"ASCII-Art-Animation mit OpenCV"}} python/inheritance -.-> lab-298850{{"ASCII-Art-Animation mit OpenCV"}} python/file_reading_writing -.-> lab-298850{{"ASCII-Art-Animation mit OpenCV"}} python/file_operations -.-> lab-298850{{"ASCII-Art-Animation mit OpenCV"}} python/threading_multiprocessing -.-> lab-298850{{"ASCII-Art-Animation mit OpenCV"}} end

Datei erstellen

Jeder sollte verstehen, dass ein Video eigentlich eine Reihe von Bildern ist. Daher besteht das grundlegende Prinzip der Umwandlung eines Videos in eine ASCII-Animation darin, Bilder in ASCII-Art umzuwandeln.

Hier ist eine einfache Erklärung des Prinzips hinter der Umwandlung von Bildern in ASCII-Art: Zunächst wird das Bild in ein Graustufenbild umgewandelt, bei dem jeder Pixel nur Helligkeitsinformationen enthält (repräsentiert durch die Werte 0 - 255). Dann erstellen wir eine begrenzte Zeichensatz, bei dem jedes Zeichen einem Bereich von Helligkeitswerten entspricht. Wir können dann jeden Pixel mit dem entsprechenden Zeichen basierend auf dieser Korrespondenz und der Helligkeitsinformation des Pixels darstellen und so ASCII-Art erstellen.

Damit eine ASCII-Animation sinnvoll ist, muss sie abspielbar sein. Der primitivste und einfachste Weg, dies zu tun, besteht darin, die ASCII-Animations-Text-Datei in einem Texteditor zu öffnen und wiederholt die PageDown-Taste zu drücken. Dieser Ansatz ist jedoch wirklich zu einfach und primitiv und überhaupt nicht elegant.

Stattdessen können wir die ASCII-Animation im Terminal abspielen, indem wir jeweils einen Frame ausgeben. Dieser Ansatz hat jedoch einen großen Nachteil: Während der Wiedergabe wird der Bildlaufbalken auf der rechten Seite des Terminals immer kleiner (falls vorhanden); nach der Wiedergabe, wenn Sie im Terminal nach oben scrollen, sehen Sie nur die zuvor ausgegebene ASCII-Art, und die gesamte Befehlshistorie vor der Wiedergabe wird herausgeschoben. Eine Lösung für dieses Problem wird später in diesem Projekt vorgestellt.

Erstellen Sie eine CLIPlayVideo.py-Datei im Verzeichnis ~/project.

cd ~/project
touch CLIPlayVideo.py

Installieren Sie dann das opencv-python-Modul:

sudo pip install opencv-python

Erstellen der CharFrame-Klasse

Um es nicht zu vergessen, importieren Sie die erforderlichen Pakete:

import sys
import os
import time
import threading
import termios
import tty
import cv2
import pyprind

Das letzte Modul, pyprind, bietet eine Fortschrittsleiste zur Anzeige. Da die Umwandlung eines Videos in eine Zeichenanimation ein zeitaufwändiger Prozess ist, benötigen wir eine Fortschrittsleiste, um den Fortschritt und die ungefähre verbleibende Zeit anzuzeigen und so einen intuitiveren Einblick in den Status des Programms zu erhalten. Installieren Sie es wie folgt:

sudo pip3 install pyprind

In diesem Projekt haben wir neben der Umwandlung von Videodateien in Zeichenanimationen und deren Wiedergabe auch die Funktion hinzugefügt, Bilddateien in Zeichenkunst umzuwandeln. Daher haben wir in unserem Programmdesign drei Klassen: CharFrame, I2Char und V2Char, wobei die letzten beiden Klassen von der ersten Klasse erben.

Die CharFrame-Klasse:

class CharFrame:

    ascii_char = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "

    ## Map pixels to characters
    def pixelToChar(self, luminance):
        return self.ascii_char[int(luminance/256*len(self.ascii_char))]

    ## Convert a regular frame to an ASCII character frame
    def convert(self, img, limitSize=-1, fill=False, wrap=False):
        if limitSize!= -1 and (img.shape[0] > limitSize[1] or img.shape[1] > limitSize[0]):
            img = cv2.resize(img, limitSize, interpolation=cv2.INTER_AREA)
        ascii_frame = ''
        blank = ''
        if fill:
            blank += ' '*(limitSize[0]-img.shape[1])
        if wrap:
            blank += '\n'
        for i in range(img.shape[0]):
            for j in range(img.shape[1]):
                ascii_frame += self.pixelToChar(img[i,j])
            ascii_frame += blank
        return ascii_frame

Das Attribut ascii_char kann je nach Video, das Sie umwandeln möchten, angepasst werden.

Die Methode pixelToChar() nimmt einen einzelnen Parameter, luminance, der die Helligkeitsinformation des Pixels erhält. Es sollte beachtet werden, dass der Ausdruck in der return-Anweisung der Methode den Wert 256 verwendet. Obwohl der Helligkeitsbereich des Pixels 0~255 beträgt, kann das Ändern von 256 auf 255 in diesem Ausdruck eine IndexError-Ausnahme verursachen.

Die Methode convert() hat einen Positions- und drei optionale Parameter. Der Parameter img erhält ein Objekt vom Typ numpy.ndarray, das das Objekt ist, das OpenCV zurückgibt, wenn es ein Bild öffnet. Ebenso werden die Frames aus dem Video, die später mit OpenCV abgerufen werden, auch von diesem Typ sein. Der Parameter limitSize akzeptiert ein Tupel, das die maximale Breite und Höhe des Bildes darstellt. Der Parameter fill gibt an, ob die Breite des Bildes mit Leerzeichen auf die maximale Breite aufgefüllt werden soll, und der Parameter wrap gibt an, ob am Ende jeder Zeile ein Zeilenumbruch hinzugefügt werden soll.

img.shape gibt ein Tupel zurück, das die Anzahl der Zeilen (Höhe), Spalten (Breite) und Farbkanäle des Bildes enthält. Wenn das Bild in Graustufen vorliegt, wird die Anzahl der Farbkanäle nicht enthalten.

Die Funktion cv2.resize() wird verwendet, um das Bild zu vergrößern oder zu verkleinern. Der erste Parameter ist das numpy.ndarray-Objekt, und der zweite ist die gewünschte Breite und Höhe des vergrößerten oder verkleinerten Bildes. Der Parameter interpolation gibt die Interpolationsmethode an. Es sind mehrere Interpolationsmethoden verfügbar, wie auf der offiziellen OpenCV-Website erklärt:

Bevorzugte Interpolationsmethoden sind cv2.INTER_AREA zum Verkleinern und cv2.INTER_CUBIC (langsam) & cv2.INTER_LINEAR zum Vergrößern. Standardmäßig wird die Interpolationsmethode cv2.INTER_LINEAR für alle Größenänderungen verwendet.

img[i,j] gibt eine Liste der BGR-Werte des Pixels in der i-ten Zeile und j-ten Spalte des Bildes zurück oder den Helligkeitswert des entsprechenden Pixels für Graustufenbilder.

✨ Lösung prüfen und üben

Erstellen der I2Char-Klasse

Hier ist die I2Char-Klasse, die von CharFrame erbt:

class I2Char(CharFrame):

    result = None

    def __init__(self, path, limitSize=-1, fill=False, wrap=False):
        self.genCharImage(path, limitSize, fill, wrap)

    def genCharImage(self, path, limitSize=-1, fill=False, wrap=False):
        img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
        if img is None:
            return
        self.result = self.convert(img, limitSize, fill, wrap)

    def show(self, stream = 2):
        if self.result is None:
            return
        if stream == 1 and os.isatty(sys.stdout.fileno()):
            self.streamOut = sys.stdout.write
            self.streamFlush = sys.stdout.flush
        elif stream == 2 and os.isatty(sys.stderr.fileno()):
            self.streamOut = sys.stderr.write
            self.streamFlush = sys.stderr.flush
        elif hasattr(stream, 'write'):
            self.streamOut = stream.write
            self.streamFlush = stream.flush
        self.streamOut(self.result)
        self.streamFlush()
        self.streamOut('\n')

cv2.imread() liest ein Bild und gibt ein numpy.ndarray-Objekt zurück. Der erste Parameter ist der Pfad zum zu öffnenden Bild, und der zweite Parameter gibt die Art der Bildöffnung an und kann die folgenden drei Werte haben:

  • cv2.IMREAD_COLOR: Lädt ein Farbbild und ignoriert den Alpha-Kanal.
  • cv2.IMREAD_GRAYSCALE: Lädt das Bild im Graustufenmodus.
  • cv2.IMREAD_UNCHANGED: Lädt das Bild einschließlich des Alpha-Kanals.

Die Methode show() akzeptiert einen Parameter, der angibt, welchen Ausgabestream verwendet werden soll. 1 repräsentiert die Standardausgabe sys.stdout, und 2 repräsentiert die Standardfehlerausgabe sys.stderr. sys.stdout.fileno() und sys.stderr.fileno() geben jeweils den Dateideskriptor für die Standardausgabe und die Standardfehlerausgabe zurück. os.isatty(fd) gibt einen booleschen Wert zurück, der angibt, ob der Dateideskriptor fd geöffnet ist und mit einem TTY-Gerät verbunden ist.

✨ Lösung prüfen und üben

Erstellen der V2Char-Klasse

Nun liegt unser Fokus auf der V2Char-Klasse, die von der CharFrame-Klasse erbt.

Zunächst sollten wir über unsere Klasse nachdenken. Eines ihrer Attribute ist charVideo, eine Liste, die alle Daten für die Zeichenanimation speichert.

Dann haben wir zwei Hauptmethoden: Die eine ist die genCharVideo()-Methode, die eine Videodatei in eine Zeichenanimation umwandelt, und die andere ist die play()-Methode, die die Zeichenanimation abspielt.

Außerdem, da die Umwandlung von Video in Zeichenanimation ein zeitaufwändiger Prozess ist, können wir die Zeichenanimationsdaten aus charVideo exportieren, um die spätere Wiedergabe zu erleichtern. Das bedeutet, dass wir Export- und Lademethoden benötigen, nämlich die export()-Methode und die load()-Methode.

Die Klasse benötigt auch eine Initialisierungsmethode, die den Pfad zur Datei, die gelesen werden soll, als Parameter nimmt. Wenn es sich um eine exportierte txt-Datei handelt, ruft sie die load()-Methode auf, um die Daten in das charVideo-Attribut zu laden. Andernfalls wird sie als Videodatei behandelt und ruft die genCharVideo()-Methode auf, um das Video in eine Zeichenanimation umzuwandeln und sie im charVideo-Attribut zu speichern.

class V2Char(CharFrame):

    def __init__(self, path):
        if path.endswith('txt'):
            self.load(path)
        else:
            self.genCharVideo(path)

Als nächstes kommt die genCharVideo()-Methode:

def genCharVideo(self, filepath):
    self.charVideo = []
    cap = cv2.VideoCapture(filepath) ## Use the `cv2.VideoCapture()` method to read the video file
    self.timeInterval = round(1/cap.get(5), 3) ## Get the frame rate of the video
    nf = int(cap.get(7)) ## Get the total number of frames in the video
    print('Generate char video, please wait...')
    for i in pyprind.prog_bar(range(nf)):
        rawFrame = cv2.cvtColor(cap.read()[1], cv2.COLOR_BGR2GRAY)
        frame = self.convert(rawFrame, os.get_terminal_size(), fill=True) ## Convert the raw frame into a character frame
        self.charVideo.append(frame)
    cap.release() ## Release the resource

Die cv2.VideoCapture()-Methode wird verwendet, um die Videodatei zu lesen, und das zurückgegebene Objekt wird cap zugewiesen.

Mit der cap.get()-Methode können wir die Eigenschaften des Videos abrufen. Beispielsweise geben cap.get(3) und cap.get(4) die Breite und Höhe des Videos zurück, und cap.get(5) gibt die Bildrate des Videos zurück. cap.get(7) gibt die Gesamtzahl der Frames im Video zurück.

timeInterval speichert das Wiedergabezeitintervall, um die Bildrate der Zeichenanimation mit der des Originalvideos übereinzustimmen.

pyprind.prog_bar() ist ein Generator, der beim Iterieren eine Fortschrittsleiste im Terminal ausgibt.

cap.read() liest den nächsten Frame des Videos. Es gibt ein Tupel mit zwei Elementen zurück. Das erste Element ist ein boolescher Wert, der angibt, ob der Frame korrekt gelesen wurde, und das zweite Element ist ein numpy.ndarray, das die Daten des Frames enthält.

cv2.cvtColor() wird verwendet, um den Farbraum des Bildes zu konvertieren. Der erste Parameter ist das Bildobjekt, und der zweite Parameter gibt den Konvertierungstyp an. Es gibt über 150 Farbraumkonvertierungen in OpenCV. Hier verwenden wir die Farb-zu-Graustufen-Konvertierung cv2.COLOR_BGR2GRAY.

os.get_terminal_size() gibt die aktuelle Spaltenanzahl (Breite) und Zeilenanzahl (Höhe) des Terminals zurück. Wir setzen den fill-Parameter auf True und haben den wrap-Parameter nicht gesetzt, sodass er standardmäßig auf False steht. Im Terminal wird, wenn die gedruckten Zeichen die Breite einer Zeile überschreiten, das Terminal automatisch umbrechen.

Vergessen Sie schließlich nicht, die Ressource mit cap.release() freizugeben.

Als nächstes kommt die play()-Methode. Wie bereits erwähnt, können wir um zu verhindern, dass der Terminal nach der Wiedergabe der Zeichenanimation mit nutzlosen Zeichen gefüllt wird, Cursor-Positionierungs-Escape-Codes verwenden.

Wir können das so machen: Nachdem jeder Frame ausgegeben wurde, bewegen wir den Cursor an den Anfang der Wiedergabe, und der nächste Frame wird von dieser Position aus ausgegeben und überschreibt automatisch den vorherigen Inhalt. Wiederholen Sie diesen Vorgang, bis die Wiedergabe abgeschlossen ist, und löschen Sie dann den zuletzt ausgegebenen Frame, damit der Terminal nicht mit Zeichenkunst gefüllt wird.

Hier ist eine Reihe von Cursor-Positionierungs-Escape-Codes (einige Terminals unterstützen möglicherweise nicht alle Escape-Codes), entnommen aus The Linux Command Line:

Escape Code Aktion
\033[l;cH Bewege den Cursor zur Zeile l, Spalte c.
\033[nA Bewege den Cursor n Zeilen nach oben.
\033[nB Bewege den Cursor n Zeilen nach unten.
\033[nC Bewege den Cursor n Zeichen nach vorne.
\033[nD Bewege den Cursor n Zeichen nach hinten.
\033[2J Lösche den Bildschirm und bewege den Cursor an die Position (0, 0).
\033[K Lösche vom Cursor-Position bis zum Ende der aktuellen Zeile.
\033[s Speichere die aktuelle Cursor-Position.
\033[u Stelle die zuvor gespeicherte Cursor-Position wieder her.

Es gibt noch ein weiteres Problem: Wie kann man die Wiedergabe中途 abbrechen? Natürlich können Sie Ctrl + C drücken, aber auf diese Weise kann das Programm keine Aufräumarbeiten durchführen, und der Terminal wird mit einer Reihe von nutzlosen Zeichen gefüllt.

Wir haben es so gestaltet: Wenn die Zeichenanimation beginnt, startet es einen Daemon-Thread, der auf Benutzereingaben wartet. Sobald er eine Eingabe erhält, stoppt er die Wiedergabe der Zeichenanimation.

Hier sind zwei Dinge zu beachten:

  1. Verwenden Sie nicht die input()-Methode, um Zeichen-Eingaben zu empfangen.
  2. Verwenden Sie keine normalen Threads.

Bezüglich des ersten Punktes: Wenn Sie die Wiedergabe durch Drücken eines beliebigen Zeichens stoppen möchten, sollten Sie nicht input() verwenden. Andernfalls müssen Sie entweder Enter drücken, um die Wiedergabe zu stoppen, oder ein anderes Zeichen drücken und dann Enter, um die Wiedergabe zu stoppen. Kurz gesagt, die Verwendung von input() ist unkomfortabel. Die beste Lösung ist die Verwendung einer Methode ähnlich wie die getchar()-Methode in der Programmiersprache C. Python bietet jedoch keine ähnliche Methode, und eine alternative Lösung wird später im Code vorgestellt.

Bezüglich des zweiten Punktes: Wir müssen verstehen, dass der Hauptthread nicht beendet wird, wenn irgendein abgeleiteter Thread noch läuft, es sei denn, der abgeleitete Thread ist als Daemon-Thread festgelegt. Wenn wir also einen normalen Thread verwenden und der Benutzer ihn nicht中途 stoppt, wird er weiterlaufen, bis die Animation beendet ist, und dann wird er ewig laufen, bis der Benutzer ein beliebiges Zeichen eingibt. Wenn wir diesen abgeleiteten Thread manuell beenden könnten, wenn die Wiedergabe abgeschlossen ist, wäre das kein Problem. Python bietet jedoch keine Methode, um Threads zu beenden. Daher können wir diesen abgeleiteten Thread nur als Daemon-Thread festlegen. Wenn der Hauptthread beendet wird, wird das Programm nur noch von einem Daemon-Thread ausgeführt, und der Daemon-Thread wird automatisch beendet, wenn das Programm beendet wird.

Der vollständige Code für die V2Char-Klasse lautet wie folgt:

class V2Char(CharFrame):

    charVideo = []
    timeInterval = 0.033

    def __init__(self, path):
        if path.endswith('txt'):
            self.load(path)
        else:
            self.genCharVideo(path)

    def genCharVideo(self, filepath):
        self.charVideo = []
        cap = cv2.VideoCapture(filepath)
        self.timeInterval = round(1/cap.get(5), 3)
        nf = int(cap.get(7))
        print('Generate char video, please wait...')
        for i in pyprind.prog_bar(range(nf)):
            rawFrame = cv2.cvtColor(cap.read()[1], cv2.COLOR_BGR2GRAY)
            frame = self.convert(rawFrame, os.get_terminal_size(), fill=True)
            self.charVideo.append(frame)
        cap.release()

    def export(self, filepath):
        if not self.charVideo:
            return
        with open(filepath,'w') as f:
            for frame in self.charVideo:
                f.write(frame + '\n') ## Add a newline character to separate each frame

    def load(self, filepath):
        self.charVideo = []
        for i in  open(filepath): ## Each line is a frame
            self.charVideo.append(i[:-1])

    def play(self, stream = 1):
        ## Bug:
        ## Cursor positioning escape codes are incompatible with Windows
        if not self.charVideo:
            return
        if stream == 1 and os.isatty(sys.stdout.fileno()): ## If it's a standard output and its file descriptor refers to a terminal
            self.streamOut = sys.stdout.write
            self.streamFlush = sys.stdout.flush
        elif stream == 2 and os.isatty(sys.stderr.fileno()): ## If it's a standard error output and its file descriptor refers to a terminal
            self.streamOut = sys.stderr.write
            self.streamFlush = sys.stderr.flush
        elif hasattr(stream, 'write'): ## If it has a write attribute
            self.streamOut = stream.write
            self.streamFlush = stream.flush

        old_settings = None
        breakflag = None
        fd = sys.stdin.fileno() ## Get the file descriptor of the standard input

        def getChar():
            nonlocal breakflag
            nonlocal old_settings
            old_settings = termios.tcgetattr(fd) ## Save the attributes of the standard input
            tty.setraw(sys.stdin.fileno()) ## Set the standard input to raw mode
            ch = sys.stdin.read(1) ## Read a character
            breakflag = True if ch else False

        ## Create a thread
        getchar = threading.Thread(target=getChar)
        getchar.daemon = True ## Set it as a daemon thread
        getchar.start() ## Start the daemon thread
        rows = len(self.charVideo[0])//os.get_terminal_size()[0] ## Number of rows in the output character art
        for frame in self.charVideo:
            if breakflag is True: ## Exit the loop if input is received
                break
            self.streamOut(frame)
            self.streamFlush()
            time.sleep(self.timeInterval)
            self.streamOut('\033[{}A\r'.format(rows-1)) ## Move up `rows-1` lines to the start
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) ## Restore the standard input to its original attributes
        self.streamOut('\033[{}B\033[K'.format(rows-1)) ## Move down `rows-1` lines to the last line and clear it
        for i in range(rows-1): ## Clear all lines of the last frame from the second last line onwards
            self.streamOut('\033[1A')
            self.streamOut('\r\033[K')
        info = 'User interrupt!\n' if breakflag else 'Finished!\n'
        self.streamOut(info)
✨ Lösung prüfen und üben

Testen und Ausführen

Geben Sie den folgenden Code unterhalb des vorherigen Codes ein. Dieser Code kann als Skriptdatei verwendet werden, um ein Video in ASCII-Art umzuwandeln.

if __name__ == '__main__':
    import argparse
    ## Set command line arguments
    parser = argparse.ArgumentParser()
    parser.add_argument('file',
                        help='Video file or charvideo file')
    parser.add_argument('-e', '--export', nargs='?', const='charvideo.txt',
                        help='Export charvideo file')
    ## Get arguments
    args = parser.parse_args()
    v2char = V2Char(args.file)
    if args.export:
        v2char.export(args.export)
    v2char.play()

Geben Sie den folgenden Befehl ein, um die Datei ~/project/BadApple.mp4 in eine ASCII-Animation umzuwandeln, sie als Datei zu exportieren und die umgewandelte ASCII-Animation abzuspielen (der Codierungsprozess kann einige Minuten dauern, bitte seien Sie geduldig).

cd ~/project
python3 CLIPlayVideo.py BadApple.mp4 -e
ASCII-Animation von BadApple

Anschließend können Sie, um die Animation erneut abzuspielen, ohne sie erneut zu konvertieren, direkt die exportierte ASCII-Art-Datei lesen. Nehmen wir an, die Datei heißt charvideo.txt:

python3 CLIPlayVideo.py charvideo.txt
✨ Lösung prüfen und üben

Zusammenfassung

In diesem Projekt wird OpenCV zur Verarbeitung von Bildern und Videos verwendet. Die hier erwähnten OpenCV-Operationen sollten nur der Anfang für alle sein. Wenn Sie tiefer einsteigen möchten, sollten Sie sich öfter die offizielle Dokumentation ansehen. Durch die Verwendung eines Daemon-Threads wird hoffentlich jedem klar, was ein Daemon-Thread ist und wie er sich von einem normalen Thread unterscheidet. Schließlich haben wir uns auch mit Cursor-Positionierung und Escape-Codes beschäftigt. Obwohl dies möglicherweise nicht sehr nützlich ist, ist es dennoch eine interessante Sache, mit der man viele Dinge machen kann. Sie können gerne mehr damit experimentieren.