daikichi blog

本、技術、その他

Webカメラ+画像認識で生活をルーティン化する

なんかIoTってやつで生活を豊かにしたいのだが、7畳のワンルームでは全てのスイッチやリモコンは3歩歩けば届く距離にあり、解決すべき課題が出てこないなーとスマートスピーカーなどにも手が出ないでいた。

ところが自宅でテレビ会議してる際に自室全体をカメラで写せるということに気づき、画像による監視でなにかできないかなと思い立つ。

そこで、掲題の実装を試す。

流れ

  • マシンに接続したカメラで写真を撮影する
  • 画像認識で写真に写っているアイテムを判別する
  • ルーティンをスケジュールする
  • ルーティン時に必要なものが写っていなかったらアラート

マシンに接続したカメラで写真を撮影する

(個人的に)手っ取り早いのでNode.jsで。

www.npmjs.com

var NodeWebcam = require( "node-webcam" );

// NodeWebcam.create().list() で調べられる
const CAMERA_NAME = 'FaceTime HDカメラ(内蔵)';
const TEMP_PHOTO_FILE = 'temppicture';

var opts = {
    width: 1280,
    height: 720,
    quality: 100,
    frames: 60,
    delay: 2, // 変更
    saveShots: true,
    output: "jpeg",
    device: CAMERA_NAME,
    callbackReturn: "location",
    verbose: false
};


const camera = NodeWebcam.create(opts)

function capturePhoto(){
  camera.capture(TEMP_PHOTO_FILE, (err, data)=>{
    if(err) return console.error(err);
    console.log(data); // 'temppicture.jpg'
  });
}

delayのところはデフォルトの0から2に変更している。 0だと撮影された結果が真っ暗だった。FaceTimeカメラの明度の自動調整が完了していなかった?

画像認識で写真に写っているアイテムを判別する

これもサービス・ライブラリは何でも良いと思う。 以前利用したことのあるのでGCPvision APIを利用する。 cloud.google.com

// 環境変数GOOGLE_APPLICATION_CREDENTIALは設定済みとする
const vision = require('@google-cloud/vision');
const client = new vision.ImageAnnotatorClient();

async  function capturePhotoAndDetectLabels(){
  return new Promise((resolve, reject)=>{
    camera.capture(TEMP_PHOTO_FILE, (err, data)=>{
      if(err) return reject(err);
      client.labelDetection(`./${data}`, (err, result)=>{
        if(err) return reject(err);
        resolve(result.labelAnnotations);
      });
    });
  })
}

たとえばこんな感じの写真が撮影できると

f:id:ringo-mogire-beeeeeeeeeeam:20200521225134j:plain
左に写ってる青いのはyogibo MAXです。オススメです。
labelAnnotationsのdescriptioは

Vacuum cleaner
Leg
Floor
Flooring

となる。

「毎朝掃除機をかける」とかであれば、このVacuum cleanerを検知してあげる

ルーティンをスケジュールする

node scheduleでググって一番上に出てきたのを使う。

www.npmjs.com

10分間、1分毎にチェックする。 写真の撮影の問題もあるので頻度はもう少し多めにしたほうが良いと思う。

const schedule = require('node-schedule');
const async = require('async');

// todo: ルーティンを増やしたらconfig化する
schedule.scheduleJob('0 9 * * *',()=>{
  async.retry({times:10, interval: 60000}, cb =>{
    capturePhotoAndDetectLabels().then(labels=>{
      if(labels.some(label=>label.description==='Vacuum cleaner')) return cb(null, true);
      cb(new Error('retry'));
    });
  }, (err, result)=>{
    if(result) return;
    // 10分間の間に作業が撮影できてないのでアラート
  });
});

ルーティン時に必要なものが写っていなかったらアラート

アラートというか、早い話

マシンからけたたましい音が鳴るとかが手っ取り早くていいと思う。

自分は部屋の照明にPhilips Hueを導入しているので、せっかくなのでIoTっぽくこれをいじってみる。

API調べるのめんどくさいのでZapierで設定しちゃう f:id:ringo-mogire-beeeeeeeeeeam:20200522004908p:plain

schedule.scheduleJob('0 9 * * *',()=>{
  async.retry({times:10, interval: 60000}, cb =>{
    capturePhotoAndDetectLabels().then((labels:Array<{description:string}>)=>{
      if(labels.some(label=>label.description==='Vacuum cleaner')) return cb(null, true);
      cb(new Error('retry'));
    });
  }, (err, results)=>{
    if(results) return;
    // アラート
    request('https://hooks.zapier.com/hooks/catch/xxxxxxxxx/yyyyyyy/');
  });
});

わかりづらいが、部屋の中が赤くなる

以上で完了。 多分撮影間隔とかは精度とVision APIの課金とバランスをとりつつ調整が必要か。

あとラズパイとかでスタンドアロンで動くようにしたいのと、罰のバリエーションをもたせてPavlok shock clockとか使ってみたい

gigazine.net

第1感 「最初の2秒」の「なんとなく」が正しい

Summary

輪切りの力

薄い「輪切り」を行う

輪切り: 要素に細かく分解すること

無意識の扉の奥

理由はわからない、でも「感じる」

人は自分の行動を説明できない

ライミング:「老い」をイメージさせるワードを無意識のうちに浴びせると老いた気分になる

見た目の罠

見た目の良さ故に「有能な大統領になる」と勘違いされた史上最悪の大統領

黒人に高い値段を吹っ掛けて失敗する自動車ディーラー

瞬時の判断力

思考を説明させるとなぞなぞの正解率が落ちる

情報過多で判断力は鈍る。情報過多によって軍事演習で百戦錬磨の将軍に負けた最新軍事フレームワーク

プロの勘と大衆の反応

革新的製品は市場調査になじまない。

コーラのテスト。テスターは少量でコーラのテストを行うが、ユーザーが飲むのは1缶だ。

パッケージを変えるだけで売れた。しかしユーザーは「美味しくなった」「味が変わった」という。

プロは本質を見抜くにあたって不要な要素を削ぎ落とすことができる

心を読む力

感情が表情に作用するのではなく、表情が感情に作用することもある。幸せだから笑うのではなく、笑うから幸せになる。

微表情で感情はわかる

自閉症患者は心を読む能力が無くなる。

しかし緊急時には普通の人間でもその状態に陥ることがある(ex.黒人が銃を持っていると勘違いして射殺した警官)

それを技術で克服する

雑感

  • 人は人間の行動を説明することができない。逆に言うと行動こそがすべて

  • ライミング、使える。他人を騙すことにも使えるし、おそらく

  • この本は肝心な「じゃあどうやったらプロレベルの第1感は鍛えられるのさ?」という疑問には答えてくれない。数と正しいフィードバックしか無いのか?