ぱそきいろのIT日記

ぱそきいろがITに関する記事を書いていきます。

深層学習で一枚の画像から人物認証をした話(画像の前処理)

こんにちは,ぱそきいろです.
ぱそきいろ (@takacpu55) | Twitter

今日は深層学習を使って人物認証で遊んだので,そのまとめになります.
具体的には僕が好きなユーチューバーのパオパオチャンネル(ぶんけい,@小豆)の二人を一枚の画像だけを使って分類してみました.
f:id:takabsk55:20190802124957j:plain
(パオパオチャンネル休止して寂しい)
長くなりそうだったので,今回は画像の前処理に関してのみ書いていきます.
学習に関してはこちらに載せています.
www.takacpu55.xyz

最後にソースコードを載せているので参考にしてください.
よろしくお願いします.

教師データを一枚にした理由

これは一言で言えます.
「教師データを準備するのがめんどくさかったから笑」
一枚づつ画像をダウンロードして,ラベル付けして,,,を何十枚とやる気力が起きません.
Webスクレイピングが出来る人は上手いことやるのでしょうが,そこまで手が回りません.
(いつかはちゃんと勉強しないと,,,)
そこで,二人が映った一枚の画像を使って人物認証をしていきたいと思います.
データが少ない分,ファインチューニングを用いて推定していきます.
学習に関してはまた別の記事で説明します.

OpenCVで顔の切り出し

まずはこちらの記事を参考に画像から顔の部分を切り出します.
ysss.hateblo.jp
切り出した画像がこちら
f:id:takabsk55:20190802154337j:plain
別々に保存したのがこちら
f:id:takabsk55:20190802154436j:plainf:id:takabsk55:20190802154450j:plain
これらを画像処理を使ってデータの水増しをしていきます.
画像を使った学習ではデータの水増しをするのが常套手段みたいです.

データの水増し

これはこちらの記事を参考にさせていただきました.
qiita.com
ここで紹介されている手法×上下の反転で36枚に増やします.
元画像
f:id:takabsk55:20190802154931j:plain
増やしたデータ
f:id:takabsk55:20190802155936p:plainf:id:takabsk55:20190802155944p:plain
これらを使って学習していきます.

まとめ

今回は深層学習に使う画像の前処理について書きました.
次回はこの画像を使って学習していきたいと思います.
ありがとうございました.

ソースコード

顔画像の切り出し

# coding: utf-8


import cv2
import matplotlib.pyplot as plt

# 画像読込み
origin_img = cv2.imread("kanta.jpg")
# 画像コピー
img = origin_img.copy()

# カスケードファイルのパス
cascade_path = "haarcascade_frontalface_alt.xml"
# カスケード分類器の特徴量取得
cascade = cv2.CascadeClassifier(cascade_path)

# 画像グレースケール化
grayscale_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# 顔検出
# minSize 最小サイズ指定
front_face_list = cascade.detectMultiScale(grayscale_img, minSize=(100, 100))

# 検出判定
print(front_face_list)
if len(front_face_list) == 0:
    print("Failed")
    quit()

# 検出位置描画
for (x, y, w, h) in front_face_list:
    print("[x,y] = %d,%d [w,h] = %d,%d" % (x, y, w, h))
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), thickness=10)

# 顔検出画像表示
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.show()
# 顔検出画像出力
cv2.imwrite("out.jpg", img)

# 検出画像出力
for (x, y, w, h) in front_face_list:
    face_img = origin_img[y:y + h, x:x + w]
    dst=cv2.resize(face_img,dsize=(224,224))
    filename = "face_" + str(x) + "-" + str(y) + ".jpg"
    cv2.imwrite(filename, dst)

データの水増し

# coding: utf-8
import numpy as np

import cv2


import chainer
FOLDER="./datas/kanta/image/"
NAME="kanta.jpg"
#反転

flip= cv2.imread(FOLDER+NAME, 1)
hflip_img = cv2.flip(flip, 1)
vflip_img = cv2.flip(flip, 0)
vhflip_img=cv2.flip(hflip_img, 0)
cv2.imwrite(FOLDER+"tate.jpg",hflip_img)
cv2.imwrite(FOLDER+"yoko.jpg",vflip_img)
cv2.imwrite(FOLDER+"tateyoko.jpg",vhflip_img)

list=[flip,hflip_img,vflip_img,vhflip_img]
for num,src in enumerate(list):
    print(num)

    # ルックアップテーブルの生成
    min_table = 50
    max_table = 205
    diff_table = max_table - min_table

    LUT_HC = np.arange(256, dtype = 'uint8' )
    LUT_LC = np.arange(256, dtype = 'uint8' )

    # ハイコントラストLUT作成
    for i in range(0, min_table):
        LUT_HC[i] = 0
    for i in range(min_table, max_table):
        LUT_HC[i] = 255 * (i - min_table) / diff_table
    for i in range(max_table, 255):
        LUT_HC[i] = 255

    # ローコントラストLUT作成
    for i in range(256):
        LUT_LC[i] = min_table + i * (diff_table) / 255

    # 変換

    high_cont_img = cv2.LUT(src, LUT_HC)
    low_cont_img = cv2.LUT(src, LUT_LC)

    cv2.imwrite(FOLDER+"high"+str(num)+".jpg", high_cont_img)
    cv2.imwrite(FOLDER+"low"+str(num)+".jpg",low_cont_img)



    LUT_G1 = np.arange(256, dtype = 'uint8' )
    LUT_G2 = np.arange(256, dtype = 'uint8' )
    # ガンマ変換ルックアップテーブル
    gamma1 = 0.75
    gamma2 = 1.5
    for i in range(256):
        LUT_G1[i] = 255 * pow(float(i) / 255, 1.0 / gamma1)
        LUT_G2[i] = 255 * pow(float(i) / 255, 1.0 / gamma2)

    high_cont_img = cv2.LUT(src, LUT_G1)
    low_cont_img = cv2.LUT(src, LUT_G2)

    cv2.imwrite(FOLDER+"G1"+str(num)+".jpg", high_cont_img)
    cv2.imwrite(FOLDER+"G2"+str(num)+".jpg",low_cont_img)


    #平滑化
    average_square = (2,2)
    blur_img = cv2.blur(src, average_square)
    cv2.imwrite(FOLDER+"hei"+str(num)+".jpg", blur_img)

    #ガウス
    row,col,ch= src.shape
    mean = 0
    sigma = 15
    gauss = np.random.normal(mean,sigma,(row,col,ch))
    gauss = gauss.reshape(row,col,ch)
    gauss_img = src + gauss
    cv2.imwrite(FOLDER+"gauss"+str(num)+".jpg", gauss_img)


    #ソルトアンドペッパー
    row,col,ch = src.shape
    s_vs_p = 0.5
    amount = 0.004
    salt_img = src.copy()
    papper_img=src.copy()

    # 塩モード
    num_salt = np.ceil(amount * src.size * s_vs_p)
    coords = [np.random.randint(0, i-1 , int(num_salt)) for i in src.shape]
    salt_img[coords[:-1]] = (255,255,255)
    cv2.imwrite(FOLDER+"salt"+str(num)+".jpg", salt_img)


    # 胡椒モード
    num_pepper = np.ceil(amount* src.size * (1. - s_vs_p))
    coords = [np.random.randint(0, i-1 , int(num_pepper)) for i in src.shape]
    papper_img[coords[:-1]] = (0,0,0)
    cv2.imwrite(FOLDER+"papper"+str(num)+".jpg",papper_img)