[PYTHON] Ich habe versucht, die Videoerstellung durch parallele Verarbeitung zu beschleunigen

langsam! !! !! Ich dachte wirklich

Ich habe versucht, Zeichen aus Untertiteln zu extrahieren (OpenCV: tesseract-ocr edition) Als Ergebnis der Bildverarbeitung mit Video 810 Sekunden (ca. 13,5 Minuten) Ich habe es verloren. Hier habe ich versucht, die Geschwindigkeit beim Erstellen von Videos durch Refactoring zu verbessern.

Methode 1 PIL <-> OpenCV

Als ich versuchte, dieselben Bilddaten von PIL nach OpenCV zu übertragen und zu verarbeiten, habe ich sie vorübergehend in einer Datei gespeichert und dann gelesen. Bei näherer Betrachtung scheint dies jedoch einfach durch Konvertieren des Numpy-Typs möglich zu sein. mit diesem 810 Sekunden (ungefähr 13,5 Minuten) -> 450 Sekunden (ungefähr 7,5 Minuten) Ich konnte es reduzieren.

Vor der Korrektur

def createTextImage(src, sentence, px, py, color=(8,8,8), fsize=28):

    #Bild speichern
    tmp_path = "src_temp.png "
    cv2.imwrite(tmp_path, src)

    #Im PIL-Objekt speichern
    img = Image.open(tmp_path)
    draw = ImageDraw.Draw(img)

    #Schreiben Sie mit PIL Text auf das Bild
    font = ImageFont.truetype("./IPAfont00303/ipag.ttf", fsize)
    draw.text((px, py), sentence, fill=color, font=font)
    img.save(tmp_path)

    #In openCV speichern
    return cv2.imread(tmp_path)

Überarbeitet

opencv(BGR) -> PIL(RGB)

cvimg = cv2.imread("sample.png ")
rgbImg = cv2.cvtColor(cvimg, cv2.COLOR_BGR2RGB)
pilImg = Image.fromarray(rgbImg)

------------------

PIL(RGB) -> opencv(BGR)
cvImg = np.array(pilImg, dtype=np.uint8)
dst = cv2.cvtColor(cvImg, cv2.COLOR_RGB2BGR)

Methode 2 Parallelverarbeitung

Früher habe ich das Lesen, Verarbeiten und Schreiben von Videos nacheinander für jeden Frame verarbeitet, aber im folgenden Ablauf habe ich ein Skript geschrieben, um nur die Verarbeitung zu parallelisieren.

Die parallele Verarbeitung verwendet "joblib". An der Rückrufquelle können Sie in fast einer Zeile schreiben, indem Sie die Einschlussverarbeitung vollständig nutzen. n_jobs = 16 ist die Anzahl der Prozesse.


from joblib import Parallel, delayed

def main_image_process(src, tool):
    
    #Lassen Sie uns hier eine Bildverarbeitung durchführen
        #Vorverarbeitung
        gray_frame = pre_process(src.content)
        #Zeichenextraktion
        #Untertitelerstellung

...
Parallel(n_jobs=16)( [delayed(main_image_process)(f, tool) for f in frames] )
...

Entwicklung von

import sys

import cv2
import io
import os
import numpy as np

import pyocr
import pyocr.builders

from PIL import Image, ImageDraw, ImageFont

from collections import namedtuple
from joblib import Parallel, delayed

import time

MovieFrame = namedtuple("MovieFrame", ["id", "content", "timestamp"])

telop_height = 50
cap_width = 1
cap_height = 1


def pre_process(src):
	kernel = np.ones((3,3),np.uint8)
	gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
        
    #Binarisierung
	o_ret, o_dst = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)
    #Öffnungsreduzierung->Erweiterung
	dst = cv2.morphologyEx(o_dst, cv2.MORPH_OPEN, kernel)
    #Umkehren
	dst = cv2.bitwise_not(dst)
    # channel 1 ->In 3 konvertieren
	dst = cv2.cvtColor(dst, cv2.COLOR_GRAY2BGR)
	return dst

#Zeichenextraktion
def extractTelopText(src, tool):

	rgbImg = cv2.cvtColor(src, cv2.COLOR_BGR2RGB)
	dst = tool.image_to_string(
		Image.fromarray(rgbImg),
		lang='jpn',
		builder=pyocr.builders.WordBoxBuilder(tesseract_layout=6)
	)

	sentence = []
	for item in dst:
		sentence.append(item.content)

	return "".join(sentence)

#Erstellen Sie leere Untertitel
def createFooterTelop(src):

	telop = np.zeros((telop_height, cap_width, 3), np.uint8)
	telop[:] = tuple((128,128,128))

	images = [src, telop]
	dst = np.concatenate(images, axis=0)
	return dst

#Parallelverarbeitung
def main_image_process(src, tool):

	#Wird verarbeitet, um die Zeichenerkennung zu vereinfachen
	gray_frame = pre_process(src.content)

	#Schneiden Sie nur dort, wo Telop wahrscheinlich erscheint
	roi = gray_frame[435:600, :]

	#Text extrahieren
	text = extractTelopText(roi, tool)
        
	#Untertitelerstellung
	dst = createFooterTelop(src.content)

	#Fügen Sie dem Bild Text hinzu
	dst = addJapaneseTelop(dst, text, 20, cap_height + telop_height - 30)
	dst = addASCIITelop(dst, str(src.timestamp) + "[sec]", cap_width - 250, cap_height + telop_height - 10, color=(0,255,0))

        #In nametuble speichern
	return MovieFrame(src.id, dst, src.timestamp)

#Fügen Sie Zeichen hinzu(Nur Alphabet)
def addASCIITelop(src, sentence, px, py, color=(8,8,8), fsize=28):

	cv2.putText(src, sentence, 
						(px, py), 
						cv2.FONT_HERSHEY_SIMPLEX, 
						1, 
						color, 
						2, 
						cv2.LINE_AA)	
	return src

#Fügen Sie Zeichen hinzu(japanisch)
def addJapaneseTelop(src, sentence, px, py, color=(8,8,8), fsize=28):

	rgbImg = cv2.cvtColor(src, cv2.COLOR_BGR2RGB)

	#openCV -> PIL
	canvas = Image.fromarray(rgbImg).copy()

	draw = ImageDraw.Draw(canvas)
	font = ImageFont.truetype("./IPAfont00303/ipag.ttf", fsize)

	#Fügen Sie Zeichen hinzu
	draw.text((px, py), sentence, fill=color, font=font)

	#PIL -> openCV	
	dst = cv2.cvtColor(np.array(canvas, dtype=np.uint8), cv2.COLOR_RGB2BGR)

	return dst

if __name__ == '__main__':

	tools = pyocr.get_available_tools()
	if len(tools) == 0:
		print("No OCR tool found")
		sys.exit(1)

	tool = tools[0]

	cap = cv2.VideoCapture('one_minutes.mp4')

	cap_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
	cap_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
	fps = cap.get(cv2.CAP_PROP_FPS)

	telop_height = 50

	fourcc = cv2.VideoWriter_fourcc('m','p','4','v')
	writer = cv2.VideoWriter('extract_telop_async.mp4',fourcc, fps, (cap_width, cap_height + telop_height))

	frames = []

	start = time.time()
	idx = 0

	#Video laden
	try :
		while True:
			if not cap.isOpened():
				break

			if cv2.waitKey(1) & 0xFF == ord('q'):
				break

			ret, frame = cap.read()

			if frame is None:
				break

			frames.append(MovieFrame(idx,frame, round(idx/fps, 4)) )
			idx += 1

	except cv2.error as e:
		print(e)

	cap.release()
	print("read movie file")
	
	#Parallelverarbeitung(Anrufer)
	r = Parallel(n_jobs=16)( [delayed(main_image_process)(f, tool) for f in frames] )

	#sort
	sorted_out = sorted(r, key=lambda x: x.id)

	#Video schreiben
	try :
		for item in sorted_out:
			writer.write(item.content)

	except cv2.error as e:
		print(e)


	writer.release()
	
	print("write movie file")
	print("Done!!! {}[sec]".format(round(time.time() - start,4)))

Andere Punkte

nametuples

Ich wollte sie alle auf einmal verarbeiten, also entschied ich mich, ein einfaches Objekt zu erstellen und versuchte, "benannte Tupel" zu verwenden.

MovieFrame = namedtuple("MovieFrame", ["id", "content", "timestamp"])

Mit dieser Option können Sie "src.id" und "src.content" sowie die Eigenschaft (Getter) festlegen, um den Code zu verkürzen.

Sortieren

Die Frames werden nach der Parallelverarbeitung aggregiert, die Reihenfolge kann jedoch leicht falsch sein. Daher wird die Anzeigereihenfolge (ID) sortiert.

sorted_out = sorted(r, key=lambda x: x.id)

Ergebnis

Was ist die Bearbeitungszeit? .. .. 267,7924 Sekunden (ungefähr 4,5 Minuten) Es wurde verkürzt auf. : tada:

Es ist ein großer Unterschied zu den ersten 810 Sekunden.

Verarbeitungszeit[sec] Verarbeitungszeit[min]
Vor der Korrektur 810 13.5
Methode 1(PIL <-> OpenCV) 450 7.5
Methode 1(PIL <-> OpenCV) +Methode 2(Parallelverarbeitung) 268 4.46

abschließend

Da es schwierig ist, eine Fehlermeldung anzuzeigen, ist es schwierig, die parallele Verarbeitung von Anfang an zu starten, es sei denn, Sie reduzieren die Anzahl der Prozesse auf eins und beseitigen den Fehler. Wenn Sie beim Hinzufügen von Zeichen auf Japanisch die Bilddaten nicht mit "canvas = Image.fromarray (rgbImg) .copy ()" duplizieren, ist eine sequentielle Verarbeitung möglich, die parallele Verarbeitung führt jedoch zu einem Fehler. Da die parallele Verarbeitung nicht ohne Vorbereitung einer kleinen Umgebung durchgeführt werden kann, ist die Verarbeitung schnell, aber es ist unvermeidlich, dass sie problematisch ist. : müdes Gesicht:

Referenzierter Link

Recommended Posts

Ich habe versucht, die Videoerstellung durch parallele Verarbeitung zu beschleunigen
Ich habe versucht, den allgemeinen Ablauf bis zur Erstellung von Diensten selbst zusammenzufassen.
Mongodb Kürzeste Einführung (3) Ich habe versucht, sogar Millionen zu beschleunigen
Ich habe versucht, durch Schaben ein Bild zu bekommen
Ich habe versucht, Drachenkugeln nach Adalin zu klassifizieren
Ich habe versucht zu debuggen.
Ich habe versucht, die Verarbeitungsgeschwindigkeit mit dplyr von R und pandas von Python zu vergleichen
Was ich getan habe, um die String-Suchaufgabe zu beschleunigen
Ich habe versucht, PredNet zu lernen
Ich habe versucht, die Erkennung von Anomalien durch spärliches Strukturlernen zu implementieren
Ich habe versucht, SVM zu organisieren.
[Einführung in die Simulation] Ich habe versucht, durch Simulation einer Koronainfektion zu spielen ♬
Ich habe versucht, PCANet zu implementieren
[Django] Ich habe versucht, Zugriffsbeschränkungen durch Klassenvererbung zu implementieren.
Ubuntu explodierte, als ich versuchte, meinen Benutzernamen zu ändern
[Einführung in Pandas] Ich habe versucht, die Austauschdaten durch Dateninterpolation zu erhöhen ♬
Ich habe versucht, MNIST nach GNN zu klassifizieren (mit PyTorch-Geometrie).
Ich habe versucht, Linux wieder einzuführen
Ich habe versucht, Pylint vorzustellen
Ich habe versucht, 100 Sprachverarbeitung klopfen 2020
Ich habe versucht, SparseMatrix zusammenzufassen
jupyter ich habe es berührt
Ich habe versucht, StarGAN (1) zu implementieren.
Ich habe versucht, einen Power BI-Bericht zu erstellen, indem ich CSV / JSON-Protokolle mit Azure Databricks verarbeitet habe
Ich habe versucht, einen einfachen Kredit-Score mit logistischer Regression zu erstellen.
[Einführung in die Simulation] Ich habe versucht, durch Simulation einer Koronainfektion zu spielen ♬ Teil 2
Ich habe versucht, die Version 2020 mit 100 Sprachverarbeitung zu lösen [Kapitel 2: UNIX-Befehle 10-14]
Ich habe versucht, den Getränkepräferenzdatensatz durch Tensorzerlegung zu visualisieren.
Beschleunigen Sie die Verarbeitung mithilfe des C ++ - Vektors unordered_map intern in Cython
Ich habe versucht, die Videowiedergabezeit anzuzeigen (OpenCV: Python-Version)
Ich habe versucht, die Satzklassifizierung durch Self Attention mit PyTorch zu implementieren
Ich habe versucht, die Befehle zusammenzufassen, die Anfängeringenieure heute verwenden
Ich ließ RNN Sin Wave lernen und versuchte vorherzusagen
Ich habe versucht, Boeing die Geigenleistung durch Posenschätzung vorzustellen
Ich habe versucht, ein Standbild aus dem Video auszuschneiden
Ich habe versucht, die Version 2020 mit 100 Sprachverarbeitung zu lösen [Kapitel 2: UNIX-Befehle 15-19]
Ich habe versucht, das Schichtplanungsproblem mit verschiedenen Methoden zu lösen
Vergleich der Stapelverarbeitungsgeschwindigkeit nach Sprache
Ich habe versucht, Deep VQE zu implementieren
Ich habe versucht, eine Quip-API zu erstellen
Numba als Python zu beschleunigen
Ich habe versucht, Python zu berühren (Installation)
Ich habe versucht, 100 Sprachverarbeitung klopfen 2020: Kapitel 3
Ich habe versucht, eine kontroverse Validierung zu implementieren
Ich habe versucht, Pytorchs Datensatz zu erklären
Ich habe Watson Voice Authentication (Speech to Text) ausprobiert.
Ich habe Teslas API berührt
Project Euler 4 Versuch zu beschleunigen
So beschleunigen Sie Python-Berechnungen
Ich habe versucht, mich über MCMC zu organisieren.
Ich habe versucht, 100 Sprachverarbeitung klopfen 2020: Kapitel 1
Ich habe versucht, Realness GAN zu implementieren
[DRF] Snippet zur Beschleunigung von PrimaryKeyRelatedField
Ich habe versucht, den Ball zu bewegen
Ich habe versucht, 100 Sprachverarbeitung zu klopfen 2020: Kapitel 2
Ich habe versucht, 100 Sprachverarbeitung zu klopfen 2020: Kapitel 4
Ich habe versucht, asynchrone Verarbeitung mit Asyncio
Ich habe versucht, den Abschnitt zu schätzen.
Ich habe versucht, die Trefferergebnisse von Hachinai mithilfe der Bildverarbeitung zu erhalten