树莓派教程 - KittyCam:在 Node.js 中构建一个带有猫脸部检测器

哈哈哈! 对于我在夏天工作的项目,这是一个逾期的博客文章!

去年八月,我使用摄像机和 PIR 运动传感器创建了这个树莓派的应用程序,用 Node.js 编写,并基于 Johnny-Five 和 KittyDar 完成。正如我在 GitHub repo 的 README 文件中所承诺的那样,我终于写下了如何构建硬件和编写应用程序的详细说明。

步骤0:KittyCam 是如何工作的

该软件是使用 Node.js 编写的,因为 JavaScript 是我最舒服的语言,也很有趣!

这是基本流程:

  1. 检测动作(使用 Johnny-Five IR.Motion 对象)
  2. 拍照(Raspistill,命令行工具)
  3. 猫面部检测(KittyDar)
  4. 将照片存储在云存储(Cloudinary)
  5. 将数据(URL)发布到 PubNub 以进行实时流式传输
  6. 在网上输出流(订阅来自 PubNub 的数据)

KittyCam 架构

硬件与软件的通信是使用 Johnny-Five,这个开源 JavaScript 机器人编程框架完成的。我正在使用它与 PIR 传感器进行通信。当传感器检测到我的猫(或任何移动的物体)附近的树莓派,它会触发相机。

使用 raspistill 命令行拍摄照片。Node.js 有一个很酷的事情就是,你可以通过派生子进程来执行命令。

照片拍摄完成后,我正在使用另一个子进程来检测照片上是否有猫,使用的是由 Heather Arthur 编写的用于猫的开源脸部检测 KittyDar

此外,我正在将照片(只有猫的照片)发送到云端存储,同时我使用 PubNub 将照片传输到网络浏览器,因为我正在为公司工作!

现在,让我们建立自己的 KittyCam!

步骤1:树莓派 2 搭建电路

你需要的东西

首先,你需要获得包含 Raspberry Pi 2 的一些硬件。我不推荐任何老的 Raspberry Pi,因为它们的内存太低,无法运行一些代码。Raspberry Pi 需要预先安装 Raspbian 操作系统。

电路连接图

  • 树莓派 2(带WiFi适配器)
  • 5MP 相机板模块
  • 热释电红外(PIR)运动传感器
  • 3 条母对母电线
  • 可选:乐高兼容 SmartiPi w/相机盒

连接硬件

这不需要太多的接线。您可以将相机和 PIR 传感器目录连接到 Raspberry Pi,而无需使用任何面包板或焊接,如您在上一节中的照片,或者如下面的 Fritzing 图所示。

Raspberry Pi Camera 连线图

Camera 连接 Pi

将相机模块连接到 CSI 端口。 请参阅关于如何在 Raspberry Pi 上设置相机模块的视频说明

PIR 传感器连接 Pi

  • 1 条红线:PIR-VCC 到 Raspberry Pi 的 5V 引脚
  • 1 条黑线:PIR-GND 到 Raspberry Pi的地线(GND 引脚)
  • 1 条任何颜色的线:PIR-OUT 到 Raspberry Pi 的引脚7(GPIO 4)

步骤2:从 Mac 远程工作

您可以将显示器,键盘,鼠标等插入到您的 Raspberry Pi 中,直接在 Raspbian GUI 上工作,或者像在平时一样使用 Mac 工作。这是我在 Mac 上远程工作的方式:

SSH 到 Raspberry Pi

首先,确保你的 Raspberry Pi 和电脑在同一个 WiFi 网络上。

如果直接将 Raspberry Pi 连接到显示器和键盘,请打开一个终端,然后找到 IP 地址:

pi@raspberrypi ~$ hostname -I

或者在 Mac 上使用一些 IP 扫描仪应用程序,如 “Angry IP Scanner” 扫描所有连接的设备。

找到 IP 地址后,在 Mac 上打开终端应用程序,然后输入地址。 我使用 Raspberry Pi 的默认用户名 “pi”。

tomomi@Mac ~$ ssh pi@10.0.1.13

然后输入密码。 默认是 “raspberry”。

一旦连接到您的 Raspberry Pi,您可以创建文件,代码,并从终端执行。 Raspbian 是基于 Debian 的,所以你可以使用通常的 linux 命令。

在 Mac 上编码

我通常使用 Sublime Text 来编写代码,所以我更喜欢在 Raspberry Pi 上编写代码。 这就是我所做的:

首先,在 Mac 上下载并安装 Cyberduck

然后通过 SSH 使用它的 IP 地址,连接你的 Pi。

编辑文件时,用 “Edit” 打开文件。

就我而言,它会自动选择 Sublime Text 来编辑 JavaScript 文件。

步骤3:软件搭建

1. 在 Raspberry Pi 上安装 Node.js

首先,确保 Raspberry Pi 已经更新到最新:

$ sudo apt-get update

然后:

$ sudo apt-get upgrade

下载并安装

下载 Node.js 的 ARM 版本:

$ wget http://node-arm.herokuapp.com/node_archive_armhf.deb

然后安装包:

$ sudo dpkg -i node_archive_armhf.deb

检测 Node 是否安装成功:

$ node -v

2. 启用相机访问

为了能够在您的 Raspberry Pi 上使用硬件摄像头模块,您需要先启用软件。

从终端进入 Pi Software Config Tool 菜单:

$ sudo raspi-config

使用箭头键选择Enable Camera

点击返回,然后在下一个屏幕上选择 Enable。

通过在终端上输入这个命令,来测试你的摄像头是否工作正常:

$ raspistill -o photo.jpg

步骤4:安装依赖

如果您希望从我的 GitHub 仓库运行代码,请在 GitHub 上复制 RPi-KittyCam 仓库,并将其复制到 Raspberry Pi 上。

如果执行 $npm install 就能成功安装所有的依赖关系,这将是非常好的,但是,不幸的是,它不能以这种方式工作。 您仍然需要手动设置和安装依赖关系。

1. 先决条件:安装 Cairo 到系统

对于猫面部检测,我正在使用 kittydar,其中依赖包括 node-canvas,这需要 Cairo

所以,让我们先来看看你的 Raspbian 的 Cairo 吧。

$ sudo apt-get install libcairo2-dev libjpeg8-dev libpango1.0-dev libgif-dev build-essential g++

有关如何为 Node Canvas 安装 Cairo 的更多信息,请参阅 Installation Ubuntu and other Debian based systems

如果您下载了我的 GitHub 仓库的 node_modules 内容,请跳过第 2 步,然后继续执行第 3 步。否则,请转至下一步手动重新安装接下来的几个模块。只是运行 npm install来获取所有的依赖关系可能会失败,因为有一些不兼容。 (我稍后解释)。

2. 安装依赖模块

现在,cd 到你的工作目录,并安装依赖关系。

安装 Canvas

您需要 canvas (node-canvas),才能够使用 KittyDar 分析图像。

$ sudo npm install canvas

安装 KittyDar

Kittydar 是一个开源的猫脸检测。它需要一个图像(画布),并告诉你,如果猫在图像中。

Cat

这是我的 Raspberry Pi 拍摄的真实照片,而 Jamie 正在吃东西,并且被 KittyDar 猫面部检测发现!

一旦你的环境设置好了,在这个 RPi-KittyCam 目录下,安装 Node.js 依赖模块。

理想情况下直接安装:

npm install kittydar —save

但是,node-canvas 1.0.1(package.json 中为 KittyDar 指定的版本)无法使用当前的 Node.js(v0.12.6)进行构建。

所以,我所做的是从 github repo 下载 zip 到 node_modules。修改 package.json 中的 canvas:〜1.0.1 为 ^ 1.0.1,以便安装最新的 canvas 作为我从 kittydar 目录安装 npm。

注意:尽管作者不再维护项目,但我正在发送有关修正的请求。

安装 Johnny-Five

Johnny-Five 是一个 JavaScript 机器人编程框架。这使得与硬件的通信变得更加容易。

$ npm install johnny-five

安装 Raspi-io

Raspi-io 是一个用作 Johnny-Five 的 I/O 插件的库。你需要安装这个在 Raspbian 上使用 Johnny-Five:

$ npm install raspi-io

3. 安装第三方服务模块

如果您不想创建 Web 界面来传输照片,或者您宁愿创建自己的 Web 服务器而不依赖于第三方服务,则此步骤是可选的。

安装 PubNub

为了实时更新 Web 界面,我正在使用 PubNub。要使用该服务,您需要注册以获取您的 API 密钥。

$ npm install pubnub

安装 Cloudinary

要存储照片,请使用 Cloudinary。要使用该服务,您需要注册以获取您的 API 密钥。

$ npm install cloudinary

在 config.js 中配置证书

在应用程序的根目录中创建一个 config.js。该文件应包含您的 API 密钥:

module.exports = {
  cloudinary: {
    cloud_name: 'your_name',
    api_key: 'your_API_key',
    api_secret: 'your_API_secret',
  },
  pubnub: {
    subscribe_key: 'your_sub_key',
    publish_key: 'your_pub_key'
  }
};

4.运行代码

一旦你配置完所有的东西,并从我的 GitHub 仓库获得所有源文件,请尝试运行 kittyCam.js。

你必须用 sudo 运行:

$ sudo node kittyCam.js

当 PIR 传感器检测到运动时,相机将拍摄照片。然后运行 child_process 来检测照片中是否有猫。有猫的时候,把照片发给 Cloudinary。

分析的照片从文件系统中删除,以保护 Pi 的干净。

5. 在Web上查看实时照片更新

从 gh-pages 分支获取网页界面源代码。

在浏览器上运行 index.html

KittyCam 截图

步骤5:代码

虽然我没有写一个完整的教程——如何从头开始编写这个 Node 应用程序,但我可以解释一些关键的功能。

从 PIR 传感器检测运动

我正在使用 Johnny-Five 的 IR.Motion 对象来检测动作。

首先,包括依赖关系。

然后,在引脚7 上创建一个新的运动硬件实例,并在检测到运动时拍摄照片:

var raspi = require('raspi-io');
var five = require('johnny-five');
var board = new five.Board({io: new raspi()});

board.on('ready', function() {

  var motion = new five.Motion('P1-7');

  motion.on('motionstart', function() {
    // Run raspistill command to take a photo with the camera module  
    // then detect cats from the photo
  })
});

用子进程执行命令

在上面的代码片段中,第一个注释是,使用 child_process.spawn() 运行 raspistill 命令来拍摄相机模块的照片:

var filename = 'photo/image_'+i+'.jpg';
var args = ['-w', '320', '-h', '240', '-o', filename, '-t', '1'];
var spawn = child_process.spawn('raspistill', args);

spawn.on('exit', function(code) {
  console.log('A photo is saved as '+filename+ ' with exit code, ' + code);
  i++;

  // Detect cats from photos - see the next section
  ...

在这里,我正在按顺序保存照片。

使用 KittyDar 检测猫

为了能够不间断地拍摄照片,即时处理每张照片,我使用另一个 child_process,这次使用 fork() ,这是 spawn 的一个实例,运行 V8 引擎的一个新实例来创建多个 wrokers。

在上面的代码片段中的注释之后,阅读另一个 JS 文件:

ar imgPath = __dirname + '/' + filename;

var args = [imgPath];
var fork = child_process.fork(__dirname + '/detectCatsFromPhoto.js');
fork.send(args);

// the child process is completed
fork.on('message', function(base64) {
  if(base64) {
    // send the image to the cloud storage
  }
  deletePhoto(imgPath);
});

detectCatsFromPhoto.js 中,启动子进程并使用 canvas 和 kittydar 来检测猫。一旦完成该过程,图像将返回到 Base64 中:

var fs = require('fs');
var kittydar = require('kittydar');
var Canvas = require('kittydar/node_modules/canvas');

process.on('message', function(m) {
  var imgPath = m[0];

  fs.readFile(imgPath, function(err, data) {
    var img = new Canvas.Image;
    img.src = data;

    //... snip snip, some canvas setup code here...

    var cats = kittydar.detectCats(canvas);
    var base64Img;

    if(cats.length > 0) {
      base64Img = canvas.toDataURL(); 
    } 
    process.send(base64Img);
    process.exit(0);
  });
}

要查看完整的源代码,请看看我的 GitHub

另外,为了看看我如何使用 PubNub 在 Web 浏览器上传输实时照片,请查看 gh-pages 分支上的源代码。

已知问题

Raspistill(相机软件)

  • 当我设置 t=0 时 Raspistill 不断地拍摄一堆照片(并且在很多子进程正在运行的同时使得 Pi 崩溃),所以我设置了t=1,这导致了延迟。它似乎只需要整数。猫太快,不能等待一秒钟。
  • sun 设置后,相机无法捕捉可识别的照片。房间的灯光太暗了。

KittyDar(猫面部识别)

  • 在他吃饭的时候,当杰米(我的猫)正在吃饭的时候,面部检测不能识别猫的脸形。
  • 当我的猫移动,从盘子旁边吃,或者把他的屁股放在相机上时,它没有告诉我我的猫在吃东西。

猫的照片未能被识别

杰米未被发现的杰米未被发现的杰米未被发现的颠倒的杰米未被发现

(原文: Jamie undetected Jamie undetected Jamie undetected Upside-down Jamie undetected)

OMG,我在电视直播上演示了KittyCam!

看我最新的博客文章,关于我在 Twit 电视上的经历!您也可以在录制的节目上观看该片段。

好的,我希望你喜欢我冗长的博客文章!

原文链接:http://www.girliemac.com/blog/2015/12/25/kittycam-raspberrypi-camera-cat-face-recog-nodejs/

1 人评价

观光\评论区

Copyright © 2017 玩点什么. All Rights Reserved.