【機械学習】Custom Visionを使用して食材の写真を送ると自動で料理を提案してくれるLINEBOTを作成してみた【画像認識】

クックパッドをはじめ、クラシルやレシぽん、楽天レシピなどの便利なレシピサイトやアプリは多く存在していますが、そもそもどの料理にするか自体を考えることが面倒なことも少なくないと思います。

そこで、今回Azure Custom Visionを使用して、食材の写真を送ると、自動で料理を提案してくれるLINEBOTを作成してみました。

Custom Visionは、画像識別ロジックを自分で構築、デプロイできるAI画像認識サービスで、アップロードした画像にタグ付け(ラベリング)することで機械学習させていくことができます。
詳細については[こちら](https://docs.microsoft.com/ja-jp/azure/cognitive-services/custom-vision-service/home)を参照ください。

LINEBOT："cook-book"
![コメント 2020-05-13 164440.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612352/3117df8e-2357-9e95-2974-141ab1cca20b.jpeg)



#環境
- Windows 10
- Node.js 12.16.1
- Azure Custom Vision

#機械学習
このような形でアップロードした画像をラベリングすることで機械学習が可能です
![コメント 2020-05-13 180401.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612352/b222e140-e4da-65a9-beb6-bc2ef8a81782.jpeg)

#ソースコード
```js
'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');
const PORT = process.env.PORT || 3000;

const config = {
  channelSecret: '', //チャンネルシークレット
  channelAccessToken: '' //チャンネルアクセストークン
};

const app = express();

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);

function handleEvent(event) {
  console.log(event);

  if (event.type !== 'message' || event.message.type !== 'image') {
    return Promise.resolve(null);
  }

  let mes = ''
  if (event.message.type === 'image') {
    mes = 'レシピを探します';
    getFaceDetect2(event.message.id, event.source.userId, config.channelAccessToken);
  } else {
    mes = event.message.text;
  }

  return client.replyMessage(event.replyToken, {
    type: 'text',
    text: mes
  });
}

const getFaceDetect2 = async (messageId, userId, accessToken) => {
  console.log("getFaceDetect2");
  console.log(messageId);
  console.log(accessToken);

  //LINEbotから画像取得する
  const configImageAPI = {
    url: `https://api.line.me/v2/bot/message/${messageId}/content`,
    method: 'get',
    headers: {
      'Authorization': 'Bearer ' + accessToken,
    },
    responseType: 'arraybuffer'
  };

  let responseImageAPI;
  try {
    responseImageAPI = await axios.request(configImageAPI);
    console.log('image data get');
  } catch (error) {
    console.log('post Error');
    console.error(error);
  }

  //Custom Vision APIへのリクエスト
  const CUSTOM_VISION_API_ENDPOINT_URL = ''; //CUSTOM_VISION_API URL"If you have an image file:"

  const configCustomVisionAPI = {
    url: CUSTOM_VISION_API_ENDPOINT_URL,
    method: 'post',
    headers: {
      'Content-type': 'application/octet-stream',
      'Prediction-Key': '' //CustomVisionAPIのプレディクションキー
    },
    data: responseImageAPI.data
  };

  let responseCustomVision;
  try {
    responseCustomVision = await axios.request(configCustomVisionAPI);
    console.log("post OK");
    console.log(responseCustomVision.data.predictions[0].tagName);
  } catch (error) {
    console.log("post Error");
  }

  //LINEBOT
  await client.pushMessage(userId, {
    type: 'text',
    text: JSON.stringify(responseCustomVision.data.predictions[0].tagName) + 'がお薦めです'
  });
}

app.listen(PORT);
console.log(`Server running at ${PORT}`);
```

#LINE BOTの動き
事前にアップロードしていない画像でもCustom Visionでは機械学習されているため、
ある程度認識して判定することが可能です。
以下は事前に取込していない画像を使用してテストをしています。

牛肉、糸こんにゃく、ジャガイモ、ニンジン、インゲンの場合
![コメント 2020-05-13 183216.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612352/c17deb01-31e6-797f-f8d3-c65b95f5b4e3.jpeg)


卵、青ネギ、ベーコンの場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612352/4d34bd59-ffc9-b771-ed4f-8e927996a590.png)


牛肉、ひき肉、たまねぎ、にんじん、トマト、ジャガイモの場合
![1コメント 2020-05-13 185934.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612352/b5ea1257-b569-0c7f-63e8-75b8b3777b0d.jpeg)

豚肉、豆腐、青ネギの場合
![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/612352/ebd54e6d-7650-5fd4-4899-431521c8e851.jpeg)




#終わりに
- 料理名だけでなく、レシピのURLを教えてくれる機能でも面白いかと思いました。