使用Python进行视频流OCR
Posted 程序媛一枚~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Python进行视频流OCR相关的知识,希望对你有一定的参考价值。
这篇博客将介绍如何使用Python,进行视频流OCR;
Optical Character Recognition OCR光学字符识别
之前的博客介绍了如何使用快速傅立叶变换(FFT)检测图像和文档中的模糊。使用这种方法,能够检测出模糊、低质量的图像,然后提醒用户应该尝试捕获更高质量的版本,以便能够对其进行OCR。
这篇博客将介绍如何对视频流进行OCR。首先需要检测模糊、低质量的帧过滤掉,只对足够质量的帧进行OCR。原理是使用FFT。
由于光照条件、相机镜头自动聚焦和运动模糊的快速变化,视频自然会有低质量的帧。
需要检测这些低质量的帧并丢弃它们,而不是试图对这些低质量的帧进行OCR,这最终会导致低OCR精度(或更糟的,完全没有意义的结果)。
检测低质量帧的一种简单方法是使用模糊检测。因此使用FFT模糊检测器处理视频流。保证OCR管道能够在视频流上运行,同时仍保持高精度。
1. 效果图
OCR视频效果图如下:
正确识别某一帧非模糊,及ocr卡片内容效果图如下:
顶部原始图:包含字符串模糊(Blurry)非模糊(Not Blurry)及fft计算得到的平均幅值;原始图上绘制卡片边框;
中间是卡片的自顶向下的鸟瞰图;同时绘制了识别的字符串边框;
底部是pytesseart识别出的字符串;(可以看到柿子中英文识别正确,英文persimmon识别完全,底部的水果有些模糊并未正确识别)
模糊直接丢弃不进行ocr效果图如下:
2. 原理
- 编写操作高质量图像的计算机视觉代码总是比编写低质量图像容易。使用FFT模糊检测方法有助于确保只有更高质量的图像进入管道。
- FFT模糊检测器还有另一个用途——它可以用来丢弃视频流中的低质量帧,否则OCR将无法处理这些帧。 由于照明条件的快速变化(例如,在阳光明媚的日子里走进黑暗的房间)、相机镜头的自动对焦或最常见的运动模糊,视频流自然会有低质量的帧。
识别中文需要单独设置 pytesseart
# 转换颜色空间,以进行ocr
rgb = cv2.cvtColor(card, cv2.COLOR_BGR2RGB)
# lang=chi_sim+eng 检测中文+字母+数字
# --psm 11 检测稀疏编码,可以设置 --psm 6
results = pytesseract.image_to_data(rgb,
lang='chi_sim+eng',
config='--psm 11',
output_type=Output.DICT)
3. 源码
# USAGE
# python ocr_video.py --input images/card.mp4 --output output/ocr_video_output.avi
# helpers.py: #工具类,将视频OCR脚本的输出作为单独的输出视频写入磁盘
# blur_detection: 子模块,检测视频流中的模糊帧
# video_ocr: 将视频ocr的结果写入单独的视频文件
# images/x.mp4:要进行ocr的视频文件
# output/x.avi: ocr结果的单独视频文件
# visualization.py: 可视化输出检测结果,包括3部分:1. 检测到名片且注释模糊/不模糊的原始输入框(顶部)
# 2. 检测到文本的名片的自顶向下转换(中间)
# 3. 自顶向下转换的OCR文本本身(底部)
# 导入必要的包
import argparse
import time
import cv2
import imutils
import numpy as np
import pytesseract # 提供Tesseract OCR的接口
from imutils.perspective import four_point_transform # (四点变换):应用透视变换,以获得正在OCR'ing的名片的自顶向下/鸟瞰视图
from imutils.video import VideoStream
from pytesseract import Output
from blur_detection.blur_detector import detect_blur_fft # fft模糊检测器
from pyimagesearch.helpers import addChiText # cv2.imshow添加中文
from pyimagesearch.helpers import cleanup_text # 清理OCR文本,去掉非ASCII字符,这样就可以使用cv2在输出图像上绘制OCR文本
from video_ocr.visualization import VideoOCROutputBuilder # 可视化生成器
# 构建命令行参数及解析
# --input 可选输入视频路径
# --output 可选输出视频路径,默认使用网络摄像头。
# --min-conf 过滤弱检测的置信度参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--input", type=str, default='images/card.mp4',
help="path to optional input video (webcam will be used otherwise)")
ap.add_argument("-o", "--output", type=str,
help="path to optional output video")
ap.add_argument("-c", "--min-conf", type=int, default=50,
help="minimum confidence value to filter weak text detection")
args = vars(ap.parse_args())
# 初始化videoOcrOutputBuilder,以轻松可视化
outputBuilder = None
# 初始化输出视频写入器和输出视频的空间维度
writer = None
outputW = None
outputH = None
# 创建一个命名的窗口,以进行输出Ocr可视化,以及设置窗口位置
# 使用cv2.moveWindow函数在屏幕上移动窗口。需要执行移动操作,因为输出窗口的大小是动态的——它将随着输出的增长和收缩而增长。
cv2.namedWindow("Output")
# 初始化一个布尔变量:显示使用Webcam还是输入视频文件
webcam = not args.get("input", False)
# 如果未提供视频路径,获取网络摄像头指针
if webcam:
print("[INFO] starting video stream...")
vs = VideoStream(src=0).start()
time.sleep(2.0)
# 否则,获取视频流指针
else:
print("[INFO] opening video file...")
vs = cv2.VideoCapture(args["input"])
# i = 0
# 遍历每一帧
while True:
# 获取摄像头/文件流的帧,并处理
orig = vs.read()
orig = orig if webcam else orig[1]
# 如果获取的是视频流文件,且没有获取到帧,则表示到达了文件末尾
if not webcam and orig is None:
break
orig = orig + 50 # 照片太暗,批量加亮50
orig = orig[200:700, :]
# 调整帧大小,计算新宽度与旧宽度的比率
# 将透视变换应用于原始高分辨率帧时,将需要此比率。
frame = imutils.resize(orig, width=500)
ratio = orig.shape[1] / float(frame.shape[1])
# 如果VideoOCROutputBuilder视频可视化器是None,初始化它
if outputBuilder is None:
outputBuilder = VideoOCROutputBuilder(frame)
# 初始化卡片和Ocr输出 ROIs
card = None
ocr = None
# 转换帧为灰度图,fft检测文本/文档模糊
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
(mean, blurry) = detect_blur_fft(gray, thresh=-9)
# 绘制是否模糊,模糊红色,不模糊绿色
color = (0, 0, 255) if blurry else (0, 255, 0)
text = "Blurry (:.4f)" if blurry else "Not Blurry (:.4f)"
text = text.format(mean)
cv2.putText(frame, text, (10, 25), cv2.FONT_HERSHEY_SIMPLEX,
0.7, color, 2)
# 卡片ROI将包含名片的自上而下转换(如果在当前帧中找到名片),而ocr将包含ocr文本本身。
# 只有当帧不模糊时,进行Ocr检测
if not blurry:
# cv2.imwrite("images/card" + str(random.randint(0, 100)) + ".jpg", orig)
# 使用高斯核对帧进行平滑,执行边缘检测
blurred = cv2.GaussianBlur(gray, (7, 7,), 0)
edged = cv2.Canny(blurred, 75, 200)
# 在边缘图中寻找轮廓,按面积大小倒序排列取前5个
# 名片将是具有四个顶点的输入帧中最大的ROI
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:1]
# 初始化轮廓线列表和卡片对应
cardCnt = None
# 遍历轮廓
for c in cnts:
# # 近似轮廓
# peri = cv2.arcLength(c, True)
# approx = cv2.approxPolyDP(c, 0.02 * peri, True)
#
# # 如果有4个顶点,则认为找到了卡片的边缘线
# if len(approx) == 4:
# cardCnt = approx
# break
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
box = np.int0(box)
cardCnt = box
# 如果找到了卡片,则进行ocr
if cardCnt is not None:
# 在帧上绘制轮廓线
cv2.drawContours(frame, [cardCnt], -1, (0, 255, 0), 3)
# 对原始的高分辨率图像应用透视变换(以便更好地进行OCR
# 对卡片应用4点透视变换以获取自上而下的鸟瞰图
card = four_point_transform(orig,
cardCnt.reshape(4, 2) * ratio)
# 开辟空间以用于可视化
ocr = np.zeros(card.shape, dtype="uint8")
# 转换颜色空间,以进行ocr
rgb = cv2.cvtColor(card, cv2.COLOR_BGR2RGB)
# lang=chi_sim+eng 检测中文+字母+数字
# --psm 11 检测稀疏编码
results = pytesseract.image_to_data(rgb,
lang='chi_sim+eng',
config='--psm 11',
output_type=Output.DICT)
# 使用ocr文本本身对输出ocr可视化进行注释
# 遍历每一个识别出的单独的文本
for i in range(0, len(results["text"])):
# 提取当前文本的边界框
x = results["left"][i]
y = results["top"][i]
w = results["width"][i]
h = results["height"][i]
# 提取文本和置信度值
text = results["text"][i]
conf = int(float(results["conf"][i]))
# 过滤弱检测
if conf > args["min_conf"]:
# 去除非ASCII码来处理文本
text = cleanup_text(text)
# 处理后的文本非空,在文本周围绘制边界框
if len(text) > 0:
cv2.rectangle(card, (x, y), (x + w, y + h),
(0, 255, 0), 2)
# cv2.putText(ocr, text, (x, y - 10),
# cv2.FONT_HERSHEY_SIMPLEX, 0.5,
# (0, 0, 255), 1)
# 添加中文字体
ocr = addChiText(ocr, text, (x, y - 10), (255, 0, 0), 25)
# 构建最终ocr可视化输出
output = outputBuilder.build(frame, card, ocr)
# 检查是否设置输出视频文件路径,及视频写入器
if args["output"] is not None and writer is None:
# 获取输出视频帧维度及初始化视频写入器
output = imutils.resize(output, height=600)
(outputH, outputW) = output.shape[:2]
fourcc = cv2.VideoWriter_fourcc(*"MJPG")
writer = cv2.VideoWriter(args["output"], fourcc, 27,
(outputW, outputH), True)
# 如果视频写入器非空,写入输出到单独视频文件
if writer is not None:
# 强制调整视频流输出以匹配输出视频的维度
outputFrame = cv2.resize(output, (outputW, outputH))
writer.write(outputFrame)
# 展示可视化结果
cv2.imshow("Output", imutils.resize(output, height=600))
# i = i + 1
# cv2.imwrite("imgs/" + str(i) + ".jpg", cv2.resize(output, (250, 600)))
cv2.moveWindow("Output", 0, 0)
key = cv2.waitKey(1) & 0xFF
if not blurry:
key = cv2.waitKey(0)
else:
key = cv2.waitKey(1) & 0xFF
# 按下‘q’键,退出循环
if key == ord("q"):
break
# 释放视频指针
# 如果使用网络摄像头
if webcam:
vs.stop()
# 如果使用视频流指针
else:
vs.release()
# 关闭所有窗口
cv2.destroyAllWindows()
参考
以上是关于使用Python进行视频流OCR的主要内容,如果未能解决你的问题,请参考以下文章
使用 Amazon Rekognition API 进行文本检测和 OCR
使用 Amazon Rekognition API 进行文本检测和 OCR