使用Amazon Echo和树莓派来自己动手做一个门铃:每个月仅花费几分钱就可以识别在你门口成千上万的访客。
最近我准备在新房子里安装一个门铃时想到:为什么不让我的门铃告诉我谁在门口?
我自己动手做的大部分项目的成本都高于其它同等产品,即便我已经把自己的时间价值定为每小时0美元。我想这可能是跟供应链和经济规模相关。但是我在自己制作这些东西的过程中得到了更多的乐趣。在这个项目中我攒了一个门口摄像头,它不仅比我的Dropcam便宜而且还有一些真正有用的功能,由于某些原因这些功能我在市场还没有见到过。
图1 我的前门有一个门铃、一个August键盘锁和一个用于人脸识别的树莓派。图片由Lukas Biewald提供
我们会攒一个成本60美元的基于树莓派的安全摄像头装置,用来拍摄照片并将其传到云端然后进行人脸识别。你还可以将数据流上传到Amazon S3,使其成为一个完整的Dropcam替代品。Nest为保存最近10天的视频每年会收取100美元,但你可以只花费大约20美元在S3中保留一年的视频文件。如果你使用Amazon Glacier,这笔费用将会降到4美元左右。
使用Amazon ReKognition进行机器学习
本教程会重点关注机器学习的部分——使用亚马逊新的Rekogniction服务来对你的访客进行人脸识别,然后将识别结果发送到你的Amazon Echo,这样你就可以始终知道谁在你的门口了。为了构建可靠的服务,我们还会使用Amazon最酷、最有用的产品之一:Lambda。
组成部件:
Amazon Echo Dot(50美元)
树莓派3代(38美元)(该项目也可以使用树莓派2代加上无线USB网卡)
树莓派兼容相机(16美元)
树莓派保护壳(6美元)
16GB SD卡(8美元)
总计:118美元
我们会使用Amazon的S3、 Lambda和Rekognition 服务来进行人脸匹配。这些服务开始是免费的,之后你每月仅花费几分钱就可以识别在你门口成千上万的访客。
配置树莓派系统
如果你已经完成了我的任何一篇树莓派教程,那么你将会很熟悉这篇教程的大部分内容。
首先从树莓派基金会上下载Noobs,并按照安装说明进行操作。这主要包括将Noobs复制到SD卡上,再将SD卡插到你的板子上,然后将鼠标、键盘和显示器插到你的板子上并按照安装说明操作。这些操作自从新的桌面环境Pixel推出以来就变得更容易了。
图2 我桌子上连着微型显示器和键盘的树莓派。图片由Lukas Biewald提供
然后将你的树莓派系统命名成你可以记住的名字,以便你可以SSH访问它。这在howtogeek上有很好的说明指南——你需要修改/etc/hosts和/etc/hostname文件并给你的树莓派系统命名。我喜欢将所有的安保摄像头树莓派用我最喜欢的电视节目“费城总是晴朗”中的角色来命名,所以我将前门的摄像头命名为“Dennis”。这意味着我不需要记住一个IP地址就可以随时SSH访问到dennis.local,即使重置了路由器也可以。
接下来你应该将摄像头连接到树莓派板子上。记住带状电缆正面应该面向以太网插孔——这个问题我可能已经Google了一百次了。备注:如果你想要一个更广的视野,你可以买一个广角摄像头;如果你想要增加夜视功能,你可以买一个红外线摄像头。
图3 准备安装的带有摄像头和外壳的树莓派。图片由Lukas Biewald提供
你可能也想把整个装置都放在一个保护壳中,以保护它免受天气的影响。你还需要将树莓派通过微型USB电缆连接到电源。(我已经在墙上钻了一个小洞将我的Dropcam连接到室内电源插座上,所以我在合适的位置上已经有了一个USB电缆。)
目前为止我已经在房子周围安装了几个这样的装置了。相机带状电缆很薄,你可以将树莓派安装在房间内部,并将电缆就像我在我的实验室(车库)里做的那样从门上穿过。
图4 树莓派上的摄像头从我的车库门上穿出来。 图片由Lukas Biewald提供
接下来你需要安装RPi-Cam-Web界面。这是一个非常有用的软件,它通过http协议从摄像头中提供连续的数据流。请遵循安装说明,并选择NGINX作为Web服务器。在/etc/raspimjpeg中有一个非常有用的配置文件可以用来配置大量选项。
配置Amazon S3和Amazon Rekognition
如果你尚未创建AWS账号,则需要现在创建。你应该先创建一个IAM用户,并让该用户可以访问S3、Rekognition和Lambda(稍后我们会使用Lambda)。
安装AWS命令行界面:
sudo apt install awscli
将你的树莓派的地区设置为美东(截止本文撰写时间,Rekognition仅在此区域可用)
创建一个人脸识别组:
aws create-collection –collection-id friends
你可以使用我写的unix shell脚本来快速添加你朋友的人脸图片:
aws s3 cp $1 s3://doorcamera > output
aws rekognition index-faces \
–image “{\”S3Object\”:{\”Bucket\”:\”doorcamera\”,\”Name\”:\”$1\”}}” \
–collection-id “friends” –detection-attributes “ALL” \
–external-image-id “$2”
将其复制到一个文件中作为shell脚本。或者在命令行里输入它,并将$1替换成你朋友图片的本地文件名,把$2换成你朋友的名字。
Amazon的 Rekognition服务使用机器学习来得到人脸图片上点与点之间的距离,然后使用这些点来匹配其索引中的人脸图像。因此你可以仅使用你朋友的一张图像来训练系统就可能得到很好的结果。
现在你可以用类似的脚本来测试这个人脸识别系统:
aws s3 cp $1 s3://doorcamera > output
aws rekognition search-faces-by-image –collection-id “friends” \
–image “{\”S3Object\”:{\”Bucket\”:\”doorcamera\”,\”Name\”:\”$2\”}}”
你会得到返回的一个很大的JSON文件,其中不仅仅有匹配结果,还有图像的其它方面信息,包括性别、表情、面部毛发和一堆其它有趣的东西。
{
“FaceRecords”: [
{
“FaceDetail”: {
“Confidence”: 99.99991607666016,
“Eyeglasses”: {
“Confidence”: 99.99878692626953,
“Value”: false
},
“Sunglasses”: {
…
接下来我们可以编写一个Python脚本从我们的树莓派摄像机中下载一个图片并检查其中的脸部。实际上我用了第二台树莓派来实现这一功能,但是运行在同一台机器上会更容易。只需要查看/dev/shm/mjepg/cam.jpg文件,你就会知道一个所对应的摄像头的图像文件。
无论哪种方式,我们需要在Web服务器中暴露此接口功能以供后面使用。我使用Flask作为我的Web服务器。
from flask import Flask, request
import cameras as c
app = Flask(__name__)
@app.route(‘/faces/’)
def face_camera(camera):
data = c.face_camera(camera)
return “,”.join(data)
if __name__ == ‘__main__’:
app.run(host=’0.0.0.0′, port=5000)
我把解析代码(以及本文提到的所有其它代码)都放在了github.com/lukas/facerec上。
如果你已经操作到了这一步,你已经能有一些非常有趣的可以用来玩的东西了。我发现Amazon服务在识别我朋友的方面是极好的。唯一看起来有些麻烦的地方就是识别我的情绪(尽管这可能更多的是我的问题而不是Amazon)。
实际上我将其中一个树莓派摄像头缝进了一个毛绒玩具里,并把一个非常令人毛骨悚然的能进行人脸识别的泰迪熊哨兵放在了我的桌上。
图5 可人脸识别的泰迪熊Freya。图片由Lukas Biewald提供
人脸识别摄像头跟Amazon Echo搭配使用
Amazon的Echo使得高品质的语音命令变得非常简单,并且对这种项目来说有着完美的接口。不幸的是,使用Echo的最好方式是让它跟一个稳定的Web服务进行直接通信,但是我们想把树莓派摄像头放在路由器防火墙后面的本地网络——这使得配置有点棘手。
我们将Echo连接到一个AWS Lambda服务上,它会通过SSH通道跟我们的树莓派系统通信。这可能有点复杂,但这是最简单的方法。
图6 架构图。图片由Lukas Biewald提供
通过SSH 通道暴露HTTP 人脸识别API接口
到目前为止我们已经构建了一个用于人脸识别的小网络应用,我们还需要让外部世界可以访问它。只要我们在某个地方有一个Web服务器,我们就可以配置一个SSH通道。不过有一个叫做localtunnel的甜美小应用程序为我们做了这一切,你可以轻松地安装它:
npm install -g localtunnel
我喜欢用一个小脚本来包装一下它,使其处于活动状态防止它挂掉。请把MYDOMAIN改为对你有意义的内容:
until lt –port 5000 -s MYDOMAIN; do
echo ‘lt crashed… respawning…’
sleep 1
done
现在你可以通过访问http://MYDOMAIN.localtunnel.me 来ping一下你的服务器。
创建一个Alexa Skill
要使用我们的Echo,我们需要创建一个新的Alexa Skill。Amazon有一个很好的入门指南,或者你可以直接访问Alexa开发者门户网站。
首先我们需要设定一个intent:
{
“intents”: [
{
“intent”: “PersonCameraIntent”,
“slots”: [
{
“name”: “camera”,
“type”: “LIST_OF_CAMERAS”
}
]
}]}
然后我们给Alexa一些样例Utterance:
PersonCameraIntent tell me who {camera} is seeing
PersonCameraIntent who is {camera} seeing
PersonCameraIntent who is {camera} looking at
PersonCameraIntent who does {camera} see
接下我们需要给Alexa一个结束点,为此我们将使用一个Lambda函数。
配置一个Lambda函数
如果你从未使用过Lambda的函数,那本文让你赚到了!Lambda函数是一种在Amazon服务器上为一个简单函数定义一个统一API的简单方法,并只有在调用时才会付费。
Alexa Skill 是Lambda函数的完美用例,所以Amazon已经配置了一个可用的用于Alexa Skill的模板。当Alexa与我们列出的PersonCameraIntents的其中一项匹配时,它将会调用我们的Lambda函数。将MYDOMAIN改为你的本地通道脚本中使用的域名,这样一切就会运行的很好。
你还可以使用Amazon Rekognition发送的元数据中的其它有趣之处。例如,它可以猜测面部表情,所以我通过它去判断在我门口的是一位开心的访客还是一个生气的访客。你还可以让Echo告诉你访客是否有胡子、戴太阳眼镜和其它一些特征:
def face_camera(intent, session):
card_title = “Face Camera”
if ‘camera’ in intent[‘slots’]:
robot = intent[‘slots’][‘camera’][‘value’]
try:
response = urlopen(‘http://MYDOMAIN.localtunnel.me/faces/%s’ % robot)
data = response.read()
if (data== “Not Found”):
speech_output = “%s didn’t see a face” % robot
else:
person, gender, emotion = data.split(“,”)
if person == “” or person is None:
speech_output = “%s didn’t recognize the person, but ” % robot
else:
speech_output = “%s recognized %s and ” % (robot, person)
if gender == “Male”:
speech_output += “he ”
else:
speech_output += “she ”
speech_output += “seems %s” % emotion.lower()
except URLError as e:
speech_output = “Strange, I couldn’t wake up %s” % robot
except socket.timeout, e:
speech_output = “The Optics Lab Timed out”
else:
speech_output = “I don’t know what robot you’re talking about”
should_end_session = False
return build_response({}, build_speechlet_response(
card_title, speech_output, None, should_end_session))
原文发布时间为:2017-04-20