🍎

食材管理アプリケーションを制作した話

2024/05/08に公開

はじめに

私は、情報工学科の大学3年生です。大学からプログラミングにのめり込み、個人開発やハッカソンなどを通して、様々なアプリケーションを開発してきました。現在は、深層学習の学習に没頭しています。

今回は、大学2年次に授業の一環で作成したWebアプリケーション「Navi Cook」を紹介します。前置きとして、開発期間は4ヶ月間です。(平日は、授業などがあり実稼働はもう少し少ない時間でした。)
また、市役所から与えられた、いくつかの市の問題の中で「市の燃えるゴミの排出量を減らす」というテーマを選定し、実際に使ってもらえるようなプロダクトを目指して作成しました。

開発の流れ

開発自体は4ヶ月間(後学期中)だったものの、アイデア出しにも4ヶ月程度(前学期中)費やしました。

アイデア出し(4月〜7月)

  1. プロジェクトテーマの選定 →「市の燃えるゴミの排出量を減らす」
  2. 現状調査
  3. ニーズ調査
  4. 前提条件・目標値の設定
  5. 既存作の文献調査
  6. なぜなぜ分析
  7. アイデアの創出

開発(10月〜1月)

  1. アイデアの再確認(最低限必要な機能の選定)
  2. デザイン制作
  3. 技術選定(アーキテクチャ設計)
  4. 開発環境の構築
  5. 開発
  6. 検証

創出されたアイデア

「家庭から出る燃えるゴミを減らす」ためにどのようなプロダクトを提供すべきか、現状調査とニーズ調査により考案した。

まず現状調査として、市の燃えるゴミの排出量とその内訳を調査したところ、家庭から出る燃えるゴミの内、約45%は生ゴミが占めていることがわかった。その生ゴミの中でも、手つかず食品や食べ残しなどの食品ロスが、燃えるゴミ全体の約13%を占めていることがわかった。また、学生116名に「賞味・消費期限切れ等で食品を廃棄したことがあるか?」というアンケートを行った結果、8割の人が廃棄したことがあるという結果になった。生ゴミの中でも、食品ロスは一人一人が意識して生活を送ることができたら、ゴミの排出量が減らせる項目であると考え、食品ロスに着目して活動を行うことにした。

ニーズ調査として、市が行った「家庭から発生する食品ロスの発生原因」の調査から、食品ロスの最も大きな原因は「食品の賞味・消費期限切れ」であることがわかった。このことから、食品の賞味・消費期限の管理を行うシステムが必要だと考える。

これらのことから創出したアイデアのイメージを以下の図で示す

画像認識技術を利用して、ユーザーが手軽に食材情報を登録し、レシピの提案や食材購入補助を受けるとともに、バランスの良い献立から健康維持ができるシステムを構築し、ユーザーが食材管理を継続できるシステムを目指す。

プロダクトの概要

https://www.youtube.com/watch?v=wmUcvecm1J0

対象ユーザー

  • 家庭内での食材の消費を効率的に管理したい家庭主婦、単身者
  • 食材の無駄を減らし、健康的な食生活を送りたいと考えている人々
  • 繁忙な日常で、食事の計画を立てる時間がない忙しい社会人や学生

特徴

  • シンプルなUIで、どんな年齢層のユーザーにも簡単に使える。
  • 食材の無駄を減らすことで、家計の節約にも寄与。
  • 栄養バランスの取れた食事の提案を通じて、日々の健康を促進。
  • 必要な食材のリストを作成し、買い忘れを防ぎます。効率的な買い物で時間を節約。

デザイン

今回は、幅広いユーザー層を想定しているので、白を貴重としたシンプルなUIにしました。

使用技術(アーキテクチャ)

フロントエンド(HTML+CSS+JavaScript)

HTMLでウェブページの基本構造を定義し、CSSを用いてスタイリングを施した。また、JavaScriptの活用により、ページの動的な振る舞いとインタラクティブな要素を実装しました。重要な機能として、JavaScriptとAjaxを用いた非同期通信を組み込見ました。

バックエンド(Flask)

バックエンドは、PythonのFlaskフレームワークを用いて、データベースの操作、画像処理、非同期通信、APIエンドポイントなどの設定を構築しました。

データベース(MySQL)

データベースは、リレーショナルデータベースであるMySQLを使用した。それぞれのテーブルの関係性を以下の図で示す。

画像分類(Teachable machine)

本プロダクトでは、食材を判定するためのアプローチで、画像分類技術を用いた。画像に1種類の物体のみが写っている場合には、画像分類モデルで食材の判定を行った。画像分類モデルの作成には、Googleが提供している、Teachable machineを用いた。

データの水増し(OpenCV)

食材の分類モデルの作成にあたって、トレーニングするデータ画像の枚数が判定精度に大きく影響を及ぼす。
一方、データの収集は想像以上に困難で、多数のデータが集められないと判断し、少量の画像を水増し処理により、増加することにした。集めた画像データを食材クラスごとにディレクトリを分けて管理し、ディレクトリ単位でディレクトリ内の画像をOpenCVを用いて、回転、反転、拡大して水増しを行った。

文字認識(VisionAI)

作成した画像分類モデルでは、野菜の分類精度はかなり高い一方、肉の判別精度はかなり低いことが問題となった。肉であることは判定できるが、肉の種類(豚肉、牛肉、鶏肉など)や肉の部位(バラ肉、ヒレ肉など)を細かく判定することは、見た目が非常に似ていることから困難であることがわかった。

肉の分類精度表(文字認識搭載前)

そこで、肉のパッケージに着目し、パッケージの文字を認識することで肉の種類を分類することで問題解決を図った。文字認識には、VisionAIを用いて行なった。

以下の図に示すように、食品画像に食品ラベルが存在するかどうかを調査し、存在する場合には食品ラベルのラベル部分だけを切り出し、VisionAIを用いて文字認識処理を行う。切り出された食品ラベルは、ブロック単位で文字が検出されるので、必要な文字データだけを抜き出しデータを得る仕組みを構築した。

文字認識搭載後の肉の分類精度表

物体検出(YOLOv8)

画像から複数の食材を判定するための処理には、物体検出技術を用いて実装した。物体検出モデルはYOLOv8を用いて独自モデルの構築を行った。本プロダクトの主要目的は、ユーザーが手作業で行なっている食材管理を、画像処理を用いて自動化し、作業の効率化と時間の節約を図ることにあるため、精度の高い物体検出が求められる。

精度の高い物体検出モデルを作成するためには、学習させるデータセットの準備が大切である。理想とする画像データは、食材クラスごとの画像枚数は1500枚以上で、クラスごとのインスタンス数は10000以上が必要である。また、実際に使用する環境に近い環境下での画像で学習させることで、より精度の高いモデルを作成することができる。

本プロダクトでは、時間の都合上、数多くのデータが用意できなかったので、できる限りユースケースに基づくデータ収集を行った。

アノテーション(FastLabel)

アノテーションとは以下の図で示すように、物体検出したい位置を画像毎にラベリングしていく作業のことである。

今回は、アノテーション作業をFastLabelというWebサイト上でアノテーションできるツールを使用した。

YOLOv8のモデル

YOLOv8の中にも、以下の図で示すように様々な種類のモデルがある。

本プロダクトでは検出精度に重点を置いていることから、YOLOv8lモデルを用いてモデル作成を行った。

YOLOv8で独自クラスを追加するために、YOLOv8を管理しているUltralyticsのGitHubリポジトリを自分のGitHubアカウントにフォークし、独自の変更を可能とした。ファークしたリポジトリをプロジェクト内で使用するできるようにするために、プロジェクトのサブモジュールとして追加した。

独自モデルの学習

サブモジュール内に、datasetsというディレクトリを作成して、その中にrefrigeratorという冷蔵庫の食材を検出するモデルを構築するための学習データを格納するディレクトリを作成した。その中に、'images'とlabelsという2つのディレクトリを作成する。imageディレクトリには、アノテーションに使用した画像を入れ、labelsディレクトリにはアノテーションで作成された、テキストファイルを格納する。そして、それぞれのディレクトリ内に7:3の割合で画像データとテキストデータを格納する。図で表現すると以下のようになる。

datasets
└── refrigerator
    ├── images
    │   ├── train
    │   │   ├── train0.jpg
    │   │   └── train1.jpg
    │   └── val
    │       ├── val0.jpg
    │       └── val1.jpg
    └── labels
        ├── train
        │   ├── train0.txt
        │   └── train1.txt
        └── val
            ├── val0.txt
            └── val1.txt

データセットの準備をした後、データのデータセットのパス、クラス数、クラス名称をyamlファイルに記述する。

yaml
path: ../datasets/refrigerator  # dataset root dir
train: images/train  # train images path
val: images/val  # val images path

# Classes
nc: 23  # number of classes
names: ['tomato', 'tamanegi', 'zyagaimo', ・・・]  # class names

最後に、train.pyという実行ファイルを作成してトレーニングを開始した。

python
from ultralytics import YOLO
model = YOLO("yolov8l.pt")  

model.train(data="/ultralytics/dataset.yaml", epochs=100, batch=8, workers=4, degrees=90.0)

モデルのテスト

実際に作成したモデルを使って、テスト画像を与えて物体検出を行なってみると...

学習していない食材以外の判定に成功した!

レシピ生成(ChatGPT API+Webスクレイピング)

本プロダクトでは、食品ロスを削減するために賞味期限の短い食材を中心にレシピの提案する必要がある。

ユーザーから使用したい、食材の一覧を受け取った後、その食材を使って作成できるレシピをデータベースを参照して検索する。冷蔵庫にある食材が少なすぎて作成できるレシピがヒットしないという問題に対処するために、Webスクレイピングだけでなく、ChatGPT APIを使用して、レシピの生成の補助ができるようにした。

また、生成されたレシピデータとWebスクレイピングから得たレシピデータはデータベースに格納することで、コストの削減と処理の負荷を削減させた。

レシピを提供するための手順

データベースにデータを格納する場合としない場合のコスト比較

40万回レシピ生成が行われた場合の、データベース利用時と利用しない場合のコスト比較である。生成されたレシピが多くなればなるほど、レシピがデータベースに格納されている確率が高くなるため、コストが発生しにくくなる。

機能一覧

ログイン機能

  • googleアカウントを利用したユーザー登録(OAuth認証)

食材追加機能

  • 冷蔵庫の中身を撮影するだけで、食材が登録される
  • 食材の賞味期限も一部判定可能(判定不可の場合は、その食材の平均賞味期限を使用)
  • 手入力での簡易修正機能

健康管理機能

  • 作成したレシピと家族の人数によって自動的に摂取栄養素を計算する。

アップデート予定(今後追加したい機能)

時間があれば、搭載したかった機能の一覧です。

  • 買い物補助機能
    • ユーザーの食材の消費パターンをもとに、食材の無くなるタイミングを予測
    • その時、冷蔵庫に入っている食材との相性を考え、購入すべき食材を提案
    • ユーザーの栄養管理データ(健康データ)を元に、購入すべき食材を提案
  • 検出できる食材クラスの追加
    • 魚や調味料など様々なカテゴリーの検出・判別をできるようにモデルを作成
  • 物体検出・画像分類の精度向上
  • レシピ情報ページで、データベース情報から足りない食材を判定し、足りない食材を違う色で表示し、買い物リストに追加できる機能
  • 食材の賞味期限が近くなったら、通知を送る

⭐️冷蔵庫表面にディスプレイを冷蔵庫内にはカメラを複数台設置して、近未来の冷蔵庫を作ってみたい

開発中に苦労したこと

このプロダクトは、初めてのWebアプリケーションの開発であったこともあり、初めてなことばかりで全てにおいて苦労しました。HTMLやCSSも未経験で勉強することから始めたので、思った以上に時間もかかりました。特に動的な動作をJavaScriptで実装したい時、自分の思い通りになかなか実装できなかったのが精神できにも辛かったです。

今回、かなりの頻度で徹夜して開発して休憩も大事!?だと感じた。エラーでひたすら格闘して気がついたら数時間が経過している...。ここで粘って開発したときはほとんど解決することができなかった。しかし、次の日頭をリセットしてから考えると意外と簡単な問題だったりした笑

この開発を通して、HTMLやCSSやJavaScriptの基礎だけでなく、様々なAIの利用を通してAIの魅力を知ると同時に、AIの仕組みが知りたくなった。APIなどを用いて、モデルを作成するのも楽しいが、自分で1から実装してみたい気持ちが大きくなった。

Discussion