株式会社IoTBankでは一緒に働く仲間を募集しています
どうも、ガジェット好きPyおじです。
ウチの周りには野良猫が多く、糞害、車のボンネットに乗る、自転車の前かごにスッポリはまってくつろぐ、など、大変に迷惑しております。
そこで、なんとか野良猫を追っ払うために、私は考えました。
使ってないスマートフォンのカメラを入力にして、猫を検知したら「ガオー」と音声が流れるというアプリを作って、追っ払ってやろうと!
流れはこうです。
- スマートフォンのカメラで1秒毎に撮影。jpgをAPIに投げる
- APIで受け取った画像から、猫を検知する。結果をスマートフォンに返す。
- カメラのFlashを焚いてもいいが、昼間も機能させたいのでスマートフォンから音を出し驚かす。
とりあえず、画像認識機能から手をつけようと思いまして、後学(向学、好学)のために、Kerasの有りモノのVGG16モデルにPASCAL VOC2012の画像を食わせて、猫と猫以外に2クラス分類させてみました。
ただ、正直、VGG16モデルをそのまま使って、猫を検知させたほうが精度は良いです。その場合、Egyptian_catとかPersian_catとかtiger_catというラベルが返ってきます。
- 前処理
で、VOC2012のデータですが、使うのは
VOCdevkit/VOC2012/JPEGImages/*.jpg
VOCdevkit/VOC2012/Annotations/*xml
でして、画像ファイル名とラベルを紐付けたDataFrameを作っちゃいましょう。
# xmlからDataFrameを作成
def xml_2_df(xmlFiles):
image_id = 0
dic_list=list()
for file in xmlFiles:
annotation_path = file
image = dict()
doc = xmltodict.parse(
open(annotation_path).read(), force_list=('object'))
# jpg名
image['file_name'] = str(doc['annotation']['filename'])
image['height'] = int(doc['annotation']['size']['height'])
image['width'] = int(doc['annotation']['size']['width'])
# ラベル
image['label'] = str(doc['annotation']['object'][0]['name'])
dic_list.append(image)
df_load = pd.DataFrame(dic_list)
return df_load
path = "VOCdevkit/VOC2012/Annotations/"
trainXMLFiles = glob.glob(os.path.join(path, '*.xml'))
df_images = xml_2_df(trainXMLFiles)
df_images
DataFrameができました。
教師データX、正解ラベルYを用意しましょう。
from keras.preprocessing.image import array_to_img, img_to_array, load_img
from keras.utils import np_utils
from tensorflow.keras.applications.vgg16 import preprocess_input
# 画像
input_dirpath = 'VOCdevkit/VOC2012/JPEGImages/'
# サブディレクトリ配下の画像(パス)を取得する。
img_files = glob.glob(os.path.join(input_dirpath, '*.jpg'))
X_train = []
X_test = []
y_train = []
y_test = []
IMAGE_SIZE = 112
X_data=[]
Y_data=[]
# 画像パスから行列として読み込む
for img_path in img_files:
temp_img = load_img(img_path, target_size=(IMAGE_SIZE,IMAGE_SIZE))
# np.arrayへ変換 (IMAGE_SIZE, IMAGE_SIZE, 3)の行列
img_arr = img_to_array(temp_img)
# 画素値を0から1の範囲に変換
X_ = preprocess_input(img_arr)
# listに突っ込む
X_data.append(X_)
basename = os.path.basename(img_path)
# ラベルデータ
row=df_images.loc[df_images['file_name'] ==basename]
# listに突っ込む
Y_data.append(row['label'].values[0])
# クラスの形式を変換 出力層が1なのでone hot しない
#Y_data = np_utils.to_categorical(Y_data, 2)
# arrayに変換
X_data = np.asarray(X_data)
Y_data= np.asarray(Y_data)
VGG16モデルを使った2クラス分類は調べれば沢山出てくるのでここでは書きませんが、出力層が
model.add(Dense(1, activation='sigmoid'))
なので、0.5を閾値にして猫が写った画像かそうじゃないかの判定までは出来ました。
次は、aws lambdaを使って、画像の判定をAPI化してみようと思います。
つづく。。。