简介
-
最近在做的一个项目中需要对自然场景的文本进行检测,查找文献后发现了一个性能较好的文本检测器——EAST Text Detector,应用这个模型后确实得到了较为鲁棒的效果。
-
完全应用这个模型需要配置较多环境(tensorflow、gpu等),后来在一篇外文博客上发现opencv的dnn模块可以加载这个模型并直接应用,这篇博客十分通俗的介绍了如何使用python-opencv应用这一模型。征得原作者允许,我打算介绍我通过这篇博客应用这一模型的过程(和翻译差不多,但有一些自己的想法)。并且欢迎关注该作者的网站pyimagesearch,一个非常不错的深度学习和计算机视觉的入门进阶网站。
性能简要介绍
模型具体介绍可以点击上面连接进入原论文深入了解,我就不介绍了(主要是我也不太懂)。但博客说该模型特点如下:
- 对于720p的视频,在实时状态下可以跑出~13FPS,但可能是在GPU平台。
- 在我电脑上实测(联想小新pro13 r5-4600U),一张480x640的图片检测一次(包括nms)平均需要200ms,也就是cpu下~5FPS的速度,还算可以。
- 仍然保持高水准(state-of-the-art)的准确率,这倒是不假,效果是可以令人接受的。
模型应用
环境准备
- Win10
- python3
- opencv > 3.0
基本参数
为了方便应用,我们把这个检测器携程一个类,类名为TexTDetector。
TextDetector.py
import cv2
from object_detection import non_max_suppression
import numpy as np
import time
import global_vars as gv
class TexTDetector:
# model_path: 模型路径
def __init__(self, model_path):
# 输入网络的图片尺寸(必须为8的倍数)
self.rw = 320
self.rh = 320
# 最小置信度
self.min_confidence = 0.5
self.net = cv2.dnn.readNet(model_path)
self.layerNames = [
"feature_fusion/Conv_7/Sigmoid",
"feature_fusion/concat_3"]
cv2.dnn.readNet可以读取网络,加载模型数据,而我们感兴趣的网络部分:
- sigmiod给出检测出的文本区域的置信度
- concat_3给出文本区域对应的几何数据
文本检测函数
def detect_text(self, image):
(imgh, imgw) = image.shape[:2]
# 记录原图像大小与缩小后的比值,得到预测结果后需要乘上这个缩放因子
rW = imgw / float(self.rw)
rH = imgh / float(self.rh)
# 放缩到网络可以接受的尺寸
image = cv2.resize(image, (self.rw, self.rh))
# 图像预处理
blob = cv2.dnn.blobFromImage(image, 1.0, (self.rw, self.rh), (123.68, 116.78, 103.94), swapRB=True, crop=False)
self.net.setInput(blob)
# 前向传播,获得置信度和几何数据
(scores, geometry) = self.net.forward(self.layerNames)
(rows, cols) = scores.shape[2:4]
rects = []
confidences = []
# 对得到的框进行筛选,先用最小置信度进行粗筛选
for i in range(rows):
scoresData = scores[0, 0, i]
xData0 = geometry[0, 0, i]
xData1 = geometry[0, 1, i]
xData2 = geometry[0, 2, i]
xData3 = geometry[0, 3, i]
anglesData = geometry[0, 4, i]
for j in range(cols):
if scoresData[j] < self.min_confidence:
continue
(offsetX, offsetY) = (j * 4.0, i * 4.0)
angle = anglesData[j]
cos = np.cos(angle)
sin = np.sin(angle)
h = xData0[j] + xData2[j]
w = xData1[j] + xData3[j]
endX = int(offsetX + (cos * xData1[j]) + (sin * xData2[j]))
endY = int(offsetY - (sin * xData1[j]) + (cos * xData2[j]))
startX = int(endX - w)
startY = int(endY - h)
rects.append((startX, startY, endX, endY))
confidences.append(scoresData[j])
# 再使用非极大值抑制算法细筛选
rects = np.array(rects)
pick = non_max_suppression(rects, probs=confidences)
boxes = rects[pick]
# 得到最终的文本框
boxes[:, [0, 2]] = (boxes[:, [0, 2]] * rW).astype(np.int32)
boxes[:, [1, 3]] = (boxes[:, [1, 3]] * rH).astype(np.int32)
return boxes
关键地方已有注释。
注意:这里非极大值抑制(nms)的实现还未给出,正常是没有imutils这个包的,这时候有两个途径:
- 直接下载博主实现的图像处理包imutils 。
pip install imutils
- 直接进入imutils的链接,复制 /imuils/object_detection.py 的代码,放在同一文件夹。我也是用这种方式,而且还需要修改一个地方:
# return only the bounding boxes that were picked
return boxes[pick].astype("int")
改为
return pick
应用
-
下载EAST预训练模型,并与代码放在同一文件夹
-
使用demo
import TextDetector as td
import cv2
import os
model_path = r'./frozen_east_text_detector.pb'
textModel = td.TextDetector(model_path)
# 你的图片路径
img_path = r'your image path'
for each in os.listdir(img_path):
img = cv2.imread(os.path.join(img_path, each))
try:
boxes = textModel.detect_text(img)
for (x, y, ex, ey) in boxes:
cv2.rectangle(img, (x, y), (ex, ey), (0, 255, 0), 2)
cv2.imshow('demo', img)
# 按下esc键退出
if cv2.waitKey(100) == 27:
cv2.destroyAllWindows()
break
Except IndexError:
print('no boxes is detected!')
效果
我还是放我项目的一个小视频吧!