JUGEMテーマ:趣味
JUGEMテーマ:電子工作
画像認識して画像に映っている物体の数をリアルタイムに数える
Webカメラの画像からリアルタイムにその場にいる人の数を数えるとか、
熊を検出するとか、鹿を検出するとかそう言った事が最近は出来るらしいです。
かなり進歩したもんですね。
技術的な要素としてはyoloとかOpenCVとかを使うと良いとの事で、
色々な所にハマりながらたどり着いたのがこちら。
https://cpp-learning.com/chainercv_yolo/
とっても素敵なページです。こういった事を惜しげもなく公開しているオーナーさんには感謝です。
今ページの記事は基本的に上記ページの再現になります。
上記ページによりますと、chainerからyoloが使用可能で、以下の機能分担になります。
openCV : ビデオ入力
ChainerCV : yoloを使用して画像認識
openCV : 結果を画面出力
以下、環境構築から実際に物体を認識するまでの記録(自分用メモ)として残したいと思います。
■chainerの環境構築
※参考サイト
https://cpp-learning.com/anaconda_windows_chainer/
手順は以下の通り
・Anacondaインストール
・Visual C++ Build Toolsインストール
・Chainerインストール
※「Visual C++ Build Tools」についてはChainerをインストールするのに必要との事。
・Anacondaインストール
ダウンロード
https://www.anaconda.com/download/#windows
ここから WindowsのPython3.7のをダウンロードして
画面の指示に従ってデフォルトでインストールする。
・Visual C++ Build Toolsインストール
ダウンロード
https://www.visualstudio.com/ja/downloads
ここの下のほうから「Tools for Visual Studio 2017」をダウンロードして
画面の指示に従ってデフォルトでインストールする。
・Chainerインストール
anacondaの仮想環境を一つ追加してそこにChainerをインストールしていきます。
スタートメニューからAnaconda→「anaconda prompt」を起動して以下のコマンドを投入していきます。
conda create -n chainer Anaconda
activate chainer
pip install chainer
pip install chainercv
pip install opencv-python
■カメラ画像を画面にリアルタイム表示
ここでは画像の解析の前にカメラでから入力した画像をほぼそのまま画面に表示するプログラムになります。
WindowsなのでLogicoolのWEBカメラをUSB接続してそのまま画面出力するサンプルです。
画面の上部に現在のフレーム数とFPSを表示していますが、私に環境では30FPSで処理できているようです。
※参考サイト
https://cpp-learning.com/python_opencv_video/
・ソース そのままパクっております。自分メモのため・・・汗;;;
Test_Cam.py
import argparse
import cv2
from timeit import default_timer as timer
def main():
parser = argparse.ArgumentParser()
parser.add_argument('video')
args = parser.parse_args()
if args.video == "0":
vid = cv2.VideoCapture(0)
else:
vid = cv2.VideoCapture(args.video)
if not vid.isOpened():
raise ImportError("Couldn't open video file or webcam.")
# Compute aspect ratio of video
vidw = vid.get(cv2.CAP_PROP_FRAME_WIDTH)
vidh = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
vidar = vidw / vidh
print(vidw)
print(vidh)
accum_time = 0
curr_fps = 0
fps = "FPS: ??"
prev_time = timer()
frame_count = 1
while True:
ret, frame = vid.read()
if ret == False:
print("Done!")
return
# Resized
im_size = (300, 300)
resized = cv2.resize(frame, im_size)
# =================================
# Image Preprocessing
# =================================
# =================================
# Main Processing
result = resized.copy() # dummy
# result = frame.copy() # no resize
# =================================
# Calculate 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
# Draw FPS in top right corner
cv2.rectangle(result, (250, 0), (300, 17), (0, 0, 0), -1)
cv2.putText(result, fps, (255, 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.35, (255, 255, 255), 1)
# Draw Frame Number
cv2.rectangle(result, (0, 0), (50, 17), (0, 0, 0), -1)
cv2.putText(result, str(frame_count), (0, 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.35, (255, 255, 255), 1)
# Output Result
cv2.imshow("Result", result)
# Stop Processing
if cv2.waitKey(1) & 0xFF == ord('q'):
break
frame_count += 1
if __name__ == '__main__':
main()
■カメラ画像表示の動作確認
動作確認
WEBカメラからの画像の場合はパラメーターに0を指定
python Test_Cam.py 0
動画ファイルを指定する場合はパラメーターに動画ファイル名を指定
python Test_Cam.py 動画ファイル名
■画像認識
後からわかったんですがyoloのVersion3の場合で最初から学習済みの物体は以下の20種類の様です。
つまりこれ以外はちゃんと認識されません。
aeroplane
bicycle
bird
boat
bottle
bus
car
cat
chair
cow
diningtable
dog
horse
motorbike
person
pottedplant
sheep
sofa
train
tvmonitor
とりあえずは人を認識できれば今のところはそれで良いかなーとは思います。
もっと認識を増やしたい場合は学習させればよいという事ですよね。
■ソース
※参考サイト
https://cpp-learning.com/chainercv_yolo/
・ソース ほぼそのままパクっております。自分メモのため・・・汗;;;
Yolo_Chainer_Video.py
import time
import argparse
import matplotlib.pyplot as plt
import cv2
import numpy as np
from timeit import default_timer as timer
import chainer
from chainercv.datasets import voc_bbox_label_names, voc_semantic_segmentation_label_colors
from chainercv.links import YOLOv2
from chainercv.links import YOLOv3
from chainercv import utils
from chainercv.visualizations import vis_bbox
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
'--model', choices=('yolo_v2', 'yolo_v3'),
default='yolo_v3')
parser.add_argument('--gpu', type=int, default=-1)
parser.add_argument('--pretrained-model', default='voc0712')
parser.add_argument('video')
args = parser.parse_args()
if args.model == 'yolo_v2':
model = YOLOv2(
n_fg_class=len(voc_bbox_label_names),
pretrained_model=args.pretrained_model)
elif args.model == 'yolo_v3':
model = YOLOv3(
n_fg_class=len(voc_bbox_label_names),
pretrained_model=args.pretrained_model)
for name in voc_bbox_label_names:
print(name)
if args.gpu >= 0:
chainer.cuda.get_device_from_id(args.gpu).use()
model.to_gpu()
if args.video == "0":
vid = cv2.VideoCapture(0)
else:
vid = cv2.VideoCapture(args.video)
if not vid.isOpened():
raise ImportError("Couldn't open video file or webcam.")
# Compute aspect ratio of video
vidw = vid.get(cv2.CAP_PROP_FRAME_WIDTH)
vidh = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
# vidar = vidw / vidh
print(vidw)
print(vidh)
accum_time = 0
curr_fps = 0
fps = "FPS: ??"
prev_time = timer()
frame_count = 1
while True:
ret, frame = vid.read()
if ret == False:
time.sleep(5)
print("Done!")
return
# BGR -> RGB
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Result image
result = frame.copy()
# (H, W, C) -> (C, H, W)
img = np.asarray(rgb, dtype = np.float32).transpose((2, 0, 1))
# Object Detection
bboxes, labels, scores = model.predict([img])
bbox, label, score = bboxes[0], labels[0], scores[0]
print("----------")
nPerson = 0
nBottle = 0
if len(bbox) != 0:
for i, bb in enumerate(bbox):
# print(i)
lb = label[i]
conf = score[i].tolist()
ymin = int(bb[0])
xmin = int(bb[1])
ymax = int(bb[2])
xmax = int(bb[3])
class_num = int(lb)
# Draw box 1
cv2.rectangle(result, (xmin, ymin), (xmax, ymax),
voc_semantic_segmentation_label_colors[class_num], 2)
# Draw box 2
# cv2.rectangle(result, (xmin, ymin), (xmax, ymax), (0,255,0), 2)
text = voc_bbox_label_names[class_num] + " " + ('%.2f' % conf)
print(text)
if(voc_bbox_label_names[class_num] == 'person'):
nPerson = nPerson + 1
if(voc_bbox_label_names[class_num] == 'bottle'):
nBottle = nBottle + 1
text_top = (xmin, ymin - 10)
text_bot = (xmin + 80, ymin + 5)
text_pos = (xmin + 5, ymin)
# Draw label 1
cv2.rectangle(result, text_top, text_bot,
voc_semantic_segmentation_label_colors[class_num], -1)
cv2.putText(result, text, text_pos,
cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 0), 1)
# Draw label 2
# cv2.rectangle(result, text_top, text_bot, (255,255,255), -1)
# cv2.putText(result, text, text_pos,
# cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 0), 1)
print("==========")
print("Number of people : " + str(nPerson))
print("Number of bottle : " + str(nBottle))
# Calculate 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
# Draw FPS in top right corner
cv2.rectangle(result, (590, 0), (640, 17), (0, 0, 0), -1)
cv2.putText(result, fps, (595, 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.35, (255, 255, 255), 1)
# Draw Frame Number
cv2.rectangle(result, (0, 0), (50, 17), (0, 0, 0), -1)
cv2.putText(result, str(frame_count), (0, 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.35, (255, 255, 255), 1)
# Output Result
cv2.imshow("Yolo Result", result)
# Stop Processing
if cv2.waitKey(1) & 0xFF == ord('q'):
break
frame_count += 1
if __name__ == '__main__':
main()
■解説
・OpenCVでカメラ画像を取得→frame
・frameの中身はBGRで入っているそうなので、Chainerで扱えるRGBに変換→rgb
・画像サイズとチャンネルの順番がOpenCV(H, W, C)とChainer(C, H, W)で異なる事と
Chainerではnumpy配列のfloat32しか扱えないのでChainerで扱えるように変換→img
・結果出力ではOpenCVを使うのでframeをコピーしておく→result
・imgに対し物体検出(Yolo)を実施し、boxとlabelの算出結果を取得
・boxとlabelの結果をresultに描画して映像出力
■画像認識動作確認
動作確認
WEBカメラからの画像の場合はパラメーターに0を指定
python Yolo_Chainer_Video.py 0
動画ファイルを指定する場合はパラメーターに動画ファイル名を指定
python Yolo_Chainer_Video.py 動画ファイル名
より細かい指定をしたい場合はyoloのバージョン、GPU指定、学習モデルなどの指定が可能
python Yolo_Chainer_Video.py --model yolo_v3 --gpu 0 --pretrained-model voc0712 0
--model yoloのバージョン指定 YoloV3 または YoloV2
--gpu プロセッサ設定 CPUなら-1 GPUなら0
--pretrained-model 学習モデル指定 voc0712など
最後の数字 WEBカメラは0、動画ならファイル名
・性能について
私の環境はCPU:Codei5-8400、2.8GHz RAM:32GByte、gpu無しなのですが
1FPSの速度です。CPU使用率は100%に張り付きます。
・認識精度について
私の手はcatとかdogとか間違われてしまったりしましたが、
全体であれば私をpersonと認識してくれました。むしろ部分でもpersonなのね。という感じです。
牛とか車とか学習済みのものは正確に認識してくれます。
熊の写真とかであれば同じ動物の仲間のdogとかcow等と認識しておりまずまずの結果かと思います。