【画像認識】Pythonで画像認識とか(テンプレートマッチング:正規化相互相関)
はじめに
最近はDeep Learningを使った画像認識ばかりでしたので、
画像認識の初歩に立ち返ってテンプレートマッチング処理をpythonとOpenCVで実装しました。
楽しみながらやりたかったので、
今回テンプレートマッチには麻雀牌を選びました。
また、いくつかあるテンプレートマッチングの中で正規化相互相関を使っています。
この正規化相互相関は画像の全体的な輝度変化に頑健なアルゴリズムです。
※各牌の画像は天鳳さんでお借りしてます。
オンライン対戦麻雀 天鳳 / 牌画
テンプレート画像一覧
ターゲット画像
出力結果
同じ画像に対してマッチング処理しているので当然スコアは1.0ですね。
ソースコード
各テンプレート画像に対してターゲット画像とテンプレートマッチングを行っています。
ちょっと無駄が多いですが、一番簡単に実装するならこの方法かと...
今後いろいろ改良を加えていきたいと思います。
# -*- 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」で中間特徴量を画像化する方法
はじめに
中間特徴量を画像化してみたくなったので、前に紹介した学習モデルを改良しました。
考え方
ネットワーク内の各層の入力と出力は配列になっています。
つまり、適当なサイズで二次元にしてあげれば画像になります。
以降に載せている処理を参考にしていただければ画像化はできます。
※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)
【画像認識】NECの顔認証決済サービス普及に向けた実験
日本電気(NEC)と三井住友フィナンシャルグループ(SMFG)・三井住友銀行(SMBC)・三井住友カードは12日、FinTechへの取り組みの一環として、顔認証を活用した決済サービスの実証実験を行うと発表した。
この実証実験はFinTechへの取り組みの一環とありますが、
これはFinTechなのでしょうか?
それはさておき、
顔認証といえば、
ももクロなどのコンサートでチケット転売防止するためのシステムを導入している
NECが強いイメージがあります。
今回は、食堂の決済を顔認証で自動化する実験のようです。
私も社員食堂を使用していますが、
確かに一度食器を置いてカードをかざすという操作は少し面倒に思います。
#とはいえ、そこまでの負荷はありませんけどね(^_^;
記事にもあったように、
今回の実験の目的はどちらかというと顔認証決済サービスを普及させたいため、
「ちゃんと使えますよ」
ということを社会に伝えることがメインなのではないでしょうか。
また、実運用による知見を蓄えることが目的なのだと考えられます。
駅の改札でICカードを出さずに通過できるようになるといいですね!
ICカードを出すことに手間取る人がいると詰まってしまうので、
それを解消できそうです。
【画像認識】Deep Learningフレームワーク「Chainer」で学習経過を確認する
前に紹介したランダム生成した○△□の識別学習をちょっと改良し、
学習経過を画像で確認できるようにしてみました。
実際の学習経過を動画にしたのでよろしければ見てください。
繰り返し学習回数が増えていくと学習モデルの出力と入力画像が近づいていることが分かります。
ソースコードはまた今度紹介させていただきます。
【関連記事】
・「Chainer」での自前データによる識別
qstairs.hatenablog.com
・「Chainer」での自前データによる学習
qstairs.hatenablog.com
・「Chainer」での自前データによる学習の下準備
qstairs.hatenablog.com