websocketでRaspberryPiからwindowsPCに画像を送る(Python)
Raspberypi3から webscketで画像をあげて、PC側で取得・表示までやります。
概要図↓
実行画面↓
開発環境
- win10 64bit
python3.5.2
openCV3.1.0
- Raspberrypi3
Raspbian Debian Stretch - Version:September 2017
python3.5.2
RaspberryPi側開発
構成
Raspberry Piのカメラモジュールで撮った映像をWebSocketでブラウザに送る!! - ami_GS's diary
ラズパイの方は、ほぼ上記参考HPのまま使っています。
今回は自分の環境でエラーが出たところを修正しました。
また、IP固定はあらかじめしておいてください。
ーーここ引用ーー
camera.py
RPi側でブラウザからのアクセスを受け付けるwebサーバ、及びカメラから映像を撮り、ブラウザへ送る。
index.html
WebSocketでブラウザに送られてきた画像を表示する。
ーーーーーーーー
インストール
pip3 install websocket pip3 install tornado
camera.py
import time import picamera import io import tornado import tornado.httpserver import tornado.websocket import tornado.ioloop import tornado.web import socket from threading import Thread WIDTH = 480 HEIGHT = 360 FPS = 30 class HttpHandler(tornado.web.RequestHandler): def initialize(self): pass def get(self): self.render("./index.html") #最初のHTTPアクセスを受け付け、WebSocket接続を確立させるスクリプトが入ったindex.htmlを返す class WSHandler(tornado.websocket.WebSocketHandler): def initialize(self, camera): self.camera = camera self.state = True def open(self): print(self.request.remote_ip, ": connection opened") t = Thread(target=self.loop) #撮影&送信スレッドの作成 t.setDaemon(True) t.start() def loop(self): stream = io.BytesIO() for foo in self.camera.capture_continuous(stream, "jpeg"): stream.seek(0) self.write_message(stream.read(), binary=True) stream.seek(0) stream.truncate() if not self.state: break def on_close(self): self.state = False #映像送信のループを終了させる self.close() #WebSocketセッションを閉じる print(self.request.remote_ip, ": connection closed") def piCamera(): camera = picamera.PiCamera() camera.resolution = (WIDTH, HEIGHT) camera.framerate = FPS camera.start_preview() time.sleep(2) #カメラ初期化 return camera def main(): camera = piCamera() print("complete initialization") app = tornado.web.Application([ (r"/", HttpHandler), #最初のアクセスを受け付けるHTTPハンドラ (r"/camera", WSHandler, dict(camera=camera)), #WebSocket接続を待ち受けるハンドラ ]) http_server = tornado.httpserver.HTTPServer(app) http_server.listen(8080) tornado.ioloop.IOLoop.instance().start() if __name__ == "__main__": main()
index.html
<html> <head> <title>livecamera</title> <img id="liveImg" src="" width="480" height="360"> <script type="text/javascript"> var img = document.getElementById("liveImg"); var arrayBuffer; //WebSocketでサーバに接続 var ws = new WebSocket("ws://192.168.1.201:8080/camera"); ws.binaryType = 'arraybuffer'; //受診するデータがバイナリであるので設定 ws.onopen = function(){console.log("connection was established");}; //接続が確立した時に呼ばれる ws.onmessage = function(evt){ arrayBuffer = evt.data; //受信したデータを復号しbase64でエンコード img.src = "data:image/jpeg;base64," + encode(new Uint8Array(arrayBuffer)); }; window.onbeforeunload = function(){ //ウィンドウ(タブ)を閉じたらサーバにセッションの終了を知らせる ws.close(1000); }; function encode (input) { var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; var output = ""; var chr1, chr2, chr3, enc1, enc2, enc3, enc4; var i = 0; while (i < input.length) { chr1 = input[i++]; chr2 = i < input.length ? input[i++] : Number.NaN; // Not sure if the index chr3 = i < input.length ? input[i++] : Number.NaN; // checks are needed here enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63; if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; } output += keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4); } return output; } </script> </head> </html>
*WebSocketでサーバに接続する部分のIPアドレスを自分のラズパイのIPに書き換えてください
起動
上の2つのプログラムを同じフォルダに置いて実行します。
python camera.py
ブラウザでwindowsPCからラズパイIPにアクセスするとリアルタイム画像が表示されます。
Windows側開発
構成
client.py
websocketのクライアント文とOpenCVでの画像表示になります。
インストール
pip3 install websocket-client
client.py
#-*- coding:utf-8 -*- from websocket import create_connection import sys import base64 from io import BytesIO import cv2 import numpy as np ws = create_connection("ws://192.168.1.201:8080/camera") # decode while True: arr = np.asarray(bytearray(ws.recv()), dtype=np.uint8) img = cv2.imdecode(arr, -1) # 'load it as it is' cv2.imshow('image', img) cv2.waitKey(10) cv2.destroyAllWindows() ws.close()
*create_connectionのアドレスをラズパイのアドレスに書き換えてください
起動
こっちを起動する前にラズパイの方を起動させておいてください。
ラズパイ起動確認後、以下で実行
python client.py
ウインドウが表示され、ラズパイが取得している画像が表示されます
初めてwebsocketやりました。
おわり
[参考]
Raspberry Piのカメラモジュールで撮った映像をWebSocketでブラウザに送る!! - ami_GS's diary
【技術】pythonでwebsocketを試してみた - エンジニアリングとお金の話
PicameraによるRaspberry Pi 3カメラモジュールのカメラ設定 | TomoSoft
Pythonの画像読み込み: PIL, OpenCV, scikit-image - Qiita
YoLo/darknet初期学習データで判別できる種類一覧
github等でYOLO、YOLOv2、darknetでよく用意されている学習データをそのまま適用したときに
判別できる種類の一覧は、以下の全80種類になります。
人 自転車 車 バイク 飛行機 バス 列車 トラック ボート 信号機 消火栓 一時停止標識 パーキングメーター ベンチ 鳥 ネコ 犬 馬 羊 牛 ゾウ くま シマウマ キリン バックパック 傘 ハンドバッグ ネクタイ スーツケース フリスビー スキー スノーボード スポーツボール 凧 野球用バット 野球グローブ スケートボード サーフボード テニスラケット ボトル ワイングラス カップ フォーク ナイフ スプーン ボウル バナナ 林檎 サンドイッチ オレンジ ブロッコリ にんじん ホットドッグ ピザ ドーナツ ケーキ 椅子 ソファー 鉢植え ベッド ダイニングテーブル トイレ テレビモニター ノートPC マウス リモコン キーボード 携帯電話 電子レンジ オーブン トースター シンク 冷蔵庫 本 時計 花瓶 はさみ テディベア ヘアドライヤー 歯ブラシ
元の英語では
person bicycle car motorbike aeroplane bus train truck boat traffic light fire hydrant stop sign parking meter bench bird cat dog horse sheep cow elephant bear zebra giraffe backpack umbrella handbag tie suitcase frisbee skis snowboard sports ball kite baseball bat baseball glove skateboard surfboard tennis racket bottle wine glass cup fork knife spoon bowl banana apple sandwich orange broccoli carrot hot dog pizza donut cake chair sofa pottedplant bed diningtable toilet tvmonitor laptop mouse remote keyboard cell phone microwave oven toaster sink refrigerator book clock vase scissors teddy bear hair drier toothbrush
BBoX-Label-ToolをPython3で使用する
BBoX-Label-Toolはpyhotn2.7で作成されているので3系では起動しません。
そこで今回はpython3系で起動できるようにします。
[環境]
win7 64bit
python3.5
[ソースダウンロード]
以下から本体をダウンロードします
github.com
[python3系に編集]
DL後、解凍。
main.pyを開きます。
10 from Tkinter import * 11 import tkMessageBox
の部分を削除して
try: import tkinter import tkinter.messagebox except: import Tkinter as tkinter import tkMessageBox from tkinter import *
に書き換え
あとはpython3用にprint文にカッコを追記して
python main.py
私の環境ではpythonで3系が起動します。
これで起動できたと思います。
ちなみに画像フォルダはimages/002とか作ってそこにいれても画像が読み込めない?事態がおきますので、
その場合は001に入っている初期画像を消して、自分の学習させたい画像を001に移動させます。
そしてBBoxを起動させてフォルダパスのところに"1"と数字のみ入れてloadすると読み込めるはずです。
おわり
Darknetをwindows10にインストールして物体認識・物体判別をする
今までChainerやTensorflowなどで記述された物体認識・物体判別をしてきましたが
今回はYoloV2の制作者がC言語製作したdarknetをwindowsPCにインストールして試してみました。
[環境]
windows7 64bit
python3.5.2
VisualStudio2015
OpenCV3.2
[OpenCVインストール]
OpenCV3.2をダウンロードします
*製作者はOpenCV3.0でやっていますがファイル関係のエラーでできなかったため3.2でやっています
OpenCV 3.2 - OpenCV library
ここの一番下の”Windows self-extracting archive:”からexeをダウンロードします
exeを実行し、C:\直下に定してインストール
環境設定に
[DarkerNetビルド]
https://github.com/AlexeyAB/darknet
ここにアクセスしてzipをダウンロード
ダウンロードしたファイルを解凍し、
次に”darknet.sln”を実行(VisualStudio2015)
VisualStudioが起動したら、
プラットフォームを”x64”に構成を”Release”に変更
ビルド→darknetのリビルドを実行
以下エラー除去
・include失敗、見つからない
プロジェクト→プロパティ→VC++ディレクトリ→インクルードディレクトリ右の▼→編集→C:\opencv\build\includeを追加
・opencv_world320.libが見つからない、参照できない
プロジェクト→プロパティ→VC++ディレクトリ→ライブラリディレクトリ右の▼→編集→C:\opencv\build\x64\vc14\libを追加
*1.CUDA8.0ではなくて他のバージョンをお持ちの場合は、メモ帳を使用してbuild\darknet\darknet.vcxprojを開き、
”CUDA 8.0”で2か所探して自分のCUDAバージョンに変更して、リビルドを実行してください。
*2.GPUがない人はbuild\darknet\darknet_no_gpu.slnで実行してください
*3.OpenCV2.4.13の人はパスを変更してください
・(right click on project) -> properties -> C/C++ -> General -> Additional Include Directories:
C:\opencv_2.4.13\opencv\build\include
・(right click on project) -> properties -> Linker -> General -> Additional Library Directories:
C:\opencv_2.4.13\opencv\build\x64\vc14\lib
*4.OpenCV2.4.**の人はさらにパス変更が必要なようです
\src\detector.c等を開き、”#pragma comment(lib, "opencv_core2413.lib"”などを変更
無事ビルドが終了したら”darknet-master\darknet-master\build\darknet\x64”にexeができています。
[DarkerNet実行]
コマンドプロンプトを起動して以下に移動
”darknet_voc.cmd”
以下エラー除去
・opencv_world320.libが見つからない、参照できない
C:\opencv\build\x64\vc14\bin\opencv_world320.dllをdarknet_voc.cmdを生成したexeと同じフォルダにコピー
・opencv_ffmpeg320_64.dllが見つからない、参照できない
C:\opencv\build\x64\vc14\bin\opencv_ffmpeg320_64.dllをdarknet_voc.cmdを生成したexeと同じフォルダにコピー
以下実行結果
\darknet-master\darknet-master\build\darknet\x64>darknet.exe detector test data/voc.data yolo-voc.cfg yolo-voc.weights -i 0 -thresh 0.2 layer filters size input output 0 conv 32 3 x 3 / 1 416 x 416 x 3 -> 416 x 416 x 32 1 max 2 x 2 / 2 416 x 416 x 32 -> 208 x 208 x 32 2 conv 64 3 x 3 / 1 208 x 208 x 32 -> 208 x 208 x 64 3 max 2 x 2 / 2 208 x 208 x 64 -> 104 x 104 x 64 4 conv 128 3 x 3 / 1 104 x 104 x 64 -> 104 x 104 x 128 5 conv 64 1 x 1 / 1 104 x 104 x 128 -> 104 x 104 x 64 6 conv 128 3 x 3 / 1 104 x 104 x 64 -> 104 x 104 x 128 7 max 2 x 2 / 2 104 x 104 x 128 -> 52 x 52 x 128 8 conv 256 3 x 3 / 1 52 x 52 x 128 -> 52 x 52 x 256 9 conv 128 1 x 1 / 1 52 x 52 x 256 -> 52 x 52 x 128 10 conv 256 3 x 3 / 1 52 x 52 x 128 -> 52 x 52 x 256 11 max 2 x 2 / 2 52 x 52 x 256 -> 26 x 26 x 256 12 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 13 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256 14 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 15 conv 256 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 256 16 conv 512 3 x 3 / 1 26 x 26 x 256 -> 26 x 26 x 512 17 max 2 x 2 / 2 26 x 26 x 512 -> 13 x 13 x 512 18 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024 19 conv 512 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 512 20 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024 21 conv 512 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 512 22 conv 1024 3 x 3 / 1 13 x 13 x 512 -> 13 x 13 x1024 23 conv 1024 3 x 3 / 1 13 x 13 x1024 -> 13 x 13 x1024 24 conv 1024 3 x 3 / 1 13 x 13 x1024 -> 13 x 13 x1024 25 route 16 26 conv 64 1 x 1 / 1 26 x 26 x 512 -> 26 x 26 x 64 27 reorg / 2 26 x 26 x 64 -> 13 x 13 x 256 28 route 27 24 29 conv 1024 3 x 3 / 1 13 x 13 x1280 -> 13 x 13 x1024 30 conv 125 1 x 1 / 1 13 x 13 x1024 -> 13 x 13 x 125 31 detection Loading weights from yolo-voc.weights...Done! Enter Image Path:
使用する画像を尋ねられるからサンプルに付属している画像のパスを入れる
Enter Image Path: ***\darknet-master\darknet-master\data\dog.jpg ***\darknet-master\darknet-master\data\dog.jpg: Predicted in 0.038000 seconds. car: 75% bicycle: 77% dog: 91% ^Cバッチ ジョブを終了しますか (Y/N)? y
Ctrl+Cを打ってyで終了する
実行結果↓
[参考HP]
「darknet」C言語で機械学習!とりあえずインストールとmake、エラーの対処をしてみた - lisz-works
DarknetをWindowsにインストールする - TadaoYamaokaの日記
YOLOv2を使って自前のデータを学習させて認識させるまで。 - 可変ブログ
OpenCV3.2インストール方法(ビルドなし) - Qiita
ChainerでYOLOv2をやってみる [訓練/学習編]
前回ChainerでYOLOv2をやったという記事にアクセスがまぁまぁあったので、
下書きのままだったYOLOv2の訓練/学習編を書いていきます。(メモ程度ですがご容赦ください)
YOLOv2の訓練手順(製作者様)↓
YOLOv2/YOLOv2_animal_train.md at master · leetenki/YOLOv2 · GitHub
[環境]
Ubuntu16.04
python3.5.2
*windows7 64bitでも可能だと思います
[インストール]
以下のものを入れてない人は入れてください
pip3 install mock
pip3 install cupy
[画像収集]
・backup
・sample_images
・items
・backgrounds
以上の4つのフォルダを新規作成してください。
次に画像を収集します
python download_images.py
itemsフォルダ内に画像がダウンロードされたか確認します。
[画像生成]
python image_generate.py
で画像がランダムに作られていきます。
ここでエラーが起こるので少し変更しました。
random_overlay_image関数の74,75行目の部分でエラーが起こります。
y = int(np.random.randint(src_h-scale_item_h)) - int(shift_item_h) x = int(np.random.randint(src_w-scale_item_w)) -int( shift_item_w)
変更した関数ごとを載せます。
def random_overlay_image(src_image, overlay_image, minimum_crop): src_h, src_w = src_image.shape[:2] overlay_h, overlay_w = overlay_image.shape[:2] shift_item_h, shift_item_w = overlay_h * (1-minimum_crop), overlay_w * (1-minimum_crop) scale_item_h, scale_item_w = overlay_h * (minimum_crop*2-1), overlay_w * (minimum_crop*2-1) a = src_h-scale_item_h b = src_w-scale_item_w if a <= 1: a = 100 if b <= 1: b = 100 c = int(np.random.randint(a) - shift_item_h) d = int(np.random.randint(b) - shift_item_w) if c < 0: c = int(np.random.randint(a)) if d < 0: d = int(np.random.randint(a)) y = (int(c)) x = (int(d)) image = overlay(src_image, overlay_image, x, y) bbox = ((np.maximum(x, 0), np.maximum(y, 0)), (np.minimum(x+overlay_w, src_w-1), np.minimum(y+overlay_h, src_h-1))) return image, bbox
はい、汚いですすみません。とにかくrandintにマイナスを入れないようにすればいいと思います。
今回は恐竜のほかにカービーを混ぜました。それに伴い、パラサウロロフスさんは消去しました。
追加したカービー↓
とてもかわいいですね。
もう一度image_generate.pyを実行して確認します。
[darknet19(画像識別器)の訓練・テスト]
今回カービーを追加したのでdata/label.tetラベルを書き換えます。
Tyrannosaurus Brachiosaurus Triceratops Riopururodon Rhino Dog Erasmosaurus Ammonite kirby Deer
*パラサウロロフスさんは消去しました。
*順番も順守
訓練
python darknet19_train.py
訓練終了後、テストします。
python darknet19_predict.py items/kirby.png
以下、結果です
[darknet19_448の訓練・重み切り出し]
訓練する
python darknet19_448_train.py
backupフォルダにdarknet19_448_final.modelが保存されたか確認
つぎに重み切り出し
python partial_weights.py
backupフォルダにpartial.modelが保存されたか確認
[YOLOv2の訓練・テスト]
python yolov2_train.py
ここで私のPCではメモリ不足になってしまったので
88行目のloss.backward()の下に
loss.unchain_backward()
を追加します。
*これでメモリが解放されますが学習にどう響くかは不明です。。。
ちなみに3日~1週間の間、学習処理をしました。
無事、訓練が終わったらテストです。
しかし、テストするまえに
yolov2_predict.pyの12行目を変更を出力したモデルの名前に書き換えます
12 weight_file = "./backup/yolov2_final_cpu.model" ↓ 12 weight_file = "./backup/yolov2_final.model"
認識テスト実行
python yolov2_predict.py test.jpg
テスト画像↓
結果
以上、終わりです。
[参考]
Chainer2.0がリリース【今後の安定版】とりあえず抑えておきたい変更点 - HELLO CYBERNETICS
chainer-object-detection/model/yolov2 at master · dsanno/chainer-object-detection · GitHub
tensorflowで物体認識(YOLOv2)をやってみる 2
前回、前々回でやっているtensorflowでYolov2なのですが、
参考にしているものがもう一つありましたので動作させるところまで書きます。
↓github↓
github.com
[環境]
win7 64bit
GTX 960
python3.5
tensolfolw 1.2.1
[動作手順]
1.先ほどのリンクに行きソースをDL、解凍
2.下のリンクをクリックしてDL。さきほど解凍したフォルダにbinという名前でフォルダを新規作成して入れる
https://pjreddie.com/media/files/yolo.weights
3.コマンドラインで先ほど解凍したフォルダに移動して
python setup.py build_ext --inplace
でインストール
4.githubのREADMEの”Using darkflow from another python application”に書かれているプログラムを参考に実行してみる
↓パスの部分を少し変えてます
[test.py] from darkflow.net.build import TFNet import cv2 options = {"model": "cfg/yolo.cfg", "load": "bin/yolo.weights", "threshold": 0.4, "gpu": 0.3} tfnet = TFNet(options) input_image = "sample_dog.jpg" image_folder = "sample_img" current_path = os.getcwd() current_path = os.path.join(current_path,image_folder) src = cv2.imread(os.path.join(current_path,input_image)) result = tfnet.return_predict(imgcv) print(result)
実行
python test.py
メモリエラーが出る場合は"options"で指定しているgpuの値をもっと引き下げてください
結果
[{'label': 'bicycle', 'confidence': 0.8448509, 'topleft': {'y': 114, 'x': 81}, ' bottomright': {'y': 466, 'x': 553}}, {'label': 'truck', 'confidence': 0.79510289 , 'topleft': {'y': 81, 'x': 462}, 'bottomright': {'y': 167, 'x': 693}}, {'label' : 'dog', 'confidence': 0.76959282, 'topleft': {'y': 214, 'x': 136}, 'bottomright ': {'y': 539, 'x': 322}}]
[画像表示]
結果は得られましたが、これでは見にくいので画像に結果を表示させようと思います。
返答値を分解すればいいんですが面倒になったので
今回は検出部に直接描画用コードを書いてしまいました。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
[2017/9/25]追記
YOLOv2のリアルタイム物体検出をTensorFlowとPythonで実装する方法 | AI coordinator
このブログの公開1日前にここのお方がメインで描画するソースを公開してくださいました。
動画での解析になっているので読み込みなどの部分を変える必要がありますが、、
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
以下、メインです。
[test.py] from darkflow.net.build import TFNet import cv2 import os import json options = {"model": "cfg/yolo.cfg", "load": "bin/yolo.weights", "threshold": 0.4, "gpu": 0.3} tfnet = TFNet(options) input_image = "sample_dog.jpg" image_folder = "sample_img" current_path = os.getcwd() output_file = "out" current_path = os.path.join(current_path,image_folder) output_path = os.path.join(current_path,output_file) if not os.path.exists(output_path): print('Creating output path {}'.format(output_path)) os.mkdir(output_path) src = cv2.imread(os.path.join(current_path,input_image)) dst = src cv2.imshow("img", src) result = tfnet.return_predict(src,dst) print(result) cv2.imshow("img_out", dst) cv2.waitKey() cv2.imwrite(output_path + '\\' + input_image, dst)
次にメイン文で呼んでる tfnet.return_predict()の中身を書き換えます。
場所は"darkflow-master\darkflow-master\darkflow\net\flow.py"です。
[flow.py] #importの追加 import cv2 import random import colorsys #メインで呼んでる関数の中身変更 def return_predict(self, im ,dst , output_image = True ):#引き数追加 assert isinstance(im, np.ndarray), \ 'Image is not a np.ndarray' h, w, _ = im.shape im = self.framework.resize_input(im) this_inp = np.expand_dims(im, 0) feed_dict = {self.inp : this_inp} out = self.sess.run(self.out, feed_dict)[0] boxes = self.framework.findboxes(out) threshold = self.FLAGS.threshold boxesInfo = list() #描画する色の指定 hsv_tuples = [(x / 80, 1., 1.) for x in range(80)] colors = list(map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples)) colors = list( map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)), colors)) random.seed(10101) # Fixed seed for consistent colors across runs. random.shuffle(colors) # Shuffle colors to decorrelate adjacent classes. random.seed(None) # Reset seed to default. i=0 for box in boxes: tmpBox = self.framework.process_box(box, h, w, threshold) if tmpBox is None: continue boxesInfo.append({ "label": tmpBox[4], "confidence": tmpBox[6], "topleft": { "x": tmpBox[0], "y": tmpBox[2]}, "bottomright": { "x": tmpBox[1], "y": tmpBox[3]} }) #描画 if output_image: cv2.rectangle(dst,(tmpBox[0], tmpBox[2]), (tmpBox[1], tmpBox[3]), colors[i], 2) fontType = cv2.FONT_HERSHEY_SIMPLEX cv2.putText(dst, tmpBox[4], (tmpBox[0], tmpBox[2] - 6),fontType , 0.6, colors[i],1,cv2.LINE_AA) cv2.putText(dst, str(tmpBox[6]), (tmpBox[0], tmpBox[2] + 15),fontType , 0.6, colors[i],1,cv2.LINE_AA) i+=1 return boxesInfo
実行
python test.py
結果
sample_computerの結果
sample_computerのprint文結果
[{'bottomright': {'x': 345, 'y': 280}, 'confidence': 0.87742555, 'topleft': {'x' : 157, 'y': 94}, 'label': 'tvmonitor'}, {'bottomright': {'x': 333, 'y': 371}, 'c onfidence': 0.79934323, 'topleft': {'x': 123, 'y': 263}, 'label': 'keyboard'}, { 'bottomright': {'x': 130, 'y': 351}, 'confidence': 0.48609883, 'topleft': {'x': 0, 'y': 20}, 'label': 'refrigerator'}]
関数の引き数ごと変えちゃったけどまぁいいか。。
[参考]
YOLOv2(TensorFlow)を使ってリアルタイムオブジェクト認識をしてみる - Qiita
おわり
tensorflowで物体認識(YOLOv2)をやってみる[動画解析編]
前回はYolov2の準備をして画像から物体認識をさせました。
今回は動画を読み込み物体認識をさせようと思います。
また、解析した動画は保存するようにしました。
[結果]
まずは結果から
↓切り抜き画像↓
[処理]
元のソースは画像系をPILで処理していました。
今回は動画読み込みや保存をOpencvで行いましたので、
Opencv -> PIL -> Yolov2 -> PIL -> Opencv
といった流れで処理させています。
[test_yolo_video.py] #! /usr/bin/env python # python test_yolo.py model_data/yolo.h5 """Run a YOLO_v2 style detection model on test images.""" import argparse import colorsys import imghdr import os import random import numpy as np from keras import backend as K from keras.models import load_model from PIL import Image, ImageDraw, ImageFont from yad2k.models.keras_yolo import yolo_eval, yolo_head import cv2 input_width, input_height = (416, 416) parser = argparse.ArgumentParser( description='Run a YOLO_v2 style detection model on test images..') parser.add_argument( 'model_path', help='path to h5 model file containing body' 'of a YOLO_v2 model') parser.add_argument( '-a', '--anchors_path', help='path to anchors file, defaults to yolo_anchors.txt', default='model_data/yolo_anchors.txt') parser.add_argument( '-c', '--classes_path', help='path to classes file, defaults to coco_classes.txt', default='model_data/coco_classes.txt') parser.add_argument( '-t', '--test_path', help='path to directory of test images, defaults to images/', default='images') parser.add_argument( '-o', '--output_path', help='path to output test images, defaults to images/out', default='images/out') parser.add_argument( '-s', '--score_threshold', type=float, help='threshold for bounding box scores, default .3', default=.3) parser.add_argument( '-iou', '--iou_threshold', type=float, help='threshold for non max suppression IOU, default .5', default=.5) def _main(args): model_path = os.path.expanduser(args.model_path) assert model_path.endswith('.h5'), 'Keras model must be a .h5 file.' anchors_path = os.path.expanduser(args.anchors_path) classes_path = os.path.expanduser(args.classes_path) test_path = os.path.expanduser(args.test_path) output_path = os.path.expanduser(args.output_path) sess = K.get_session() # TODO: Remove dependence on Tensorflow session. with open(classes_path) as f: class_names = f.readlines() class_names = [c.strip() for c in class_names] with open(anchors_path) as f: anchors = f.readline() anchors = [float(x) for x in anchors.split(',')] anchors = np.array(anchors).reshape(-1, 2) yolo_model = load_model(model_path) # Verify model, anchors, and classes are compatible num_classes = len(class_names) num_anchors = len(anchors) # TODO: Assumes dim ordering is channel last model_output_channels = yolo_model.layers[-1].output_shape[-1] assert model_output_channels == num_anchors * (num_classes + 5), \ 'Mismatch between model and given anchor and class sizes. ' \ 'Specify matching anchors and classes with --anchors_path and ' \ '--classes_path flags.' print('{} model, anchors, and classes loaded.'.format(model_path)) # Check if model is fully convolutional, assuming channel last order. model_image_size = yolo_model.layers[0].input_shape[1:3] is_fixed_size = model_image_size != (None, None) # Generate colors for drawing bounding boxes. hsv_tuples = [(x / len(class_names), 1., 1.) for x in range(len(class_names))] colors = list(map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples)) colors = list( map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)), colors)) random.seed(10101) # Fixed seed for consistent colors across runs. random.shuffle(colors) # Shuffle colors to decorrelate adjacent classes. random.seed(None) # Reset seed to default. # Generate output tensor targets for filtered bounding boxes. # TODO: Wrap these backend operations with Keras layers. yolo_outputs = yolo_head(yolo_model.output, anchors, len(class_names)) input_image_shape = K.placeholder(shape=(2, )) boxes, scores, classes = yolo_eval( yolo_outputs, input_image_shape, score_threshold=args.score_threshold, iou_threshold=args.iou_threshold) #video系準備 cap = cv2.VideoCapture("input.mp4") # Define the codec and create VideoWriter object fourcc = cv2.VideoWriter_fourcc(*'MJPG') ret, frame = cap.read() h, w, ch = frame.shape output_video = cv2.VideoWriter('output.avi',fourcc, 30.0, (w,h)) while(cap.isOpened()): # フレームを取得 ret, frame = cap.read() #BGRからRGBへ変換 cv_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) #PILに変換 src_image_pil=Image.fromarray(cv_rgb) pil_normalize = src_image_pil.convert('RGB') image = pil_normalize if is_fixed_size: # TODO: When resizing we can use minibatch input. resized_image = image.resize( tuple(reversed(model_image_size)), Image.BICUBIC) image_data = np.array(resized_image, dtype='float32') else: # Due to skip connection + max pooling in YOLO_v2, inputs must have # width and height as multiples of 32. new_image_size = (image.width - (image.width % 32), image.height - (image.height % 32)) resized_image = image.resize(new_image_size, Image.BICUBIC) image_data = np.array(resized_image, dtype='float32') # print(image_data.shape) image_data /= 255. image_data = np.expand_dims(image_data, 0) # Add batch dimension. out_boxes, out_scores, out_classes = sess.run( [boxes, scores, classes], feed_dict={ yolo_model.input: image_data, input_image_shape: [image.size[1], image.size[0]], K.learning_phase(): 0 }) #print('Found {} boxes for {}'.format(len(out_boxes), image_file)) font = ImageFont.truetype( font='font/FiraMono-Medium.otf', size=np.floor(3e-2 * image.size[1] + 0.5).astype('int32')) thickness = (image.size[0] + image.size[1]) // 300 for i, c in reversed(list(enumerate(out_classes))): predicted_class = class_names[c] box = out_boxes[i] score = out_scores[i] label = '{} {:.2f}'.format(predicted_class, score) draw = ImageDraw.Draw(image) label_size = draw.textsize(label, font) top, left, bottom, right = box top = max(0, np.floor(top + 0.5).astype('int32')) left = max(0, np.floor(left + 0.5).astype('int32')) bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32')) right = min(image.size[0], np.floor(right + 0.5).astype('int32')) #print(label, (left, top), (right, bottom)) if top - label_size[1] >= 0: text_origin = np.array([left, top - label_size[1]]) else: text_origin = np.array([left, top + 1]) # My kingdom for a good redistributable image drawing library. for i in range(thickness): draw.rectangle( [left + i, top + i, right - i, bottom - i], outline=colors[c]) draw.rectangle( [tuple(text_origin), tuple(text_origin + label_size)], fill=colors[c]) draw.text(text_origin, label, fill=(0, 0, 0), font=font) del draw #cvに変換して表示&保存 cv_output=np.asarray(image) cv_output = cv2.cvtColor(cv_output, cv2.COLOR_BGR2RGB) cv2.imshow("view", cv_output) output_video.write(cv_output) # qキーが押されたら途中終了 if cv2.waitKey(5) & 0xFF == ord('q'): break cap.release() output_video.release() cv2.destroyAllWindows() sess.close() if __name__ == '__main__': _main(parser.parse_args())
読み込む動画データをソース上に直接書いてしまっているのですが、
同じフォルダにinput.mp4を置いてください。
(あとでコマンドラインの引き数に書き直す予定です)
実行する
python test_yolo_video.py model_data/yolo.h5
おわり