使用Tensorflow,OpenCV和Docker进行实时和视频处理对象检测
在本文中,我将介绍如何在Docker容器中设法使用Tensorflow Object-detection API来执行实时(网络摄像头)和视频后期处理。我用python3多处理和多线程库来使用OpenCV。
数据科学Docker
我不会花时间描述Tensorflow对象检测API的实现,因为在这个主题上有很多文章。相反,我将展示如何在作为数据科学家的全天工作中使用Docker。请注意,我使用Tensorflow的经典ssd_mobilenet_v2_coco模型来提高性能。我在本地(在模型/目录中)复制模型(.pb文件)和相应的标签贴图以保留稍后使用个人模型的可能性。
我相信今天使用Docker成为主要的数据科学家技能。在数据科学和机器学习领域,每周都会发布大量新算法,工具和程序,并将它们安装到您的计算机上,以测试它们是导致操作系统崩溃的最佳方式(有经验的!)。为了防止这种情况,我现在使用Docker容器来创建我的数据科学工作区。
# Install tensorFlow
RUN pip install -U tensorflow
# Install tensorflow models object detection
RUN git clone https://github.com/tensorflow/models /usr/local/lib/python3.5/dist-packages/tensorflow/models
RUN apt-get install -y protobuf-compiler python-pil python-lxml python-tk
#Set TF object detection available
ENV PYTHONPATH "$PYTHONPATH:/usr/local/lib/python3.5/dist-packages/tensorflow/models/research:/usr/local/lib/python3.5/dist-packages/tensorflow/models/research/slim"
RUN cd /usr/local/lib/python3.5/dist-packages/tensorflow/models/research && protoc object_detection/protos/*.proto --python_out=.
安装OpenCV:
# Install OpenCV
RUN git clone https://github.com/opencv/opencv.git /usr/local/src/opencv
RUN cd /usr/local/src/opencv/ && mkdir build
RUN cd /usr/local/src/opencv/build && cmake -D CMAKE_INSTALL_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local/ .. && make -j4 && make install
实时对象检测
我首先尝试将对象检测应用于我的摄像头流。Dat Tran的文章充分描述了这项工作的主要部分。困难在于将网络摄像头流发送到码头容器并恢复输出流以使用X11服务器显示它。
发送视频流到容器中
在Linux中,设备位于/ dev /目录中,可以作为文件进行操作。通常,您的笔记本电脑摄像头是“0”设备。要将其流发送到docker容器中,请在运行docker映像时使用device参数:
docker run --device=/dev/video0
从容器中恢复视频流
首先,您必须公开您的xhost,以便容器可以通过读写X11 unix套接字来呈现正确的显示。首先设置X服务器主机的权限(这不是最安全的方式),让Docker访问它:
xhost + local:docker
然后,一旦完成使用该项目,将访问控制返回其默认值:
xhost -local:docker
然后,创建两个环境变量XSOCK和XAUTH:
XSOCK = / tmp / .X11-unix
XAUTH = / tmp / .docker.xauth
第一个引用X11 Unix套接字,第二个引用具有我们现在创建的适当权限的X身份验证文件:
xauth nlist $ DISPLAY | sed -e's /^..../ ffff /'| xauth -f $ XAUTH nmerge -
最后,我们只需更新我们的docker run line命令。我们转发DISPLAY环境变量,为X11 Unix套接字和X身份验证文件装入一个名为XAUTHORITY的环境变量,该变量链接到它:
docker run -it --rm --device = / dev / video0 -e DISPLAY = $ DISPLAY -v $ XSOCK:$ XSOCK -v $ XAUTH:$ XAUTH -e XAUTHORITY = $ XAUTH
现在我们可以运行我们的容器并完成了:
OpenCV需要通过使用cv2.imshow函数调用python脚本(init-openCV.py)来“初始化” 。我收到以下错误消息:
The program 'frame' received an X Window System error.
然后,可以调用主python脚本(my-object-detection.py),并将视频流很好地发送到主机显示屏。我对使用第一个python脚本来初始化X11系统的解决方案并不是很满意,但到目前为止我还没有发现任何解决这个问题的方法。
视频处理
为了管理我的摄像头实时运行对象检测API,我使用了线程和多处理的 python库。线程用于读取网络摄像头流。帧被放入队列以供工作人员处理(其中运行Tensorflow对象检测)。
对于视频处理目的,不可能使用线程,因为在工作人员能够在放入输入队列的第一个应用对象检测之前读取所有视频的帧。输入队列已满时读取的帧将丢失。也许使用大量的工人和巨大的队列可能会解决问题(计算成本过高)。
简单队列的另一个问题是由于分析时间不断变化,帧不会以与输入队列中相同的顺序在输出队列中发布。
要添加我的视频处理功能,我删除线程来读取帧。相反,我使用以下几行代码来读取帧:
while True:
# Check input queue is not full
if not input_q.full():
# Read frame and store in input queue
ret, frame = vs.read()
if ret:
input_q.put((int(vs.get(cv2.CAP_PROP_POS_FRAMES)),frame))
如果输入队列未满,则从视频流中读取下一帧并将其放入队列中。否则,当帧没有从输入队列中获取时,没有任何操作。
为了解决帧顺序的问题,我使用了一个优先级队列作为第二个输出队列:
读取帧并将其放入输入队列中,并输入相应的帧号(实际上是将一个python列表对象放入队列中)。
然后,工作人员从输入队列中取出帧,对它们进行处理,并将它们放入第一个输出队列(仍保留其相对帧号)。
while True:
frame = input_q.get()
frame_rgb = cv2.cvtColor(frame[1], cv2.COLOR_BGR2RGB)
output_q.put((frame[0], detect_objects(frame_rgb, sess, detection_graph)))
3.如果输出队列不为空,则帧将被提取并放入优先级队列,其相应的帧号作为优先级号。优先级队列的大小可以任意设置为其他队列大小的三倍。
# Check output queue is not empty
if not output_q.empty():
# Recover treated frame in output queue and feed priority queue
output_pq.put(output_q.get())
4.最后,如果输出优先级队列不为空,则获取具有最高优先级(先前最小编号)的帧(这是标准优先级队列工作)。如果先验对应于期望的帧号,则帧被添加到输出视频流(并且如果需要,则写入),否则帧被放回到优先级队列中。
# Check output priority queue is not empty
if not output_pq.empty():
prior, output_frame = output_pq.get()
if prior > countWriteFrame:
output_pq.put((prior, output_frame))
else:
countWriteFrame = countWriteFrame + 1
# Do something with your frame
为了停止这个过程,我检查所有队列是否为空,并且所有帧都已经从视频流中提取出来:
if((not ret)&input_q.empty()&
output_q.empty()&output_pq.empty()):
break
完整的代码:https://github.com/lbeaucourt/Object-detection