実践型AIプログラミング特講 最終章その5 #44

実践型AIプログラミング特講 最終章その5 #44

今回は前回に引き続いて画像解析について学んでいこうと思います。画像解析において重要になってくるのは限られたソース画像から汎用性の高い機械学習モデルを形成することです。なので少ないソースを最大限活用する方法を皆様にご紹介していきたいと思います。

料理の写真からカロリーを調べるツールを作ろう

画像分析を利用して、料理の写真からカロリーを計算するプログラムを作ってみましょう。そのために、写真共有サイトのFlickr から数種類の料理写真をダウンロードし、その料理写真を学習させて料理の判定を行います。

料理写真の判定方法について

ここでは、料理の写真からカロリーを計算するプログラムを作ります。その判定方法は、次の通りです。

(1)写真に何の料理が映っているのか判定する

(2) 判定した料理のカロリーを表示する

もちろん、ページ数に限りがあるので、あらゆる料理を網羅することはできません。ここでは「寿司」「サラダ」「麻婆豆腐」と3種類の写真を学習させて、カロリーを表示するプログラムを作ってみましょう。

機械学習でもっともたいへんなのはデータ集め

今回作成するプログラムでは、ただ3種類の料理の写真を判定させるだけです。たった3種類とは言え、それでもたくさんの写真を集めなければなりません。各料理につき、最低 100 枚以上の写真か必要です。それほど膨大な写真をどのようにして集めることができるでしょうか。ある程度の利益が見込めるのであれば、人海戦術でアルバイトを雇って写真を撮影してきてもらうこともできるでしょう。また、今ではクラウドソーシングなどを活用することで、比較的安い金額でデータの収集が可能です。さらに、インターネット上にあるデータをうまく活用できれば、手軽にデータを収集できます。写真データで言えば、写真の共有サイトがいくつもあり、そのうちいくつかは写真検索用の APIを提供しています。それらを活用することで、膨大な写真を手軽に集めることができます。今回は、写真共有サイト『Flickr』が提供する写真検索 API を利用して、料理の写真を大量に集めることにしましょう。

▲写真共有サイト『Flickr』の Web サイト

Flickr

[URL] https:///www.flickr. com/

Flickr API を使って写真を集めよう

さて、これから Flickr API を使って写真を大量に集めましょう。APIを使うためには、Flickr のサイトにログインして、APIキーを取得する必要があります。

APIを使うためのキーを取得しよう

キーの取得は簡単です。Yahoo.com(日本の Yahoo! のアカウントとは別物なので注意)のアカウントを作成した上で、以下のFlickr APIのページにアクセスします。

Flickr API のページ

[URL] https://www.flickr.com/services/api/

そこで、画面上部にある[Create an App]のリンクをクリックします。COMMERCIAL KEY(非商用利用)】か[APPLY FOR A COMMERCIAL KEY(商用利用)]かを選ぶ画面が出ます。目的に応じたキーを取得しましょう。続けて、作成するアプリの名前と何を作るのかを入力する画面が出ます。適当に入力して、利用規約に同意するチェックを入れて[SUBMIT(送信)】ボタンをクリックしましょう。すると、Flickr より「Key」と「Secret」という2つの文字列が得られます。この2つの文字列をコピーして控えておきましょう。

Flickr API を使うためのモジュール

Python から Flickr API を使うために必要なモジュールをインストールします。コマンドラインで、以下のコマンドを実行しましょう。

# モジュールのダウンロード

pip3 install flickrapi

以上で、Flickr APIを使う準備が整いました。

画像をダウンロードしよう

それでは、キーワードを指定して画像をダウンロードしましょう。以下のプログラムを実行するとFlickr から 75 × 75 ピクセルの正方形の写真を、300枚ずつダウンロードします。

# Flickr で写真を検索して、ダウンロードする

from flickrapi import FlickrAPI

from urllib.request import urlretrieve

from pprint import pprint

import os, time, sys

# API キーとシークレットの指定(★以下書き換えてください★)(*1)

key= “a880b66929d40bdc255e3cb6b28eaa56”

secret = “885f6135fc82a8e5”

wait_time =1 # 待機秒数(1以上を推奨)

# キーワードとディレクトリー名を指定してダウンロード(* 2)

def main():

go_download (’70 #a’, ‘sushi’)

go_download (‘H5’, ‘salad’)

go_download(‘麻婆豆腐’,’tofu’)

# Flickr API で写真を検索(*3)

def go_download (keyword, dir):

# 画像の保存パスを決定

savedir = “./image/” + dir

if not os.path.exists(savedir):

  1. mkdir (savedir)

# API を使ってダウンロード(*4)

flickr=FlickrAPI(key, secret, format=’parsed-json’)

res = flickr.photos.search(

text =keyword, # 検索語

per_page=300, # 取得件数

media=’photos’, # 写真を検索

sort=”relevance”, # 検索語の関連順に並べる

safe_search = 1, # セーフサーチ

extras =’url_q, license’)

# 検索結果を確認

photos= res[‘photos’]

print (photos)

try:

# 1枚ずつ画像をダウンロード(*5)

for i, photo in enumerate(photos[‘photo’]):

url_q = photo[‘url_q’]

filepath = savedir + ‘/’ + photo[‘id’] + ‘.jpg’

if os.path.exists(filepath): continue

print (str(i + 1) + “:download=”, url_q)

urlretrieve (url_q, filepath)

time.sleep (wait_time)

except:

import traceback

traceback.print_exc()

if __name__==’__main__’:

main()

最初に画像を保存するディレクトリー image を作成してから、プログラムを実行してみましょう。実行すると、image ディレクトリー以下に料理名のディレクトリーが作成され、300枚ずつの画像がダウンロードされます。プログラムを確認してみましょう。プログラムの(※1)では、Flickr の開発者サイトで取得したAPIのキーとシークレットを指定します。実際に利用する際は、この値を書き換えてから実行してください。また、一度に大量の画像をダウンロードしようとすると、Flickr のサーバーに負荷をかけてしまっので、写真を1枚ダウンロードするごとに1秒のウェイトを置くように配慮します。プログラムの(※2) の部分では、検索語句(キーワード)と保存するディレクトリー名を指定して、ダウンロードを実行するよう指示します。この部分を変更することで、別の写真をダウンロードできます。そして、(※3)以下の部分、関数go_download) では、Flickr API で写真を検索しダウンロードします。Aの部分で、キーワードを指定して検索し、APIの結果を得ます。どんな結果が返されるのかは、コマンドラインに表示されます。この検索 API では、最大300件の画像URLの一覧を得ることができます。(※5)の部分で画像を1枚ずつ、繰り返しダウンロードします。

クリーニング – 関係ない写真を削除しよう

ダウンロードが完了すると、料理名の各ディレクトリーに300件ずつ画像ファイルがあるのを確認できるでしょう。それらを一度確認してみましょう。そのうちのかなり多くの画像は、まったく関係のない画像です。そこで、ダウンロードした画像のうち、関係のないものを削除しましょう。つまり、以下のディレクトリーを確認して関係ないものを削除します。

なぜ関係のない写真がダウンロードされるのかと言うと、写真をアップロードしたユーザーが関係ないタイトルやタグをつけてアップロードすることがあるからです。また、関連するお店の写真や、材料や調理方法を示した写真である場合もあります。そこで正しい画像だけを残して、関係ない画像を削除しましょう。このクリーニングの作業が重要で、この作業の手を抜くと、あまり判定精度が上がりません。頑張ってデータセットのクリーニングを行いましよう。ここでは、300件の画像がありますが、厳選して100件ずつまで削ってください。このとき、対象が大きく映っており、関係のない物体が映り込んでいないこと、色が鮮明なものを中心に選ぶと良いでしょう。また、白黒画像やセピア調の画像など、本来の色合いからかけ離れているものも削除しましょう。

ディレクトリー以下の画像を NumPy 形式にまとめよう

加に 料理の写真が入った各ディレクトリーを、アータセットとして使えるよう、NumPy 形式に変換して、ファイルに保存しておきましょう。ダウンロードする料理画像は、カラー画像なので、RGB の多値は整数ですが、機械字習で使いやすいよっに、0から1までの実数に変換します。

# 画像ファイルを読んで NumPy 形式に変換

import numpy as np

from PIL import Image

import os, glob, random

outfile =”image/photos.npz” # 保存ファイル名

max_photo= 100 # 利用する写真の枚数

photo_size = 32 # ERX

x=[]#画像データ

y = [] # ラベルデータ

def main():

# 各画像のフォルダーを読む(*1)

glob_files (“./image/sushi”, 0)

glob_files (“./image/salad”, 1)

glob_files(“./image/tofu”, 2)

# ファイルへ保存(*2)

np.savez (outfile, x=x, y=y)

print (” 保存しました :” + outfile, len(x))

# path 以下の画像を読み込む(*3)

def glob_files (path, label):

files =glob.glob(path + “/*.jpg”)

random.shuffle(files)

# 各ファイルを処理

num =0

for f in files:

if num >= max_photo: break

num += 1

# 画像ファイルを読む

Img= Image.open(f)

Img= img.convert (“RGB”) # 色空間をR G Bに変換

Img=img.resize((photo_size, photo_size)) # サイズを変更

Img=np.asarray(img)

x.append (img)

у. append (label)

if __name__==’__main__’:

main()

少し歯切れが悪いですが本記事は以上になります。もうここまでついてこられた読者の方々にはなんの心配もしていません。自信を持って自分でプログラミングを改善してみるなり、新しく機械学習を実装してみるなり様々なことに挑戦してみてください。もうそれだけのスキルがとっくに身についているはずです。次回は最後にご紹介したソースコードの説明から始めたいと思います。

次回の記事

プログラミングカテゴリの最新記事