当然の発展として、物体識別であらかじめ識別してタグ付けした。
おまけに、fpsを画面に表示するようにしました。
ちなみに、7-8fps(1060)、29-30fps(1080)でした。
コードは以下に置いた
OpenCV / meanshift_recognizedByVGG16.py
やったこと
機能として以下3つ追加した。
1.追跡する物体を決定したとき、物体識別をVGG16で実施
2.fpsを計測して画像の左上に表示
3.動画を保存する
1.追跡する物体を決定したとき、物体識別をVGG16で実施
コードは以下のとおりで、先日のFlaskと同じくVGG16を利用したyomikomi()関数を使った。今回は引数として取得した画像を渡す。
def yomikomi(img):
batch_size = 2
num_classes = 1000
img_rows, img_cols=img.shape[0],img.shape[1]
input_tensor = Input((img_rows, img_cols, 3))
# 学習済みのVGG16をロード
# 構造とともに学習済みの重みも読み込まれる
model = VGG16(weights='imagenet', include_top=True, input_tensor=input_tensor)
model.summary()
# 引数で指定した画像ファイルを読み込む
# サイズはVGG16のデフォルトである224x224にリサイズされる
# 読み込んだPIL形式の画像をarrayに変換
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
#preds = model.predict(preprocess_input(x))
preds = model.predict(x)
results = decode_predictions(preds, top=1)[0]
return str(results[0][1])
呼び出し側は以下のとおり、
def main():
cap = cv2.VideoCapture(0)
# 追跡する枠の座標とサイズ
x = 100
y = 100
w = 224
h = 224
track_window = (x, y, w, h)
# フレームの取得
ret,frame = cap.read()
cv2.waitKey(2)
# 追跡する枠を決定
while True:
ret,frame = cap.read()
img_dst = cv2.rectangle(frame, (x,y), (x+w, y+h), 255, 2)
cv2.imshow("SHOW MEANSHIFT IMAGE",img_dst)
roi = frame[y:y+h, x:x+w]
if cv2.waitKey(20)>0:
txt=yomikomi(roi)
break
追跡する物体が確定して、画像を取得したところでその画像を引数にしてyomikomi(img)に渡して物体識別をしてもらいます。その結果は、上記のように識別物体の名称str(results[0][1])として受け取ります。
こうして追跡している間中、名称を表示するようにしました。
2.fpsを計測して画像の左上に表示
fpsの計測は以下のとおりです。
curr_time = timer()
exec_time = curr_time - prev_time
prev_time = curr_time
accum_time = accum_time + exec_time
curr_fps = curr_fps + 1
if accum_time > 1:
accum_time = accum_time - 1
fps = "FPS: " + str(curr_fps)
curr_fps = 0
cv2.putText(img_dst, fps, (30,50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,0), 1)
最後の行で表示しています。表示文字の大きさは1としましたが、案外大きく表示されます。そして、物体識別したタグも同様に以下のように記載しました。
img_dst = cv2.rectangle(frame, (x,y), (x+w, y+h), 255, 2)
cv2.putText(img_dst, txt, (x+3,y+10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,0,0), 1)
上で物体を四角で囲み、二行目でその左上に表示するようにしています。ここでは文字サイズ0.5としました。
3.動画を保存する
これも以前やっていますが、img_dstを直接保存しようとしてもうまくいきません。
ということで当該部分を抜き出すと、以下のとおりでうまくいきます。
OUT_FILE_NAME = "meanshift_result.mp4"
FRAME_RATE=8
out = cv2.VideoWriter(OUT_FILE_NAME, \
cv_fourcc('M', 'P', '4', 'V'), \
FRAME_RATE, \
(w, h), \
True)
img_dst = cv2.resize(img_dst, (int(h), w))
out.write(img_dst)
ここで下から二番目の変換が重要なようです。これがないとうまく保存できません。
※元画像が大きすぎて保存できていない⇒(224,224)サイズに縮小でうまくいく
あとはおまじないの関数が必要です。
def cv_fourcc(c1, c2, c3, c4):
return (ord(c1) & 255) + ((ord(c2) & 255) << 8) + \
((ord(c3) & 255) << 16) + ((ord(c4) & 255) << 24)
まとめ
・opencv.meanshiftに物体識別を行って、物体検出しつつ物体追跡をできるようにした
・fpsは7-8fps程度あり、追加により劣化はしていない。
・動画保存の機能を追加した
・説明は省いたが、前回のものに比較すると、最初の物体選択の画面を追跡画面と共通になるように変更した。これにより、Webでも追跡が開始できるようにできる
・複数物体もやれそうだが、次回以降にする