Motive Ich habe versucht, Zeichen aus Untertiteln zu extrahieren (OpenCV: tesseract-ocr edition) Google CloudVision API Ich möchte vision /) verwenden, um die Zeichen in den Untertiteln zu extrahieren.
Method Um die Google Cloud Vision-API verwenden zu können, müssen Sie zunächst ein Konto in der Google Cloud-Konsole registrieren und einen API-Schlüssel erhalten. Informationen zur Methode finden Sie unter Zusammenfassung der Verwendung der Cloud Vision-API (mit Beispielcode).
import requests
import json
import base64
import cv2
import sys
if __name__ == "__main__":
KEY = "--- your api key ---"
url = 'https://vision.googleapis.com/v1/images:annotate?key='
api_url = url + KEY
#Bild wird geladen
img_file_path = sys.argv[1]
mat = cv2.imread(img_file_path)
#Nur Untertitel-Anzeigeteil
roi = mat[435:600, :]
# openCV -> base64
result, dst_data = cv2.imencode('.png', roi)
img_content = base64.b64encode(dst_data)
#Anforderungshauptteil erstellen
req_body = json.dumps({
'requests': [{
'image': {
'content': img_content.decode('utf-8')
},
'features': [{
'type': 'DOCUMENT_TEXT_DETECTION'
}]
}]
})
#Ausstellung anfordern
res = requests.post(api_url, data=req_body)
#Holen Sie sich Bildinformationen von der Anfrage
res_json = res.json()['responses']
if 0 < len(res_json[0]):
textobj = res_json[0]['textAnnotations'][0]
print("".join(textobj["description"].strip().split("\n")))
Wenn ich eine API anfordere, entwerfe ich json, indem ich das Bild in base64 konvertiere.
src = cv2.imread("image_path")
result, dst_data = cv2.imencode('.png', src)
img_content = base64.b64encode(dst_data)
Sie können von openCV mit konvertieren.
Darüber hinaus ist es ausreichend, Zeichen zu extrahieren, während die API so wie sie ist sequentiell verarbeitet wird. Die Verarbeitungsgeschwindigkeit erhöht sich jedoch, wenn die parallele Verarbeitung mit "asyncio" durchgeführt wird. Der Grund für die Verwendung von "asyncio" ist, dass es stabiler als "multiprocessing.Pool" ist, da es die API-Antwortverarbeitung innerhalb des Collouts blockiert.
async def main_image_process(src):
#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 = await extractTelopText(roi)
await asyncio.sleep(2)
dst = await createFooterTelop(src.content)
dst = await addJapaneseTelop(dst, text, 20, cap_height + telop_height - 30)
dst = await addASCIITelop(dst, str(src.timestamp) + "[sec]", cap_width - 250, cap_height + telop_height - 10, color=(0,255,0))
return MovieFrame(src.id, dst, src.timestamp)
if __name__ == "__main__":
r = []
loop = asyncio.get_event_loop()
try:
r = loop.run_until_complete(
asyncio.gather(*[main_image_process(f) for f in frames])
)
finally:
loop.close()
Es scheint, dass es einfacher mit Python 3.7 oder höher geschrieben werden kann, aber es ist noch nicht stabil und das Standardpaket von centOS war Python 3.6, also schreibe ich es basierend auf 3.6.
Development
Der ganze Code.
import sys
import cv2
import io
import os
import numpy as np
import base64
import json
import requests
import asyncio
from PIL import Image, ImageDraw, ImageFont
from collections import namedtuple
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)
o_ret, o_dst = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)
dst = cv2.morphologyEx(o_dst, cv2.MORPH_OPEN, kernel)
dst = cv2.bitwise_not(dst)
dst = cv2.cvtColor(dst, cv2.COLOR_GRAY2BGR)
return dst
async def extractTelopText(src):
KEY = "--- your api key ---"
url = 'https://vision.googleapis.com/v1/images:annotate?key='
api_url = url + KEY
message = ""
result, dst_data = cv2.imencode('.png', src)
img_content = base64.b64encode(dst_data)
#Anforderungshauptteil erstellen
req_body = json.dumps({
'requests': [{
'image': {
'content': img_content.decode('utf-8')
},
'features': [{
'type': 'DOCUMENT_TEXT_DETECTION'
}]
}]
})
#Ausstellung anfordern
res = requests.post(api_url, data=req_body)
#Holen Sie sich Bildinformationen von der Anfrage
res_json = res.json()['responses']
if 0 < len(res_json[0]):
textobj = res_json[0]["textAnnotations"][0]
message = "".join(textobj["description"].strip().split("\n"))
return message
async 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
async def main_image_process(src):
#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 = await extractTelopText(roi)
await asyncio.sleep(2)
dst = await createFooterTelop(src.content)
dst = await addJapaneseTelop(dst, text, 20, cap_height + telop_height - 30)
dst = await addASCIITelop(dst, str(src.timestamp) + "[sec]", cap_width - 250, cap_height + telop_height - 10, color=(0,255,0))
return MovieFrame(src.id, dst, src.timestamp)
async 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
async def addJapaneseTelop(src, sentence, px, py, color=(8,8,8), fsize=28):
rgbImg = cv2.cvtColor(src, cv2.COLOR_BGR2RGB)
canvas = Image.fromarray(rgbImg).copy()
draw = ImageDraw.Draw(canvas)
font = ImageFont.truetype("./IPAfont00303/ipag.ttf", fsize)
draw.text((px, py), sentence, fill=color, font=font)
dst = cv2.cvtColor(np.array(canvas, dtype=np.uint8), cv2.COLOR_RGB2BGR)
return dst
if __name__ == '__main__':
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
#read frame
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")
#process
r = []
loop = asyncio.get_event_loop()
try:
r = loop.run_until_complete(
asyncio.gather(*[main_image_process(f) for f in frames])
)
finally:
loop.close()
#sort
sorted_out = sorted(r, key=lambda x: x.id)
#write frame
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)))
Result
tesseract-ocr Verarbeitungszeit: 450 Sekunden ≒ 7,5 Minuten
GoogleCloudVisionAPI
Verarbeitungszeit: 1315 Sekunden ≒ 21 Minuten
Die asynchrone Verarbeitung bei Verwendung einer externen API hat eine Weile gedauert. Sie können jedoch feststellen, dass die Google CloudVision-API für die OCR-Genauigkeit besser geeignet ist.
Future Das nächste Mal denke ich darüber nach, das Video von Ich habe das Objekt mithilfe der Bildreparatur (inpaint) (OpenCV: C ++) zu bearbeiten. Ich denke darüber nach, es C ++ basierend auf dem von mir verwendeten Code zu machen. Wenn es darum geht
Reference
Recommended Posts