【使用树莓派和YOLO——打造一个“穷人版”深度学习摄像头】
摘要: 本文主要是根据亚马逊推出的DeepLens原理,通过树莓派以及检测网络模型YOLO搭建一个用于检测鸟儿的智能摄像头,操作起来简单方便,可实践性强。感兴趣的读者可以按照步骤一步步搭建属于自己的一款智能摄像头吧!
亚马逊最近推出深度学习摄像头DeepLens,这是一个智能摄像头,能够利用机器学习来检测物体、面孔以及一些活动场景,比如弹吉他等。这款相机定价为249美元,计划于2018年4月在美国发售。虽然目前无法上手使用这款黑科技产品,但是智能摄像头的创意想法真是令人兴奋。
想象一下,在我们弹吉他、创作一段新的舞蹈或者学习一项新的滑板技巧时,可以通过一个摄像头告诉我们正在做的事情是多么神奇的一件事啊。摄像头使用原始图像数据来判断你是否炫了一个新的滑板技巧,或是在尝试一个新的舞蹈系列动作时,告诉我们这套舞蹈有哪些动作以及如何将动作与音乐节拍协调起来等。智能相机的使用场景非常广泛,有待众人来开发。说到这里,读者有没有动心去赶紧尝试一下这类黑科技产品呢?虽然买不到成熟的产品,但是本文将带领读者通过树莓派以及YOLO搭建一个深度学习摄像头,它的功能是检测何时有鸟儿出现在摄像头的图像中,如果发现图像中存在鸟儿,就保存这张有鸟儿的照片,最终的结果如下图所示:
深度学习摄像机是机器学习计算机全新平台的开始。DeepLens有100GFlops的计算能力,可以推断出,这仅仅是一个有趣的深度摄像机计算机所需的计算能力的开始。相信在不久的将来,这类设备的计算能力会变得更加强大,功能也会更加完善。但是谁想等到以后呢?那么现在就开始动手设计吧!
可以智能推理的“哑”摄像机
为了在摄像机中建立一个深度学习模型,我们使用一台“哑”摄像计算机(比如9美元的树莓派),将其连接到一个摄像头上,然后通过WIFI发送图像。在权衡时延问题后,可以建立一个类似于DeepLens产品且更便宜的智能摄像头。本文将用Python编写一个网络服务器,该服务器将树莓派上的图像传送到另外一台计算机上以完成推理或图像检测。
另外一台计算机具有更强的处理能力,将使用“YOLO”模型对输入图像进行检测,如果摄像头的视野中存在鸟儿时,计算机将会告诉我们这一点。
“YOLO”结构是最快的检测模型,可以在许多不同平台上运行,非常方便。本文搭建的模型非常小,因此可以在CPU上完成运行并得到检测结果,而不必在昂贵的GPU上运行。
我们的设想是当摄像头视野中检测到一只鸟儿时,就保存该图像以供后续分析,得到图像仅仅是深度学习摄像头的开始。
检测VS成像
由于DeepLens的成像是嵌入于计算机中,因此它可以进行基础类别检测,并能确定图像是否符合设定的标准或者是否与计算能力相匹配。但是类似于树莓派这类硬件,不一定具有实时检测所需的计算能力,因此将使用另外一台计算机来推断图像中的内容。本文使用的是一个简单的Linux计算机来作为深度学习机器推理的服务器,该计算机连接着一个摄像头和WIFI接口(树莓派3和一个便宜的摄像头)。这是一个很好的服务器栈,因为它能够连接许多外部摄像头,并在台式机上完成所有的计算。
摄像头图像服务器栈
如果不想使用树莓派摄像头,那么可以在树莓派上安装OPenCV3代替摄像头的功能。一旦完成这些步骤,只需要设置好网络服务器,然后就可以从摄像头处得到图像。本文初步使用的摄像头服务器代码为 Miguel Grinberg的经典服务器代码:
1 |
1 |
#!/usr/bin/env pythonfrom importlib import import_moduleimport osfrom flask import Flask, render_template, Response# uncomment below to use Raspberry Pi camera instead# from camera_pi import Camera# comment this out if you're not using USB webcamfrom camera_opencv import Cameraapp = Flask(__name__)@app.route('/')def index(): return "hello world!"def gen2(camera): """Returns a single image frame""" frame = camera.get_frame() yield frame@app.route('/image.jpg')def image(): """Returns a single current image for the webcam""" return Response(gen2(Camera()), mimetype='image/jpeg')if __name__ == '__main__': app.run(host='0.0.0.0', threaded=True) |
如果想使用树莓派摄像头,那么需要确保代码中没有注释from camera_pi这一行,而from camera_opencv这一行被注释掉。
之后使用Python3 app.py或gunicorn运行服务器。当服务器没有接收到请求时,使用Miguel优秀的摄像管理机制关闭摄像头;或者是当服务器接收到多个请求时,使用该管理机制来处理多线程问题。
一旦启动了树莓派,就能够通过浏览器访问其IP地址来测试并确保服务器正常工作。其URL地址应该类似于http://192.168.1.4:5000/image.jpg:
从摄像头服务器中提取图像并进行推理
现在有了一个可以从摄像头获取图像的端点,就可以构建脚本程序完成图像的抓取并进行推理。我们将使用python中常用的第三方库request以及Darkflow和在Tensorflow上实现的YOLO模型,不幸的是无法通过pip安装Darkflow,只能通过拷贝安装。
在安装完Darkflow后,下载一个将要使用的YOLO模型以及相关权重参数。本文中,使用的是YOLO v2微小版,这是因为本文是在CPU上完成整个模型的运行,而不是GPU。与YOLO v2模型相比,微小版网络损失了一些精度。
当以上步骤完成后,还需要在电脑上安装Pillow、numpy以及OpenCV。最后,编写代码以运行检测:
1 |
1 |
from darkflow.net.build import TFNetimport cv2from io import BytesIOimport timeimport requestsfrom PIL import Imageimport numpy as npoptions = {"model": "cfg/tiny-yolo-voc.cfg", "load": "bin/tiny-yolo-voc.weights", "threshold": 0.1}tfnet = TFNet(options)birdsSeen = 0def handleBird(): passwhile True: r = requests.get('http://192.168.1.11:5000/image.jpg') # a bird yo curr_img = Image.open(BytesIO(r.content)) curr_img_cv2 = cv2.cvtColor(np.array(curr_img), cv2.COLOR_RGB2BGR) result = tfnet.return_predict(curr_img_cv2) print(result) for detection in result: if detection['label'] == 'bird': print("bird detected") birdsSeen += 1 curr_img.save('birds/%i.jpg' % birdsSeen) print('running again') time.sleep(4) |
以上就是我们的第一个非常基础的版本,能够在控制台上看到树莓派正在检测的物体,也可以浏览硬盘中保存的每一只鸟儿图像。之后可以运行一个程序标记出YOLO检测出的图像上检测到的鸟儿。
权衡:更多的假阳性还是假阴性?
需要注意到,在选择字典中创建的门限秘钥。这个阈值表明摄像头中的物体为我们要检测物体的信心。为了测试,本文将该阈值设置为0.1,但是这个低阈值给我们带来了很多误报。此外,使用的YOLO微小模型的精度一直比真正的YOLO模型要低,所以会有一些错误的检测。
降低或提高阈值能够提升或减少模型的输出,这取决于你想创建的内容。在本文中,倾向于有更多的假阳性,但是更希望得到更多的鸟儿图像。所以这点需要各人权衡以满足各自的需求。
之后就是等待鸟儿的到来,此外本文的代码可以在GitHub上下载。由于本文结合了许多前人的工作,所以内容不是很多。但是这篇文章是作者尝试与鸟类互动系列课程的开始,如果各位读者感兴趣的话,可以在此订阅后续内容。
作者信息
Kirk Kaiser,艺术家和软件开发工程师。