前々回の記事からあまり差がないように見えるかもしれないが、。。。
すごくハマった。。。
ということで、ひとまずOpenCVのお勉強を前回して、特に画像保存。
どうにかそこをクリアしたので、ここにたどり着けました。
特に、以下の参考サイトの方ありがとうございます。
【参考】
OpenCVで動画をリアルタイムに変換してみる
今回のコード
SSD / testing_utils / videotest_alt.py
SSD / testing_utils / videotest_example_alt.py
※カメラ使える状態(カメラ付ノートなど)で、vid_test.run(0)を生かすとカメラ入力できます
結果
見た目あまり変わらないけど、とりあえず直接物体検出したものを保存できるようになりました♬
ということで、今回はとりあえず結果を先に持ってきました。
苦労したところ
なんとなく愚痴っぽいが誰か同じハマり方するかもなので記載する
今回、最大の危機は何度も言うけど画像保存かな??
カメラ付きのノートでやってみると、カメラはすぐ使えました。
そこで、画像保存。。。前回は持ってる動画の物体検出なのでスマホで撮影してアップできましたが、今回は、。。。
動機はともかく、単純に上記の参考のとおり画像保存すればよいと思ってやりましたが、ハマりました。。。
以下、ハマり具合を三段階に分けてご説明したいと思います。
Step1.単純に画像保存のコードを参考のとおり入れてみる
普通、これで動くよな~
でも、理由不明で動かない。。出来てしまえば(根本原因は不明かも)、
isColor=Falseが原因だ。。
Step2.グレー画像しか保存できないと思い、グレー化して保存してみる
そして、上記参考のとおり、グレー化して保存
できない。。。
はっきり言って、。。意味不明。。かなり混乱しました。
isColor=Falseが原因ではなかった。。
で、あまり意味はありませんが、もともとの動画rgbをグレー化して保存
videotest_alt.py
127 rgb = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB)
出来ました!(かなり当たり前なのだが。。上記だって出来て当たり前??)
Step3.コードを見直して、いろいろ試す
少なくとも、このコードが呪われているわけでもなさそうなので、いろいろ試してみます。
①isColor=Trueにしてカラーを保存できるようにして保存
できました!
②もう、#to_drawが悪さしているという仮説。。。
ちゃんとコードを読み切っていないが。。rgbが保存できてto_drawが保存できないので、そこしかないということで、すべて洗い出して、元々のrgbに置き換えてやってみました
できました!
どうにか無事に保存できるようになりました。
これでいいんじゃね??ちょっとアスペクト比が気に食わないが。。。
そして、実は入力画像サイズを非対称にすると、バグります。。。
(500,500,3)⇒OK
(480,360,3)⇒NG
。。。
てな具合です。もともと(300,300,3)だったはずなので、これでいいかな??
※大切なことは上記コードの意味やバグの本質をあまり理解していないということです。
102 # Compute aspect ratio of video
103 vidw = vid.get(cv2.CAP_PROP_FRAME_WIDTH)
104 vidh = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
105 vidar = vidw/vidh
132 to_draw = cv2.resize(resized, (int(self.input_shape[0]*vidar), self.input_shape[1]))
上記コードは単に入力画像のアスペクト比を割り戻して、1:1に規格化しているだけだよなぁ~
これが保存に影響するのかな??
実は、物体検出の四角の位置がずれているかもなぁ~
最後のあがき
ということで、
実は、上記の物体検出は四角の位置がずれている
そして、以下のコードがガンらしい
132 to_draw = cv2.resize(resized, (int(self.input_shape[0]*vidar), self.input_shape[1]))
上記を以下のとおり書き換えると、to_draw で無事に保存できる。
132 to_draw = cv2.resize(resized, (int(self.input_shape[0]*1), self.input_shape[1]))
そして、描画前拡大してアスペクト比を調整して表示すると、きちんと四角の位置は正しく表示している。
205 to_draw = cv2.resize(resized, (int(self.input_shape[0]*vidar), self.input_shape[1]))
しかし、このvidarのままだと保存ができないどころか、vidarは1以外の数字だと保存できない。。。理由は依然不明だが、。。。
ということで、保存するために
205 to_draw = cv2.resize(resized, (int(self.input_shape[0]*1), self.input_shape[1]))
としている。。。。
表示するときは、元画像のアスペクト比で戻してやればいいと思う。
そのコードは今回は未作成である。
これで、ステージクリアかな??
しかしながら、そんなに簡単ではなかった。。。
つまり、上記コードでも入力画像を(500,400,3)などとした場合、やはり以下のエラーが出る。
ValueError: Error when checking : expected input_1 to have shape (500, 400, 3) but got array with shape (400, 500, 3)
ここは解消しておきたい。
ということで、以下のように入力サイズを入れ替えてみた。
im_size = (self.input_shape[1], self.input_shape[0])
resized = cv2.resize(orig_image, im_size)
rgb = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB)
その結果、以下のコードの組み合わせでうまく入力画像にあったアスペクト比の物体検出後の動画出力ができた。しかも無事に保存もできた!
205 to_draw = cv2.resize(resized, (int(self.input_shape[0]*1), self.input_shape[1]))
【参考】
Python, OpenCVでBGRとRGBを変換するcvtColor
ということで、以下のようなアスペクト比の物体検出動画が保存できました。
今度こそステージクリアだ!
【追記2018/5/15】
Python, OpenCV, Pillow(PIL)で画像サイズ(幅、高さ)を取得によれば、やはりOpenCVでは、
「カラー画像の場合は行(高さ) x 列(幅) x 色(3)の三次元のndarrayとなる。shapeは(行(高さ), 列(幅), 色(3))のタプルとなる。」とのことです
以下は、(640,360,3)というちょっと極端な入力にしました。
以下は、(640,480,3):前回も書いたけど、ちょっと検出能力上がっている!
今回の最終版コード
SSD / testing_utils / videotest_alt2.py
SSD / testing_utils / videotest_example_alt2.py
まとめ
・カメラ入力で物体検出できた
(TVとかやったけどとりあえず著作権の壁、自分の顔は嫌だし、外景色もなあ~で掲載できず。。。)⇒次の目標ができました
・物体検出動画をいろいろなアスペクト比の入力動画に対して実施して保存できた
・しかし、cv2.resizeすると保存できない現象はまだ解消しておらず、一体どういう理由から来ているのかが不明
次回は、精度追求(含む他のモデル実装)、カテゴリを増やす、ラズパイ載せ替え(主にフィールドで遊びたい)等などなどへ挑戦したいと思います。