みらいテックラボ

音声・画像認識や機械学習など, 週末プログラマである管理人が興味のある技術の紹介や実際にトライしてみた様子などメモしていく.

ペットボトルを認識してみよう! (1)

これは, 昨年の10月~12月に開催された「チームで学ぼう! TensorFlow(機械学習)実践編第2期」において, 私の参加した「チーム仲鶴後吉(仮)」の成果を数回に分けて紹介するものである. (勉強会からずいぶん時間が経ってしまったが....)

関連記事
ペットボトルを認識してみよう! (1)
ペットボトルを認識してみよう! (2)
ペットボトルを認識してみよう! (3)
ペットボトルを認識してみよう! (4)
ペットボトルを認識してみよう! (5)

0. メンバー紹介
メンバーは以下の4名.

名前スキルなど
仲 〇組み込みソフト開発, データ分析, システム設計, 機械学習, C, R, Python(初心者)
鶴 □パターン認識(音声, 文字), 機械学習の経験あり, 端末アプリ, ミドルウェア開発. C/C++, Android Java, Python(初心者)
後 ◇物理学出身, レーダの信号処理考える仕事, 機械学習独学3年, Python3年
吉 △機械学習の経験なし, C言語, プログラマ歴1年ちょい, Python(初心者)

ちなみにチーム名の由来であるが, これはチーム発足時にチーム名を付ける必要があったのだが, メンバーの苗字の一字を組み合わせて仮の名を付けたことが始まりである.

1. テーマと目標
勉強会は, 「TensorFlowやKerasなどの機械学習ツールを使ったサービスを考え, 実装を通じて機械学習を学ぶ.」ということで, 参加者が6チーム(4-5名)に分かれ, チームでそれぞれ何をやるか決めるところから始まった.
我々のチームでもアイデア出しの段階ではいろいろな案が出たが, 実際に実装し試すことを考えると, データをある程度集めやすいテーマとする必要があった.

そこで決まったテーマと目標は以下の通り.

テーマ:
「ペットボトル飲料のカテゴリ認識とその応用」

f:id:moonlight-aska:20170414233652j:plain:w100 

目標:
 STEP1 メーカー画像(1本/背景白)での判別
   ・データの収集, 各種画像処理によるデータ水増しツールを作成する.
   ・TensorFlowの使い方を学ぶ
   ・CNNによる画像認識をとりあえずやってみる.
 STEP2 実環境下(複数本/背景あり)での判別
   ・実環境下でのデータ収集を行う.
   ・ペットボトル候補領域の切り出しとペットボトル認識を組み合わせる.
 STEP3 応用
   ・ペットボトル認識の応用を考える.
   ・応用例を実装する. ('16/12までには難しいかな!?)

システムイメージ:
f:id:moonlight-aska:20170414235941p:plain:w500

ペットボトルのカテゴリ認識を通して, TensorFlowの使い方や画像認識をステップを踏んで学びやってみることに注力し, 応用については時間があればということにして活動を開始.

2. データ収集と整備
2.1 画像データ収集
ペットボトルの画像とその商品情報を集める必要があるが, 効率的に画像を集めるために, まずは各飲料メーカーのHPから集めることにした.
画像を1枚1枚ダウンロードしていたのではデータ収集に時間がかかるので,商品一覧ページから画像を一括取得する簡単なツールを作成し, 作業を効率化.
f:id:moonlight-aska:20170415001140p:plain:w300

(1) 画像URLのリスト作成
[コード]

# -*- coding: utf-8 -*- 

import urllib
#import urllib.request
import chardet
import os.path
# from html.parser import HTMLParser
from HTMLParser import HTMLParser

class imgParser(HTMLParser):

    def __init__(self):
        HTMLParser.__init__(self)

    def handle_starttag(self,tagname,attribute):
        if tagname.lower() == "img":
            for i in attribute:
                if i[0].lower() == "src":
                    # ボタン等はgifが多いので除去
                    if '.gif' in i[1]:  
                        continue
                    idx = i[1].find('?')
                    if idx == -1:   # サイズ指定なし
                        img_url=i[1]
                    else:
                        img_url=i[1][:idx]
                    # 取得した画像のURLを集めたファイルの作成
                    f = open("collection_url.csv","a")
                    # サントリー
                    if input_num == 1:
                        f.write("=IMAGE(\"{}\")\n".format(img_url))
                    # コカ・コーラ
                    elif input_num == 2:
                        f.write("=IMAGE(\"http://www.cocacola.co.jp{}\")\n".format(img_url))
                    # アサヒ飲料
                    elif input_num == 3:
                        f.write("=IMAGE(\"http://www.asahiinryo.co.jp{}\")\n".format(img_url))
                    # 他(サイトによってパスが違う)ls
                    else:
                        if img_url.startswith('http'): # httpで始まる
                            f.write("=IMAGE(\"{}\")\n".format(img_url))
                        elif img_url.startswith('/'):   # '/'で始まる
                            f.write("=IMAGE(\"" + serch_url + "{}\")\n".format(img_url))
                        else:
                            f.write("=IMAGE(\"" + serch_url + "/{}\")\n".format(img_url))
                    f.close()

if __name__ == "__main__":
    # ファイルの削除
    if os.path.exists("collection_url.csv"):
        os.remove("collection_url.csv")
    print('画像を取得したいURLを入力してください。')
    print('1: サントリー\n2: コカ・コーラ\n3: アサヒ飲料(炭酸のページ)\n4: 他(直接入力)')
    input_num = input('>>>  ')
    if input_num == 1:
        serch_url = 'http://www.suntory.co.jp/softdrink/products'
    elif input_num == 2:
        serch_url = 'http://www.cocacola.co.jp/brands/all-products'
    elif input_num == 3:
        serch_url = 'http://www.asahiinryo.co.jp/products/carbonated'
    else:
        print('URLを入力してください。')
        input_num = input('>>>  ')
        serch_url = input_num
        
    print('画像URLを取得中です...')
    # data = urllib.request.urlopen(serch_url).read()
    data = urllib.urlopen(serch_url).read()
    enc = chardet.detect(data)
    htmldata = data.decode(enc['encoding'])

    parser = imgParser()
    parser.feed(htmldata)
    parser.close()

    print("collection_url.csvを作成しました")

(2) URLリストの画像ダウンロード
[コード]

# -*- coding: utf-8 -*- 

import urllib
# import urllib.request
import os.path
import re

def download(url,savename):
    # img = urllib.request.urlopen(url)
    img = urllib.urlopen(url)
    basename, ext = os.path.splitext(os.path.basename(url))
    filename = savename + ext
    localfile = open(filename.strip(), 'wb')
    localfile.write(img.read())
    img.close()
    localfile.close()

def get_url_root(url):
    if("http://" in url):
        url_delet_http = url.lstrip("http://")
        if("/" in url_delet_http):
            url_root = "http://" + url_delet_http[0:url_delet_http.find("/")]
            return url_root
    elif("https://" in url):
        url_delet_http = url.lstrip("https://")
        if("/" in url_delet_http):
            url_root = "http://" + url_delet_http[0:url_delet_http.find("/")]
            return url_root
    return 0

if __name__ == "__main__":
    print('画像URLリストのファイル名を入力してください')
    print('./collection_url.csvでよければ"1"を入力してください')
    input_filename = input('>>>  ')
    if input_filename == 1:
        input_filename = 'collection_url.csv'
    print(input_filename)
    
    # 生成したファイルの読み込み
    f = open("{}".format(input_filename),"r")
    url_list = []
    for row in f:
        # row_url = row.split('\t') --> csv ','区切り対応
        row_url = row.split(',')
        for k, u in enumerate(row_url):
            if u.startswith('=IMAGE'): 
                u = re.sub('^=IMAGE\(\"', "", u)
                u = re.sub('\"\)$', "", u)
                url_list.append(u)
    len_url = len(url_list)
    f.close()
    print('{} file(s)'.format(len_url))
    number_url = []
    
    # for i in range(0,(len_url-1)):
    for i in range(0,(len_url)):
        number_url.append(url_list[i])
    
    # for j in range(0,(len_url-1)):
    for j in range(0,(len_url)):
        url = number_url[j]
        if("../" in url):
            root_url = get_url_root(url)
            if(root_url!=0):
                url = url.replace("..",root_url)
        print(url)
        download(url, "asahi_{0:04d}".format(j))
    print('画像のダウンロードが終了しました')

2.2 ラベリング
ペットボトルのカテゴリは以下の11種とし, 2.1で収集した画像データと各飲料メーカーの情報を見ながら, 人手で不要な画像の除去とラベリングを行った.
f:id:moonlight-aska:20170415002519p:plain:w400
[注] 各画像は各飲料メーカーのHPのものを使わせていただいています.

例えば上記の一部コーヒーとコーラのように, パッと見画像だけではどちらか分かりにくいものもあることが分かった.
ボトル形状はかなり類似しているので, 主にボトルラベルや飲料水の色でカテゴリを識別するので, カテゴリ数は少ないが結構難しいかも...

収集したペットボトルの画像データ数は以下の通り. (最終報告時点)
f:id:moonlight-aska:20170415074130p:plain

今回は, 「データ収集と整備」について紹介したが, 次回は学習データを増やすための「画像の水増し」などについて紹介する予定.

---





PythonによるWebスクレイピング

PythonによるWebスクレイピング