以前、keras-yolo3を使用して画像と動画から物体検出を行う方法を書きました。
keras-yolo3を利用すると画像から物体を検出して、検出した物体のクラス名と
確率を画像に出力してくれます。
Photo by rawpixel.com from Pexels
検出した物体を切り抜きたいときは、物体の座標、幅、高さが必要になります。
keras-yolo3を利用して物体の種類、左上の座標、幅、高さを求められるようにしてみます。
動作環境
- Windows10
- Python3.7.9
- パッケージ管理にPipenvを使用
object-detection-keras-yolo3の利用方法
keras-yolo3のコードを利用して物体の種類、左上の座標、幅、高さを画像から検出する
Pythonスクリプトを作成しました。
keras-yolo3のweight変換方法を踏襲しているので、検出できる物体は80種類です。
検出できる物体はこちらを参照してください。
インストール方法
object-detection-keras-yolo3のダウンロード
gitでcloneをする場合は以下を入力してください。
1 |
git clone https://github.com/kazusapg/object-detection-keras-yolo3.git |
またはgithubのページ右側の緑色のclone or downloadをクリック後
Download ZIPを選択し、ファイルをダウンロードしてから解凍してください。
Pipenvを利用したインストール
Pipenvで仮想環境を作成する場合はコマンドプロンプトまたはPowerShellで
object-detection-keras-yolo3フォルダに移動後、pipenv installを入力します。
必要なパッケージをインストールした後に、pipenv shellで仮想環境に入ります。
1 2 3 |
cd object-detection-keras-yolo3 pipenv install pipenv shell |
YOLOv3 weightsの変換
YOLO: Real-Time Object DetectionからYOLOv3 weightsをダウンロードします。
weightsファイルはページ内のhere(237MB)をクリックするとダウンロードできます。
You already have the config file for YOLO in the cfg/ subdirectory. You will have to download the pre-trained weight file here (237 MB).
ダウンロードしたweightsファイルをobject-detection-keras-yolo3フォルダに移動し、
下記のコマンドを入力してweightsファイルをkerasで利用できる形に変換します。
1 |
python keras_yolo3/convert.py keras_yolo3/yolov3.cfg yolov3.weights model_data/yolo.h5 |
使用方法
- keras.yolo3からYOLOクラスをインポートします。
- objectsからget_objects_informationをインポートします。
- YOLOクラスのインスタンスを作成します。
- YOLOインスタンスと画像のファイルパスを引数としてget_objects_information関数を
呼び出します。 - get_objects_information関数は、検出した物体ごとにdictionaryを生成し、
生成したdictionaryをListに加えて返します。物体が検出できないときは空のListを返します。
get_objects_information関数内で生成されるdictionaryは
下記のキーを参照することで、それぞれの物体の情報を取得できます。
- predicted_name 検出した物体のクラス名(人、自転車、車など)
- x 検出した物体の左上座標のx位置
- y 検出した物体の左上座標のy位置
- width 検出した物体の幅
- height 検出した物体の高さ
使用例
下記の画像から物体の情報を取得してみます。
Photo by rawpixel.com from Pexels
コードは以下になります。
画像はsample_picture.jpgという名前でpictureフォルダに保存されているとします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
from PIL import Image from keras_yolo3.yolo import YOLO from objects import get_objects_information if __name__ == '__main__': yolo = YOLO() image_path = "./picture/sample_picture.jpg" objects_info_list = get_objects_information(yolo, image_path) yolo.close_session() img = Image.open(image_path) count = 0 for object_info in objects_info_list: class_name = object_info['predicted_name'] x = object_info['x'] y = object_info['y'] width = object_info['width'] height = object_info['height'] cropped_img = img.crop((x, y, x + width, y + height)) cropped_img.save("./picture/{}{}.jpg".format(class_name, count)) count = count + 1 |
画像内に人が2人写っているので、get_objects_information関数から
2つのdictionaryを含んだ状態でListが返ってきます。
1 2 3 4 |
[{'x': 102.010155, 'y': 395.04367, 'width': 530.84344, 'height': 500.70053, 'predicted_name': 'person'}, {'x': 700.43365, 'y': 400.91656, 'width': 433.38104, 'height': 494.5551, 'predicted_name': 'person'}] |
List内のそれぞれのdictionaryを利用して、Pillowで保存した画像は下記の2つになります。
コメント
オリジナルの学習データで切り抜きしようとしていますが、エラーが出ます。
オリジナルの学習はこちらを参考に実施しました。
https://sleepless-se.net/2019/06/21/how-to-train-keras%e2%88%92yolo3/
【やったこと】
・model_dataにオリジナルで作成した重みを入れた。
・『coco_classes.txt』内のクラス名をオリジナルと同じにした(6クラス)
・yolo.py の”model_image_size”をオリジナル学習時と合わせた(320,320)
【エラー内容】
ValueError: Dimension 0 in both shapes must be equal, but are 1 and 255. Shapes are [1,1,1024,33] and [255,1024,1,1]. for ‘Assign_360’ (op: ‘Assign’) with input shapes: [1,1,1024,33], [255,1024,1,1].
対応方法をご存じでしたらご教示頂けないでしょうか。
よろしくお願いいたします。
すみません。自己解決しました。
model_dataにオリジナルで作成(学習)した重みを入れてませんでした。
学習後のものを入れると正常に動きました。
お忙しいところ失礼します。
当記事からkeras-yolo面白く感じ始めてみたのですが、逆に画像であれば認識してる物体の領域の座標をテキストファイル等で出力。
動画であれば認識した物体の領域を座標、秒数で出力することは可能なのでしょうか?
分かりにくい文で申し訳ないのです、もしよろしければ返事をいただけると幸いです。
りたさん
コメントありがとうございます。
当記事内で紹介しているobject-detection-keras-yolo3ですが
画像の座標しか検出できないので、オリジナルのkeras-yolo3を修正したほうが
簡単です。
keras-yolo3は動画と画像で物体検出ができるので、動画または画像の読み込み時に
処理を振り分けてもらうのが良いと思います。
座標を取得するためにyolo.py内のdetect_imageメソッドを変更する必要があります。
返信ありがとうございます。
初心者ながら変更を行ってみたのですがうまくいかない状況です。
大変申し訳ないのですが、参考になるコードを教えていただけないでしょうか?
object-detection-keras-yolo3内のyolo.pyのdetect_imageメソッドで
検出した物体の左上の座標、幅、高さ、検出した物体のクラス名をまとめた
dictをlistに詰めて返すようにしています。
現在は画像内の物体しか検出できていませんが、こちらのコードを再利用してもらうと
動画内の物体の座標も取得できると思いますので参考にしてみてください。