Qstairs

現役AIベンチャーCTOの知見、画像認識(人工知能、Deep Learning)を中心とした技術ノウハウをアップしていきます

広告

【画像認識】Pythonで画像認識とか(テンプレートマッチング:正規化相互相関)

f:id:qstairs:20161220213708j:plain

はじめに

最近はDeep Learningを使った画像認識ばかりでしたので、
画像認識の初歩に立ち返ってテンプレートマッチング処理をpythonOpenCVで実装しました。
楽しみながらやりたかったので、
今回テンプレートマッチには麻雀牌を選びました。
また、いくつかあるテンプレートマッチングの中で正規化相互相関を使っています。
この正規化相互相関は画像の全体的な輝度変化に頑健なアルゴリズムです。

※各牌の画像は天鳳さんでお借りしてます。
 オンライン対戦麻雀 天鳳 / 牌画

テンプレート画像一覧

f:id:qstairs:20161220212547p:plain

ターゲット画像

f:id:qstairs:20161220212609p:plain

出力結果

同じ画像に対してマッチング処理しているので当然スコアは1.0ですね。

f:id:qstairs:20161220212627j:plain

ソースコード

各テンプレート画像に対してターゲット画像とテンプレートマッチングを行っています。
ちょっと無駄が多いですが、一番簡単に実装するならこの方法かと...
今後いろいろ改良を加えていきたいと思います。

# -*- coding:utf-8 -*-
import os
import os.path
import cv2
import argparse

# 引数指定
parser = argparse.ArgumentParser(description='Train Sample')
parser.add_argument('--target', '-t', default='', type=str, help='Target Image')
parser.add_argument('--template', '-temp', default='unit', type=str, help='Template Folder')
parser.add_argument('--out', '-o', type=str, default='out', help='Output File')
args = parser.parse_args()

template_list = os.listdir(args.template)
template_images = []

# テンプレート一覧画像取得
for template_name in template_list:
    image = cv2.imread(args.template+"/"+template_name)
    template_images.append(image)

# マッチング対象
target_image = cv2.imread(args.target)
# 出力用
target_out_image = cv2.imread(args.target)

# 各テンプレート画像でマッチング
for template_image in template_images:

    # TM_CCOEFF_NORMED ゼロ正規化相互相関
    res = cv2.matchTemplate(target_image, template_image, cv2.TM_CCOEFF_NORMED)

    # 一番小さいスコアとその座標、一番高いスコアとその座標を取得する
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
    top_left = max_loc
    print max_val

    if max_val > 0.9:
        h, w = template_image.shape[:2]
        bottom_right = (top_left[0] + w, top_left[1] + h)

        # cv2.rectangle(out, pt1, pt2, color, thickness)
        cv2.rectangle(target_out_image, top_left, bottom_right, 255, 2)

        # image[y,x] = roi
        target_out_image[top_left[1]-h:top_left[1], top_left[0]:top_left[0]+w,:] = template_image

        # スコアを出力
        cv2.putText(target_out_image, "%0.2lf"%max_val, (top_left[0],top_left[1]-h), cv2.FONT_HERSHEY_PLAIN, 1, (0,0,255), thickness=2)

        cv2.imshow("out", target_out_image)
        cv2.imshow("template", template_image)
        cv2.waitKey(100)

# 出力
cv2.imwrite(args.out, target_out_image)

【画像認識・AI】Deep Learning「Chainer」で中間特徴量を画像化する方法

f:id:qstairs:20160601221351j:plain

はじめに

中間特徴量を画像化してみたくなったので、前に紹介した学習モデルを改良しました。

考え方

ネットワーク内の各層の入力と出力は配列になっています。
つまり、適当なサイズで二次元にしてあげれば画像になります。
以降に載せている処理を参考にしていただければ画像化はできます。
OpenCVを使用しています。

学習モデル

self.model = FunctionSetのl3の出力を画像化し、Intermediateフォルダに出力します。
そして、その画像と入力画像のmean_squared_errorをloss値として学習しています。
#この学習方法が良いのかはわかりません。

# -*- coding:utf-8 -*-
from chainer import cuda, Function, FunctionSet, gradient_check, Variable, optimizers, serializers
from chainer.training import extensions
import chainer.functions as F
import cv2
import numpy as np
import os
import os.path

class CNN():
    cuda.get_device(0).use()    # GPUを使用することを前提とする
    def __init__(self):
        if os.path.isdir("Intermediate") != True:
            os.mkdir("Intermediate")

        self.model = FunctionSet(
            conv1 = F.Convolution2D(1,32,3,pad=1),  # 100x100x1 -> 50x50x32
            conv2 = F.Convolution2D(32,32,3,pad=1), # 50x50x32 -> 25x25x32
            conv3 = F.Convolution2D(32,32,3,pad=1), # 25x25x32 -> 13x13x32
            conv4 = F.Convolution2D(32,32,3,pad=1), # 13x13x32 -> 7x7x32 = 1568
            l1 = F.Linear(1568,1000),
            l2 = F.Linear(1000,700),
            l3 = F.Linear(700,400),
            l4 = F.Linear(400,50),
            l5 = F.Linear(50,3),
        ).to_gpu()

    def forward(self, x_data, y_data, resize_data, epoch, train=True):
        x, t, r = Variable(x_data), Variable(y_data), Variable(resize_data) 
        c = F.max_pooling_2d(F.relu(self.model.conv1(x)), 2)
        c = F.max_pooling_2d(F.relu(self.model.conv2(c)), 2)
        c = F.max_pooling_2d(F.relu(self.model.conv3(c)), 2)
        c = F.max_pooling_2d(F.relu(self.model.conv4(c)), 2)

        h = F.dropout(F.relu(self.model.l1(c)), train=train)
        h = F.dropout(F.relu(self.model.l2(h)), train=train)
        h = F.relu(self.model.l3(h))

        # 中間特徴出力
        img = cuda.to_cpu(h.data.reshape(5,len(h.data)/5, 20, 20))
        resize_img = cuda.to_cpu(r.data.reshape(5,len(r.data)/5, 20, 20))
        for i in range(len(img)):
            yoko_img =  cv2.hconcat(img[i])
            yoko_resize = cv2.hconcat(resize_img[i])
            com_one_line = cv2.vconcat([yoko_img, yoko_resize])
            if i == 0:
                com_img = com_one_line
            else:
                com_img = cv2.vconcat([com_img, com_one_line])
        #cv2.imshow("Intermediate layer", com_img)
        #cv2.waitKey(1)
        cv2.imwrite("Intermediate/%06d.png"%epoch, com_img*255)
        loss1 = F.mean_squared_error(h, r)

        h = F.relu(self.model.l4(h))
        
        y = self.model.l5(h)

        if train:   # 学習時
            return F.softmax_cross_entropy(y, t)+loss1
        else:
            return y       # 評価時

学習処理

loss = model.forwardで誤差を算出する際に
入力画像をリサイズしたデータを引数に与えています。

# -*- coding:utf-8 -*-
import numpy as np
import chainer
from chainer import cuda, Function, FunctionSet, gradient_check, Variable, optimizers, serializers
from chainer.training import extensions
import argparse
import random
import chainer.functions as F
import cv2
import CNN_model as cnn
import time

cuda.get_device(0).use()    # GPUを使用することを前提とする

# 引数指定
parser = argparse.ArgumentParser(description='Train Sample')
parser.add_argument('--train_list', '-train', default='train.txt', type=str, help='Train data list')
parser.add_argument('--test_list', '-test', default='test.txt', type=str, help='Test data list')
parser.add_argument('--epoch', '-e', type=int, default=100, help='Number of epochs to train')
args = parser.parse_args()

# 学習モデル設定
model = cnn.CNN()
optimizer = optimizers.Adam()
optimizer.setup(model.model)

# 学習データリストファイルから一行ずつ読み込む
train_list = []
for line in open(args.train_list):
    pair = line.strip().split()
    train_list.append((pair[0], np.float32(pair[1])))

# 画像データとラベルデータを取得する
x_train = []    # 画像データ格納
y_train = []    # ラベルデータ格納
resize_train = []   # 画像リサイズデータ格納
for filepath, label in train_list:
    img = cv2.imread(filepath, 0)   # グレースケールで読み込む
    x_train.append(img)
    y_train.append(label)
    resize_img = cv2.resize(img,(20,20))
    resize_train.append(resize_img)

# 学習で使用するsoftmax_cross_entropyは
# 学習データはfloat32,ラベルはint32にする必要がある。
x_train = np.array(x_train).astype(np.float32)
y_train = np.array(y_train).astype(np.int32)
resize_train = np.array(resize_train).astype(np.float32)
# 画像を(学習枚数、チャンネル数、高さ、幅)の4次元に変換する
x_train = x_train.reshape(len(x_train), 1, 100, 100) / 255
resize_train = resize_train.reshape(len(resize_train), 400) / 255

N = len(y_train)

batchsize = 100
datasize = len(x_train)
n_epoch =  args.epoch   # 繰り返し学習回数
# 学習開始
train_start = time.time()
for epoch in range(1, n_epoch+1):
    sum_loss = 0
    perm = np.random.permutation(N) # データセットの順番をシャッフル
    train_start_one = time.time()
    for i in range(0,datasize, batchsize):
        x_batch = cuda.to_gpu(x_train[perm[i:i+batchsize]]) # バッチサイズ分のデータを取り出す
        y_batch = cuda.to_gpu(y_train[perm[i:i+batchsize]])
        resize_batch = cuda.to_gpu(resize_train[perm[i:i+batchsize]])
        # 初期化
        optimizer.zero_grads()
        # 誤差伝播
        loss = model.forward(x_batch, y_batch, resize_batch, epoch, train=True)
        # 誤差逆伝播
        loss.backward()
        # ネットワークパラメータ更新
        optimizer.update()

        sum_loss += loss.data
    print "epoch:{} loss={} time:{}".format(epoch, sum_loss / (datasize/batchsize), time.time()-train_start_one)

print "train time:{}".format(time.time()-train_start)
# 学習したモデルを出力する
serializers.save_npz("model_{}".format(n_epoch), model.model)
serializers.save_npz("state_{}".format(n_epoch), optimizer)

画像化イメージ

www.youtube.com



参考記事
qstairs.hatenablog.com

【画像認識】NECの顔認証決済サービス普及に向けた実験

f:id:qstairs:20161215225636j:plain

日本電気(NEC)と三井住友フィナンシャルグループ(SMFG)・三井住友銀行(SMBC)・三井住友カードは12日、FinTechへの取り組みの一環として、顔認証を活用した決済サービスの実証実験を行うと発表した。


news.mynavi.jp


この実証実験はFinTechへの取り組みの一環とありますが、
これはFinTechなのでしょうか?

それはさておき、
顔認証といえば、
ももクロなどのコンサートでチケット転売防止するためのシステムを導入している
NECが強いイメージがあります。
今回は、食堂の決済を顔認証で自動化する実験のようです。

私も社員食堂を使用していますが、
確かに一度食器を置いてカードをかざすという操作は少し面倒に思います。
#とはいえ、そこまでの負荷はありませんけどね(^_^;


記事にもあったように、
今回の実験の目的はどちらかというと顔認証決済サービスを普及させたいため、
「ちゃんと使えますよ」
ということを社会に伝えることがメインなのではないでしょうか。
また、実運用による知見を蓄えることが目的なのだと考えられます。


駅の改札でICカードを出さずに通過できるようになるといいですね!
ICカードを出すことに手間取る人がいると詰まってしまうので、
それを解消できそうです。

【画像認識】Amazon Go

f:id:qstairs:20161208234746j:plain


Amazonはレジに並んで会計を済ませなくても手軽に食品や総菜の買い物ができる食品店の実店舗を公開した。


wired.jp


最大の謎は、
手にした商品をどのようにして認識しているのか?
これにつきます。


技術としてはDeep Learningを使うことはわかるのですが、

商品が買い物客の手で隠れたり、
高速に棚からとったり、
商品の形が変わりやすかったり...etc

このようにいろんな問題があると思います。


この問題をどうやって解決したのか...


実際に店舗に行って、
いろんなこと(意地悪なこと)を試してみたくなりますね(^_^)

【画像認識】Deep Learningフレームワーク「Chainer」で学習経過を確認する

f:id:qstairs:20160601221047j:plain


前に紹介したランダム生成した○△□の識別学習をちょっと改良し、
学習経過を画像で確認できるようにしてみました。


qstairs.hatenablog.com



実際の学習経過を動画にしたのでよろしければ見てください。


youtu.be



繰り返し学習回数が増えていくと学習モデルの出力と入力画像が近づいていることが分かります。

ソースコードはまた今度紹介させていただきます。


【関連記事】
・「Chainer」での自前データによる識別
qstairs.hatenablog.com

・「Chainer」での自前データによる学習
qstairs.hatenablog.com

・「Chainer」での自前データによる学習の下準備
qstairs.hatenablog.com

【画像認識・AI】将棋自動実況システム

f:id:qstairs:20161203221925j:plain

株式会社Liaro(東京都渋谷区、代表取締役:花田賢人)は、Deep Learningなどの画像認識アルゴリズムを用いたAIによる将棋の自動実況システムを開発。


robotstart.info


システム名そのままの機能かと思いきや、
記事を読む限り、
実況ではなく駒の場所を認識しているだけのようです。

今後、盤面解析といった機能追加を進めるようですので、
これからに期待ですね!

#麻雀の何切る問題を自動解析するシステムとかも作れそう...
#作ってみようかな(´・ω・`)笑

【画像認識・AI】TensorflowがついにWindows対応!!

f:id:qstairs:20160601221047j:plain

Google Inc.は29日(現地時間)、機械学習のために開発されたオープンソースライブラリ「TensorFlow」の最新版v0.12が公開されたことを、公式ブログ“Google Developers Blog”で発表した。本バージョンでは、Windowsが新たにネイティブサポートされた。

forest.watch.impress.co.jp


ついに来ました!
TensorflowのWindows版!


今仕事ではChainerをメインでDeep Learningを使っていますが、
Tensorflowにも手を出そうかな...

広告