はじめに
LINEBotからRaspberryPiで写真を撮ってLINEにおくる!で作ったLINEBotにAI機能を追加してどの猫がいるか教えてくれるものを作りました。
概要
LINEBotからRaspberryPiを動かして写真を撮り、Gyazoに送って画像判定で何が映っているかと撮影した写真をLINEに送るものです。
画像判定
画像判定はMicrosoft Custom Vision Serviceを使用。
茶色と白黒とグレーの3匹のねこを学習させ、mixとして色々な猫を追加学習させて、3匹のどの猫に近いかを教えてくれます。
3匹以外の猫を判定するとmixが一番高い値で出ます!(catタグは全ての猫に追加)
できたもの
どのニャンコがいるか教えてくれるようになった!
— 3yaka (@3yaka4) May 13, 2020
ニャンコのプライバシーを守るため色でこたえるw
#ねこIoT #cognitive #customvision #linebot #raspberrypi pic.twitter.com/pILH3mwTq8
使い方
RaspberryPiを猫がよくいる場所に置きます。
猫が見たいので LINEBotに「ねこ」と入れます。
(「ねこ」以外のワードには「何が見たいの?」と返してきます。)
写真を撮るのに時間がかかるので、「写真撮ってくるから待っててねー」、とつなぎのワードが入ります。
写真を撮って送るときに Azure Cognitive Vision ServicesのCustom Vision Serviceを使用してどの猫がいるかを画像を分類して、10秒ほどすると猫の種類と写真が送られてきます。
環境
MacBook Pro macOS Mojave
Visual Studio Code 1.44.0
Azure Cognitive Vision Services
Custom Vision Service
RaspberryPi 3B
Release: 10
Codename: buster
Node.js v12.16.3
npm v6.14.4
ngrok
Pi camera
洗濯バサミ
コード
'use strict';
const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');
const PORT = process.env.PORT || 3000;
const Gyazo = require('gyazo-api');
const gyazoclient = new Gyazo('***');
const config = {
channelSecret: '***',
channelAccessToken: '***'
};
const app = express();
let whichCat;
app.get('/', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用(無くても問題ない)
app.post('/webhook', line.middleware(config), (req, res) => {
console.log(req.body.events);
Promise
.all(req.body.events.map(handleEvent))
.then((result) => res.json(result));
});
const client = new line.Client(config);
async function handleEvent(event) {
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}
let mes = event.message.text;
if (event.message.text.match("ねこ")) {
await client.replyMessage(event.replyToken, {
type: "text",
text: '写真を撮ってくるからちょっと待っててね'
});
await nyanpi();
return nyancoPic(event.source.userId);
}
else {
return client.replyMessage(event.replyToken, {
type: "text", text: '何が見たいのかな?'
});
}
}
const nyanpi = async (userId) => {
const PiCamera = require('pi-camera');
const myCamera = new PiCamera({
mode: 'photo',
output: `${__dirname}/nyan.jpg`,
width: 640,
height: 480,
nopreview: true,
});
await myCamera.snap()
await gyazoclient.upload('./nyan.jpg', {
title: "my picture",
desc: "upload from nodejs"
})
}
//Custom Vision Service
const sendCustomVision = async (imageURL) => {
const CUSTOM_VISION_API_ENDPOINT_URL = '***';
// Prediction-Keyの値を Prediction-Key ヘッダーに入れる
// JSONで送るので Content-type ヘッダーに application/json 指定
const configCustomVisionAPI = {
url: CUSTOM_VISION_API_ENDPOINT_URL,
method: 'post',
headers: {
'Content-type': 'application/json',
'Prediction-Key': '***'
},
data: {
url: imageURL
}
};
// axiosの送信設定
let responseCustomVision;
try {
// POSTリクエストで送る
responseCustomVision = await axios.request(configCustomVisionAPI);
console.log("post OK");
// データ送信が成功するとレスポンスが来る
console.log(responseCustomVision.data);
// 全てのタグにcatが含まれているので、近似値が高いものがcatタグの時は2番目を返す
const catTag = responseCustomVision.data;
if (catTag.predictions[0].tagName === "cat") {
whichCat = catTag.predictions[1].tagName
} else {
whichCat = catTag.predictions[0].tagName;
}
} catch (error) {
console.log("post Error");
// ダメなときはエラー
console.error(error);
}
}
//gyazoから最新の写真URLを取得
const nyancoPic = async (userId) => {
const response = await gyazoclient.list()
const gyazoimgUrl = response.data[0].url;
//画像判定に送る
const sendcstmvison = await sendCustomVision(gyazoimgUrl);
//タグの名前を猫の見た目に置き換え
if (whichCat === "chairo") {
whichCat = "ちゃいろ";
} else if (whichCat === "shirokuro") {
whichCat = "しろくろ";
} else {
whichCat = "グレー";
}
return client.pushMessage(userId, [{
type: 'image',
originalContentUrl: gyazoimgUrl,
previewImageUrl: gyazoimgUrl
},
{
type: "text", text: `${whichCat}の猫がいるよ`
}]);
}
app.listen(PORT);
console.log(`Server running at ${PORT}`);
参考サイト
Computer Vision サービスを使用した画像処理 - Learn | Microsoft Docs
感想
AIが簡単に実装できた
グレーがシンガプーラという猫種で他のことめちゃくちゃ顔が同じなのでシンガプーラ判定やってみたい。
ngrokなので早く何かにdeployしたい。