硬核奶爸!用树莓派做个“智能婴儿监视器”:啼哭自动通知,还能剖析哭声寄义

2020-11-06 网络
浏览
[科技新闻]硬核奶爸!用树莓派做个“智能婴儿监视器”:啼哭自动通知,还能剖析哭声寄义

原标题:硬核奶爸!用树莓派做个“智能婴儿看管器”:饮泣自动关照,还能剖析哭声寄义

大数据文摘出品

泉源:Medium

编译:陈之炎

作为一位新晋奶爸和程序员,我在新身份中最常思索的问题就是“照顾婴儿的事变真的没法自动化吗?

固然,这或许能够完成,就算有给孩子换尿布的机器人(假设有充足多的父母同意在本身踉跄学步的孩子身上测试如许的装备),情愿自动化照顾婴儿的父母还真为数不多。

作为父亲,我起首意想到的事变是:婴儿许多时候都邑在哭,纵然我在家,也不大概老是能听到孩子的哭声。

一般,商用婴儿看管器能够弥补这一空缺,它们充任对讲机,让你在另一个房间也能听到婴儿的哭声。

但我很快意想到:商用婴儿看管器没有我设想中的抱负装备智能:

  • 它们只能充任一个传声筒:把声响从泉源带到扬声器,却没法发明孩子哭声的寄义;
  • 当家长要去到另一个房间里时,相应要把扬声器带到另一个房间,没法在任何其他现有的音频装备上播放声响;
  • 扬声器一般是低功率扬声器,没法衔接到外部扬声器-这意味着,假如我在另一个房间播放音乐,我大概会听不到孩子的哭声,即使监控器和我在同一个房间也没法听到;
  • 大多数扬声器都是在低功率无线电波上事变的,这意味着假如婴儿在他/她的房间里,而你必需走到楼下,它们才事变。

因而,我萌生了克己一个更好用的“智能婴儿看管器”的主意。

说干就干,我先给这个“智能婴儿看管器”定义了一些须要的功用。

  • 它能够运转于价廉物美的树莓派(RaspberryPI)与USB麦克风
  • 当孩子入手下手/住手饮泣时,它应当检测到孩子的哭声,并关照我(抱负状况下是在我的手机上),或许跟踪我仪表板上的数据点,或许运转相应的使命。它不应当是一个纯真的对讲器,简朴地将声响从一个源通报到另一个兼容的装备
  • 它能够在扬声器,智能手机,电脑等装备上传输音频。
  • 它不受源和扬声器之间间隔的影响,无需在全部屋子里将扬声器移来移去。
  • 它还应当有一个摄像头,能够应用摄像头对孩子及时监控,当他一入手下手哭,我便能够抓拍到图片或婴儿床的短视频,以搜检有什么不对劲。

来看看一个新晋奶爸怎样运用工程师的大脑开源东西来完成这项使命吧。

收集音频样本

起首,购置一块树莓派(RaspberryPi),在SD卡上烧录好Linux操作系统(发起运用RaspberryPI3或更高版本),运转Tensorflow模子。还能够购置一个与树莓派兼容的USB麦克风。

然后装置须要的相干项:

[sudo] apt-get install ffmpeg lame libatlas-base-dev alsa-utils

[sudo] pip3 install tensorflow

第一步,必需纪录充足的音频样本,婴儿在什么时候哭,在什么时候不哭。稍后将应用这些样原本练习音频检测模子。

注重:在这个例子中,我将展现怎样应用声响检测来辨认婴儿的哭声,一样的精准程序能够用来检测任何别的范例的声响-只需它们充足长(比方:警报或邻居家的钻孔声)。

起首,检察音频输入装备:

arecord -l

在树莓派(RaspberryPI)上,取得以下输出(注重,有两个USB麦克风):

**** List of CAPTURE Hardware Devices ****

card 1: Device [USB PnP Sound Device], device 0: USB Audio [USB Audio]

Subdevices: 0/1

Subdevice #0: subdevice #0

card 2: Device_1 [USB PnP Sound Device], device 0: USB Audio [USB Audio]

Subdevices: 0/1

Subdevice #0: subdevice #0

我应用第二个麦克风来纪录声响-即卡2,装备0。辨认它的ALSA要领要么是hw:2,0(直接接见硬件装备),要么是plughw:2,0(假如须要的话,它会输入采样率和花样转换插件)。确保SD卡上有充足的空间,然后入手下手录制一些音频:

arecord -D plughw:2,0 -c 1 -f cd | lame - audio.mp3

和孩子在同一个房间里,纪录几分钟或几个小时的音频-最好是长时候的缄默沉静、婴儿哭声和其他与之无关的声响-,灌音完成后按Ctrl-C。尽量多的反复这个历程屡次,在一天中的差别时候或差别的日子里猎取差别的音频样本。

标注音频示例

一旦有了充足的音频样本,就能够把它们复制到电脑上来练习模子了-能够运用SCP复制文件,也能够直接从SD卡上复制。

把它们都存储在雷同目次下,比方:~/datasets/sound-detect/audio。别的,为每一个示例音频文件建立一个新文件夹,它包括一个音频文件(名为audio.mp3)和一个标注文件(名为labels.json),应用它来标记音频文件中的负/正音频段,原始数据集的构造以下:

~/datasets/sound-detect/audio

-> sample_1

-> audio.mp3

-> labels.json

-> sample_2

-> audio.mp3

-> labels.json

下面:标注录制的音频文件-假如它包括了孩子几个小时的哭声,大概会迥殊受虐。在你最喜欢的音频播放器或Audacity中翻开每一个数据集音频文件,并在每一个示例目次中建立一个新的label.json文件。肯定饮泣入手下手的确实时候和完毕时候,并在labels.json中标注为time_string -> label的关键值构造。例:

{

"00:00": "negative",

"02:13": "positive",

"04:57": "negative",

"15:41": "positive",

"18:24": "negative"

}

在上面的例子中,00:00到02:12之间的一切音频段将被标记为负,02:13到04:56之间的一切音频段将被标记为正,以此类推。

生成数据集

对一切的音频示例标注完成以后,接下来是生成数据集,末了将它输入到Tensorflow模子中去。起首,建立了一个名为micmon的通用库和一组用于声响看管的实用东西。然后,入手下手装置:

git clone git@github.com:/BlackLight/micmon.git

cd micmon

[sudo] pip3 install -r requirements.txt

[sudo] python3 setup.py build install

本模子设想基于音频的频次样本而非原始音频,由于,在这里我们想检测到一个特定的声响,这个声响有着特定的“频谱”标签,即:基频(或基频下落的窄带局限)和一组特定的谐波。这些谐波频次与基波之间的比率既不受振幅的影响(频次比恒定,与输入幅度无关),也不受相位的影响(不管什么时候入手下手纪录,一连的声响都邑有雷同的频谱特征)。

这类与振幅和相位无关的特征使得这类要领更有大概练习出一个鲁棒的声响检测模子,而不是简朴地将原始音频样本馈送到模子中。另外,该模子能够更简朴(能够在不影响机能的状况下将多个频次分为一组,从而能够有效地完成降维),不管样本持续时候多长,该模子将50~ 100个频带作为输入值,一秒钟的原始音频一般包括44100个数据点,而且输入的长度跟着样本的持续时候而增添,而且不太容易发生过拟合。

micmon能盘算音频样本某些段的FFT(疾速傅里叶变换),将结果频谱分为低通和高通滤波器的频带,并将结果保留到一组numpy紧缩(.npz)文件中。能够经由过程在敕令行上实行micmon-datagen敕令来完成:

micmon-datagen \

--low 250 --high 2500 --bins 100 \

--sample-duration 2 --channels 1 \

~/datasets/sound-detect/audio ~/datasets/sound-detect/data

在上面的示例中,我们从存储在~/dataset/sound-detect/audio下的原始音频样本生成一个数据集,并将生成的频谱数据存储到~/datasets/sound-detect/data. –low和~/datasets/sound-detect/data. --high中, low和high离别示意最低和最高频次,最低频次的默许值为20Hz(人耳可闻的最低频次),最高频次的默许值为20kHz(康健的年青人耳可闻的最高频次)。

经由过程对此局限做出限制,尽量多地捕捉愿望检测到的其他范例的音频背景和无关谐波的声响。在本案例中, 250-2500赫兹的局限足以检测婴儿的哭声。

婴儿的哭声一般是高频的(歌剧女高音能到达的最高音符在1000赫兹摆布),在这里设置了最少双倍的最高频次,以确保能取得充足高的谐波(谐波是更高的频次),但也不要将最高频次设得太高,以防备其他背景声响的谐波。我剪切掉了频次低于250赫兹的音频信号-婴儿的哭声不太大概发生在低频段,比方,能够翻开一些positive音频样本,应用均衡器/频谱剖析仪,搜检哪些频次在positive样本中占主导地位,并将数据集集合在这些频次上。--bins指定了频次空间的组数(默许值:100),更大的数值意味着更高的频次分辨率/粒度,但假如太高,大概会使模子容易发生过分拟合。

剧本将原始音频分割成较小的段,并盘算每一个段的频谱标签。示例持续时候指定每一个音频段有多长时候(默许:2秒)。关于持续时候较长的声响,取更大的值会起到更好的作用,但它同时会削减检测的时候,而且大概会在短音上失效。关于持续时候较短的声响,能够取较低的值,但捕捉的片断大概没有充足的信息量来可靠地辨认声响。

除了micmon-datagen剧本以外,也能够应用micmonAPI,编写脚原本生成数据集。例:

import os

from micmon.audio import AudioDirectory, AudioPlayer, AudioFile

from micmon.dataset import DatasetWriter

basedir = os.path.expanduser('~/datasets/sound-detect')

audio_dir = os.path.join(basedir, 'audio')

datasets_dir = os.path.join(basedir, 'data')

cutoff_frequencies = [250, 2500]

# Scan the base audio_dir for labelled audio samples

audio_dirs = AudioDirectory.scan(audio_dir)

# Save the spectrum information and labels of the samples to a

# different compressed file for each audio file.

for audio_dir in audio_dirs:

dataset_file = os.path.join(datasets_dir, os.path.basename(audio_dir.path) '.npz')

print(f'Processing audio sample {audio_dir.path}')

with AudioFile(audio_dir) as reader, \

DatasetWriter(dataset_file,

low_freq=cutoff_frequencies[0],

high_freq=cutoff_frequencies[1]) as writer:

for sample in reader:

writer = sample

不管是运用micmon-datagen照样运用micmon Python API生成数据集,在历程完毕时,应当在~/datasets/sound-detect/data目次下找到一堆.npz文件,每一个标注后的音频原始文件对应一个数据集。以后,便能够应用这个数据集来练习神经网络举行声响检测。

练习模子

micmon应用Tensorflow Keras来定义和练习模子,有了PythonAPI,能够很容易地完成。比方:

import os

from tensorflow.keras import layers

from micmon.dataset import Dataset

from micmon.model import Model

# This is a directory that contains the saved .npz dataset files

datasets_dir = os.path.expanduser('~/datasets/sound-detect/data')

# This is the output directory where the model will be saved

model_dir = os.path.expanduser('~/models/sound-detect')

# This is the number of training epochs for each dataset sample

epochs = 2

# Load the datasets from the compressed files.

# 70% of the data points will be included in the training set,

# 30% of the data points will be included in the evaluation set

# and used to evaluate the performance of the model.

datasets = Dataset.scan(datasets_dir, validation_split=0.3)

labels = ['negative', 'positive']

freq_bins = len(datasets[0].samples[0])

# Create a network with 4 layers (one input layer, two intermediate layers and one output layer).

# The first intermediate layer in this example will have twice the number of units as the number

# of input units, while the second intermediate layer will have 75% of the number of

# input units. We also specify the names for the labels and the low and high frequency range

# used when sampling.

model = Model(

[

layers.Input(shape=(freq_bins,)),

layers.Dense(int(2 * freq_bins), activation='relu'),

layers.Dense(int(0.75 * freq_bins), activation='relu'),

layers.Dense(len(labels), activation='softmax'),

],

labels=labels,

low_freq=datasets[0].low_freq,

high_freq=datasets[0].high_freq

# Train the model

for epoch in range(epochs):

for i, dataset in enumerate(datasets):

print(f'[epoch {epoch 1}/{epochs}] [audio sample {i 1}/{len(datasets)}]')

model.fit(dataset)

evaluation = model.evaluate(dataset)

print(f'Validation set loss and accuracy: {evaluation}')

# Save the model

model.save(model_dir, overwrite=True)

运转此剧本后(在对模子的准确性觉得惬意后),能够在~/models/sound-detect目次下找保留的新模子。在我的这个例子中,我收集~5小时的声响就充足用了,经由过程定义一个较优的频次局限来练习模子,准确率大于98%。假如是在盘算机上练习模子,只需将其复制到RaspberryPI,便能够预备进入下一步了。

应用模子举行展望

这时候,制造一个剧本:应用之前练习过的模子,当孩子入手下手哭的时候,关照我们:

import os

from micmon.audio import AudioDevice

from micmon.model import Model

model_dir = os.path.expanduser('~/models/sound-detect')

model = Model.load(model_dir)

audio_system = 'alsa' # Supported: alsa and pulse

audio_device = 'plughw:2,0' # Get list of recognized input devices with arecord -l

with AudioDevice(audio_system, device=audio_device) as source:

for sample in source:

source.pause() # Pause recording while we process the frame

prediction = model.predict(sample)

print(prediction)

source.resume() # Resume recording

在RaspberryPI上运转剧本,并让它运转一段时候-假如在过去2秒内没有检测到哭声,它将在规范输出中打印negative,假如在过去2秒内检测到哭声否,则在规范输出中打印positive。

,

科技是智慧的体验,人文科技、未来科技带您走进新时代的步伐,

秀羞科技频道为大家提供科技全方面的报道和资讯服务。

,

然则,假如孩子哭了,简朴地将音讯打印到规范输出中并没有太大作用-我们愿望取得明白及时关照!

能够应用Platypush来完成这个功用。在本例中,我们将运用pushbullet集成在检测到cry时向我们的手机发送音讯。接下来装置Redis(Platypush用于吸收音讯)和Platypush,应用HTTP和Pushbullet来集成:

[sudo] apt-get install redis-server

[sudo] systemctl start redis-server.service

[sudo] systemctl enable redis-server.service

[sudo] pip3 install 'platypush[http,pushbullet]'

将Pushbullet应用程序装置在智能手机上,到pushbullet.com上以猎取API token。然后建立一个~/.config/platypush/config.yaml文件,该文件启用HTTP和Pushbullet集成:

backend.http:

enabled: True

pushbullet:

token: YOUR_TOKEN

接下来,对前面的剧本举行修正,不让它将音讯打印到规范输出,而是触发一个能够被Platypush hook捕捉的自定义事宜CustomEvent:

#!/usr/bin/python3

import argparse

import logging

import os

import sys

from platypush import RedisBus

from platypush.message.event.custom import CustomEvent

from micmon.audio import AudioDevice

from micmon.model import Model

logger = logging.getLogger('micmon')

def get_args():

parser = argparse.ArgumentParser()

parser.add_argument('model_path', help='Path to the file/directory containing the saved Tensorflow model')

parser.add_argument('-i', help='Input sound device (e.g. hw:0,1 or default)', required=True, dest='sound_device')

parser.add_argument('-e', help='Name of the event that should be raised when a positive event occurs', required=True, dest='event_type')

parser.add_argument('-s', '--sound-server', help='Sound server to be used (available: alsa, pulse)', required=False, default='alsa', dest='sound_server')

parser.add_argument('-P', '--positive-label', help='Model output label name/index to indicate a positive sample (default: positive)', required=False, default='positive', dest='positive_label')

parser.add_argument('-N', '--negative-label', help='Model output label name/index to indicate a negative sample (default: negative)', required=False, default='negative', dest='negative_label')

parser.add_argument('-l', '--sample-duration', help='Length of the FFT audio samples (default: 2 seconds)', required=False, type=float, default=2., dest='sample_duration')

parser.add_argument('-r', '--sample-rate', help='Sample rate (default: 44100 Hz)', required=False, type=int, default=44100, dest='sample_rate')

parser.add_argument('-c', '--channels', help='Number of audio recording channels (default: 1)', required=False, type=int, default=1, dest='channels')

parser.add_argument('-f', '--ffmpeg-bin', help='FFmpeg executable path (default: ffmpeg)', required=False, default='ffmpeg', dest='ffmpeg_bin')

parser.add_argument('-v', '--verbose', help='Verbose/debug mode', required=False, action='store_true', dest='debug')

parser.add_argument('-w', '--window-duration', help='Duration of the look-back window (default: 10 seconds)', required=False, type=float, default=10., dest='window_length')

parser.add_argument('-n', '--positive-samples', help='Number of positive samples detected over the window duration to trigger the event (default: 1)', required=False, type=int, default=1, dest='positive_samples')

opts, args = parser.parse_known_args(sys.argv[1:])

return opts

def main():

args = get_args()

if args.debug:

logger.setLevel(logging.DEBUG)

model_dir = os.path.abspath(os.path.expanduser(args.model_path))

model = Model.load(model_dir)

window = []

cur_prediction = args.negative_label

bus = RedisBus()

with AudioDevice(system=args.sound_server,

device=args.sound_device,

sample_duration=args.sample_duration,

sample_rate=args.sample_rate,

channels=args.channels,

ffmpeg_bin=args.ffmpeg_bin,

debug=args.debug) as source:

for sample in source:

source.pause() # Pause recording while we process the frame

prediction = model.predict(sample)

logger.debug(f'Sample prediction: {prediction}')

has_change = False

if len(window) < args.window_length:

window = [prediction]

else:

window = window[1:] [prediction]

positive_samples = len([pred for pred in window if pred == args.positive_label])

if args.positive_samples <= positive_samples and \

prediction == args.positive_label and \

cur_prediction != args.positive_label:

cur_prediction = args.positive_label

has_change = True

logging.info(f'Positive sample threshold detected ({positive_samples}/{len(window)})')

elif args.positive_samples > positive_samples and \

prediction == args.negative_label and \

cur_prediction != args.negative_label:

cur_prediction = args.negative_label

has_change = True

logging.info(f'Negative sample threshold detected ({len(window)-positive_samples}/{len(window)})')

if has_change:

evt = CustomEvent(subtype=args.event_type, state=prediction)

bus.post(evt)

source.resume() # Resume recording

if __name__ == '__main__':

main()

将上面的剧本保留为~/bin/micmon_detect.py。假如在滑动窗口时候内上检测到positive_samples样本(为了削减展望毛病或暂时毛病引发的噪声),则剧本触发事宜,而且它只会在当前展望从negative到positive的状况下触发事宜。然后,它被分派给Platypush。关于别的差别的声响模子(不一定是饮泣婴儿),该剧本也是通用的,对应别的正/负标签、别的频次局限和别的范例的输出事宜,这个剧本也能事变。

建立一个Platypush hook来对事宜作出相应,并向装备发送关照。起首,建立 Platypush剧本目次:

mkdir -p ~/.config/platypush/scripts

cd ~/.config/platypush/scripts

# Define the directory as a module

touch __init__.py

# Create a script for the baby-cry events

vi babymonitor.py

babymonitor.py的内容为:

from platypush.context import get_plugin

from platypush.event.hook import hook

from platypush.message.event.custom import CustomEvent

@hook(CustomEvent, subtype='baby-cry', state='positive')

def on_baby_cry_start(event, **_):

pb = get_plugin('pushbullet')

pb.send_note(title='Baby cry status', body='The baby is crying!')

@hook(CustomEvent, subtype='baby-cry', state='negative')

def on_baby_cry_stop(event, **_):

pb = get_plugin('pushbullet')

pb.send_note(title='Baby cry status', body='The baby stopped crying - good job!')

为Platypush建立一个效劳文件,并启动/启用效劳,如许它就会在终端上启动:

mkdir -p ~/.config/systemd/user

wget -O ~/.config/systemd/user/platypush.service \

https://raw.githubusercontent.com/BlackLight/platypush/master/examples/systemd/platypush.service

systemctl --user start platypush.service

systemctl --user enable platypush.service

为婴儿看管器建立一个效劳文件-如:

~/.config/systemd/user/babymonitor.service:

[Unit]

Description=Monitor to detect my baby's cries

After=network.target sound.target

[Service]

ExecStart=/home/pi/bin/micmon_detect.py -i plughw:2,0 -e baby-cry -w 10 -n 2 ~/models/sound-detect

Restart=always

RestartSec=10

[Install]

WantedBy=default.target

该效劳将启动ALSA装备plughw:2,0上的麦克风看管器,假如在过去10秒内检测到最少2个positive 2秒样本,而且先前的状况为negative,则会触发state=positive事宜;假如在过去10秒内检测到少于2个positive样本,而且先前的状况为positive,则state=negative。然后能够启动/启用效劳:

systemctl --user start babymonitor.service

systemctl --user enable babymonitor.service

确认一旦婴儿入手下手饮泣,就会在手机上收到关照。假如没有收到关照,能够搜检一下音频示例的标签、神经网络的架构和参数,或样本长度/窗口/频带等参数是不是准确。

另外,这是一个相对基础的自动化例子-能够为它增加更多的自动化使命。比方,能够向另一个Platypush装备发送要求(比方:在寝室或客堂),用TTS插件高声提醒婴儿在哭。还能够扩大micmon_detect.py剧本,以便捕捉的音频样本也能够经由过程HTTP流-比方运用Flask包装器和ffmpeg举行音频转换。另一个风趣的用例是,当婴儿入手下手/住手饮泣时,将数据点发送到当地数据库(能够参考我先前关于“怎样运用Platypush PostgreSQL Mosquitto Grafana建立天真和自我管理的仪表板”的文章https://towardsdatascience.com/how-to-build-your-home-infrastructure-for-data-collection-and-visualization-and-be-the-real-owner-af9b33723b0c):这是一组相称有效的数据,能够用来跟踪婴儿睡觉、醒着或须要喂食时的状况。虽然监测宝宝一直是我开发micmon的初志,然则一样的程序也能够用来练习和检测别的范例声响的模子。末了,能够斟酌运用一组优越的电源或锂电池组,如许看管器便能够便携化了。

装置宝贝摄像头

有了一个好的音频馈送和检测要领以后,还能够增加一个视频馈送,以坚持对孩子的监控。一入手下手,我 在RaspberryPI3上装置了一个PiCamera用于音频检测,厥后,我发明这个设置相称不切实际。想想看:一个RaspberryPi 3、一个附加的电池包和一个摄像头,组合在一起会相称愚笨;假如你找到一个轻型相机,能够很容易地装置在支架或天真的手臂上,而且能够四周挪动,如许,不管他/她在那里,都能够亲昵关注孩子。终究,我挑选了体积较小的RaspberryPi Zero,它与PiCamera兼容,再配一个小电池。

婴儿看管器摄像头模块的第一个原型

一样,先插进去一个烧录了与RaspberryPI兼容的操作系统的SD卡。然后在其插槽中插进去一个与RaspberryPI兼容的摄像头,确保摄像头模块在raspi-config中启用,装置集成有PiCamera的Platypush:

[sudo] pip3 install 'platypush[http,camera,picamera]'

然后在~/.config/platypush/config.yaml:中增加相机设置:

camera.pi:

listen_port: 5001

在Platypush从新启动时搜检此设置,并经由过程HTTP从摄像头猎取快照:

wget http://raspberry-pi:8008/camera/pi/photo.jpg

或在浏览器中翻开视频:

http://raspberry-pi:8008/camera/pi/video.mjpg

一样,当应用程序启动时,能够建立一个hook,该hook经由过程TCP/H264启动摄像头馈送:

mkdir -p ~/.config/platypush/scripts

cd ~/.config/platypush/scripts

touch __init__.py

vi camera.py

也能够经由过程VLC:播放视频。

vlc tcp/h264://raspberry-pi:5001

在手机上经由过程VLC应用程序或应用RPi Camera Viewer应用程序寓目视频。

从主意到末了完成结果还不错,这也算是一个新晋奶爸从护理杂事中脱身的自我救赎吧。

原文链接:

攻克石墨烯润滑油技术难点,「华墨」想为中国制造高质量发展保驾护航

该产品利用公司独创的石墨烯改性二元复方组合材料,实现了石墨烯晶体在润滑油中的均匀分布,达到了超耐磨与润滑兼具的效果,同时具备减少油耗,减震降噪,并提升发动机动力等功能特点。 根据清华大学高端装备研究院,国…