前文提到过在静态图像上进行基于深度学习的OpenCV目标检测,为了进一步扩展,接下来做了一下实时的摄像头拍摄的视频的检测。分两步,首先,获取视频流;然后,对每一帧加入目标检测。
实时视频目标检测
还是用Python,首先创建一个real_time_object_detection.py,并插入下列代码:
# import the necessary packages
from imutils.video import VideoStream
from imutils.video import FPS
import numpy as np
import argparse
import imutils
import time
import cv2
值得说的是导入imutils,这个包的参考地址,这个包里有个VideoStream的封装,方便调用摄像头,有空会继续写camera这方面。
这里的注意这里的OpenCV版本得是OpenCV3.3或者更新的版本,才能使用深度神经网络模块dnn。
接下来是命令行参数:
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--prototxt", required=True,
help="path to Caffe 'deploy' prototxt file")
ap.add_argument("-m", "--model", required=True,
help="path to Caffe pre-trained model")
ap.add_argument("-c", "--confidence", type=float, default=0.2,
help="minimum probability to filter weak detections")
args = vars(ap.parse_args())
这些命令行参数介绍了输入的参数。相对于上一篇的目标检测,这里的输入部分不需要图片路径了,因为一会儿会读取视频流作为输入,其他的参数还是不变的:
- --prototxt: Caffe模型的路径
- --model:预训练的模型的路径
- --confidence: 能过滤弱检测器的最小的可能性的阈值,默认是20%。
然后初始化类的标签列表和包围框的颜色:
CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat",
"bottle", "bus", "car", "cat", "chair", "cow", "diningtable",
"dog", "horse", "motorbike", "person", "pottedplant", "sheep",
"sofa", "train", "tvmonitor"]
COLORS = np.random.uniform(0, 255, size=(len(CLASSES), 3))
上面创建了一个叫“CLASSES”的列表,表示能检测出来的目标的分类;COLORS是颜色列表,用于存放对应的包围框的颜色。
接下来,导入模型,并打开视频流:
# load our serialized model from disk
print("[INFO] loading model...")
net = cv2.dnn.readNetFromCaffe(args["prototxt"], args["model"])
# initialize the video stream, allow the cammera sensor to warmup,
# and initialize the FPS counter
print("[INFO] starting video stream...")
vs = VideoStream(src=0).start()
time.sleep(2.0)
fps = FPS().start()
上面这段代码,主要是导入模型并打印了相关的信息。接下来就是初始化视频流(这里可以是一段视频或者是camera实时拍摄的内容)。首先我们打开VideoStream,然后我们让camera准备起来。最后,我们启动帧计数器。这里面VideoStream和FPS都是来自于imutils包。
接下来就是在每一帧进行循环:
# loop over the frames from the video stream
while True:
# grab the frame from the threaded video stream and resize it
# to have a maximum width of 400 pixels
frame = vs.read()
frame = imutils.resize(frame, width=400)
# grab the frame dimensions and convert it to a blob
(h, w) = frame.shape[:2]
blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)),
0.007843, (300, 300), 127.5)
# pass the blob through the network and obtain the detections and
# predictions
net.setInput(blob)
detections = net.forward()
首先,我们读入一帧,修改尺寸。由于后面还需要得到这个宽高数据,把它们存入(h,w)。然后把每个frame转换为dnn模块的输入blob。
接下来是最关键的——把这个blob传入神经网络。这里我们设置了神经网络的输入,并且计算输入的前向传播,并将结果存储为“detections”。
这时,会在每一个输入的帧检测目标。这时需要看看置信值并决定什么情况下检测的结果可以用框全出来并打上标签。
# loop over the detections
for i in np.arange(0, detections.shape[2]):
# extract the confidence (i.e., probability) associated with
# the prediction
confidence = detections[0, 0, i, 2]
# filter out weak detections by ensuring the `confidence` is
# greater than the minimum confidence
if confidence > args["confidence"]:
# extract the index of the class label from the
# `detections`, then compute the (x, y)-coordinates of
# the bounding box for the object
idx = int(detections[0, 0, i, 1])
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype("int")
# draw the prediction on the frame
label = "{}: {:.2f}%".format(CLASSES[idx],
confidence * 100)
cv2.rectangle(frame, (startX, startY), (endX, endY),
COLORS[idx], 2)
y = startY - 15 if startY - 15 > 15 else startY + 15
cv2.putText(frame, label, (startX, y),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, COLORS[idx], 2)
从detectons的循环开始,记得单张图片中可能出现多个目标。我们还对每次检测应用了一个置信度的检查机制。如果置信度足够高(比如说超过了阈值),那么我们将会在终端上显示这个预测并且在图像上绘制彩色的包围框和文字,接下来我们逐句分析:
对detections进行循环,首先我们提取confidence值
如果confidence值超过了最小的阈值,我们提取类的标签序号并且计算围绕着被测物体的包围框。
然后,我们提取包围框的(x,y)坐标,用于绘制矩形和显示文字。
接下来,我们创建一个文字标签label,包含类CLASS的名字和置信度。
再继续,就是(1)显示每帧结果画面(2)检查快捷键(3)更新FPS计数器
# show the output frame
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF
# if the `q` key was pressed, break from the loop
if key == ord("q"):
break
# update the FPS counter
fps.update()
如果按‘q’跳出循环,还需要做以下处理:
# stop the timer and display FPS information
fps.stop()
print("[INFO] elapsed time: {:.2f}".format(fps.elapsed()))
print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))
# do a bit of cleanup
vs.stream.release()
cv2.destroyAllWindows()
跳出循环后,FPS计数器随之中止,同时在终端会打印出帧率信息。同时,停止视频流并关闭窗口。
- 注意,这里有一个值得关注的地方:关闭摄像头用的是vs.stream.release(),如果只用vs.stop()会导致camera图像停止读取,而camera仍然开着,资源得不到释放。只有前面这样写,才能彻底释放camera资源。
实时的深度学习目标检测结果
要运行上面的代码只要打开终端,运行
$ python real_time_object_detection.py \
--prototxt MobileNetSSD_deploy.prototxt.txt \
--model MobileNetSSD_deploy.caffemodel
就可以看到结果了
接下来有时间会写写OpenCV里面的摄像头camera操作。
参考:
https://www.pyimagesearch.com/2017/09/18/real-time-object-detection-with-deep-learning-and-opencv/