機械学習 マスク写真判定

Visual Geometry Group - University of Oxford
Computer Vision group from the University of Oxford
Pubfig: Public Figures Face Database

画像から人間の顔を検出して、顔画像を保存するプログラム

import cv2, dlib, sys, glob, pprint

# 入力ディレクトリの指定
indir = "./capture"
# 出力ディレクトリの指定
outdir = "./face"
# 暫定的な画像のID
fid = 1000
# 入力画像をリサイズするか?
flag_resize = False

# dlibをはじめる
detector = dlib.get_frontal_face_detector()

# 顔画像を取得して保存する
def get_face(fname):
    global fid
    img = cv2.imread(fname)
    # デジタルカメラなどの画像であれば
    # サイズが大きいのでリサイズ
    if flag_resize:
        img = cv2.resize(img, None,
            fx = 0.2, fy = 0.2)
    # 顔検出
    dets = detector(img, 1)
    for k, d in enumerate(dets):
        pprint.pprint(d)
        x1 = int(d.left())
        y1 = int(d.top())
        x2 = int(d.right())
        y2 = int(d.bottom())
        im = img[y1:y2, x1:x2]
        # 50x50にリサイズ
        try:
            im = cv2.resize(im, (50, 50))
        except:
            continue
        # 保存
        out = outdir + "/" + str(fid) + ".jpg"
        cv2.imwrite(out, im)
        fid += 1

# ファイルを列挙して繰り返し顔検出を行う
files = glob.glob(indir+"/*")
for f in files:
    print(f)
    get_face(f)
print("ok")

学習プログラム

import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras.optimizers import RMSprop
import matplotlib.pyplot as plt
import cv2, glob
import numpy as np

# 画像形式の指定 --- (※1)
in_shape = (50, 50, 3)
nb_classes = 2

# CNNモデル構造を定義 --- (※2)
model = Sequential()
model = Sequential()
model.add(Conv2D(32,
          kernel_size=(3, 3),
          activation='relu',
          input_shape=in_shape))
model.add(Conv2D(32, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(nb_classes, activation='softmax'))

# モデルをコンパイル --- (※3)
model.compile(
    loss='categorical_crossentropy',
    optimizer=RMSprop(),
    metrics=['accuracy'])

# 画像データをNumpy形式に変換 --- (※4)
x = []
y = []
def read_files(target_files, y_val):
    files = glob.glob(target_files)
    for fname in files:
        print(fname)
        # 画像を読み出し
        img = cv2.imread(fname)
        # 画像サイズを50x50に変換
        img = cv2.resize(img, (50, 50))
        print(img)
        x.append(img)
        y.append(np.array(y_val))

# ディレクトリ内の画像を集める
read_files("imageset/mask_off/*.jpg", [1,0])
read_files("imageset/mask_on/*.jpg", [0,1])
x_train, y_train = (np.array(x), np.array(y))
# テスト用の画像をNumpy形式で得る
x, y = [[], []]
read_files("imageset/mask_off_test/*.jpg", [1,0])
read_files("imageset/mask_on_test/*.jpg", [0,1])
x_test, y_test = (np.array(x), np.array(y))
# データを学習 --- (※5)
hist = model.fit(x_train, y_train,
    batch_size=100,
    epochs=100,
    validation_data=(x_test, y_test))
# データを評価
score = model.evaluate(x_test, y_test, verbose=1)
print("正解率=", score[1], 'loss=', score[0])
# モデルを保存 --- (※6)
model.save('mask_model.h5')
# 学習の様子を描画 --- (※7)
plt.plot(hist.history['accuracy'])
plt.plot(hist.history['val_accuracy'])
plt.title('Accuracy')
plt.legend(['train', 'test'], loc='upper left')
plt.show()

LIVEマスクチェック

import keras
import cv2, dlib, pprint, os
import numpy as np
from keras.models import load_model

# 結果ラベル
res_labels = ['NO MASK!!', 'ok']
save_dir = "./live"

# 保存した学習データを読む --- (※1)
model = load_model('mask_model.h5')

# Dlibをはじめる --- (※2)
detector = dlib.get_frontal_face_detector()

# Webカメラから入力を開始 --- (※3)
red = (0,0,255)
green = (0, 255, 0)
fid = 1
cap = cv2.VideoCapture(0)
while True:
    # カメラの画像を読み込む --- (※4)
    ok, frame = cap.read()
    if not ok: break
    # 画像を縮小表示する --- (※5)
    frame = cv2.resize(frame, (500,300))
    # 顔検出 --- (※6)
    dets = detector(frame, 1)
    for k, d in enumerate(dets):
        pprint.pprint(d)
        x1 = int(d.left())
        y1 = int(d.top())
        x2 = int(d.right())
        y2 = int(d.bottom())
        # 顔部分を切り取る --- (※7)
        im = frame[y1:y2, x1:x2]
        im = cv2.resize(im, (50, 50))
        im = im.reshape(-1, 50, 50, 3)
        # 予測 --- (※8)
        res = model.predict([im])[0]
        v = res.argmax()
        print(res_labels[v], res)
        # 枠を描画 --- (※9)
        color = green if v == 1 else red
        border = 2 if v == 1 else 7
        cv2.rectangle(frame, 
          (x1, y1), (x2, y2), color, 
          thickness=border)
        # テキストを描画
        cv2.putText(frame,
            res_labels[v], (x1, y1-7),
            cv2.FONT_HERSHEY_SIMPLEX,
            0.9, color, thickness=2)
    if len(dets) > 0: # 結果を保存
        if os.path.exists(save_dir):
            jpgfile = save_dir + "/" + str(fid) + ".png"
            cv2.imwrite(jpgfile, frame)
            fid += 1
    # ウィンドウに画像を出力 --- (※10)
    cv2.imshow('Mask Live Check', frame)
    # ESCかEnterキーが押されたらループを抜ける
    k = cv2.waitKey(1) # 1msec確認
    if k == 27 or k == 13: break

cap.release() # カメラを解放
cv2.destroyAllWindows() # ウィンドウを破棄

写真チェックプログラム

import keras
import cv2, dlib, pprint, os, sys
import numpy as np
from keras.models import load_model

# 結果ラベル
res_labels = ['NO MASK!!', 'ok']

# 保存した学習データを読む 
model = load_model('mask_model.h5')

# 写真から入力を
if len(sys.argv) <= 1:
    print("[USAGE] photo_check.py infile.jpg")
    quit()
fname = sys.argv[1]
frame = cv2.imread(fname)
# 横幅が500pxになるようリサイズ
width = 500
h, w = frame.shape[:2]
height = round(h * (width / w))
frame = cv2.resize(frame, dsize=(width, height))

# 顔検出
red = (0,0,255)
green = (0, 255, 0)
detector = dlib.get_frontal_face_detector()
dets = detector(frame, 1)
for k, d in enumerate(dets):
    pprint.pprint(d)
    x1 = int(d.left())
    y1 = int(d.top())
    x2 = int(d.right())
    y2 = int(d.bottom())
    # 顔部分を切り取る
    im = frame[y1:y2, x1:x2]
    im = cv2.resize(im, (50, 50))
    im = im.reshape(-1, 50, 50, 3)
    # 予測 
    res = model.predict([im])[0]
    v = res.argmax()
    print(res_labels[v], res)
    # 枠を描画
    color = green if v == 1 else red
    border = 2 if v == 1 else 7
    cv2.rectangle(frame, 
      (x1, y1), (x2, y2), color, 
      thickness=border)
    # テキストを描画
    cv2.putText(frame,
        res_labels[v], (x1, y1-7),
        cv2.FONT_HERSHEY_SIMPLEX,
        0.9, color, thickness=2)

jpgfile = fname + "-out.png"
cv2.imwrite(jpgfile, frame)

タイトルとURLをコピーしました