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.
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)
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] )
...
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)))
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.
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)
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 |
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:
Recommended Posts