こんにちは。インターン生のjuro, piyoです。
8月の頭から6週間、ソラコムのサマーインターンシップに参加させていただきました。
この記事ではインターンシップ中にやったことを紹介しつつ、ソラコムの雰囲気をお伝えできたらなと思っています。
初めに成果物を
制作経緯や内容等詳しくは後述しますが、簡潔に言うと僕達の制作物は「動画を要約するカメラ」です。
例えば、このような動画があった時に
以下のように一枚の画像に情報を圧縮することができます。
前半(テーマ決め)
そもそもソラコムのインターンはかなりプログラムの自由度が高く、取り組むプロジェクトや達成すべきノルマといったものが特に設定されていません。
そのため、はじめの一週間はインターンを通じて取り組むプロジェクトを決めることが目標でした。
ソラコム自体のサービスについて調べたり、ソラコムのデバイスやAWSのサービスを自分たちで組み合わせて簡単なデモを作ったりしていました。
またMaker Faire Tokyo 2019やHello SORACOMといったイベントに参加したりもしました。
簡単なデモやイベント、社員さんの説明などを通じて僕達が特に興味を持ったものが今年の7月にリリースされたばかりの”S+ Camera Basic”と呼ばれるデバイスでした。
S+ Camera Basicとは?
簡単に言うとプログラムで動作を制御できるカメラ。
S+ Camera Basicの中で動くプログラムはパソコンから遠隔から変更できるようになっていて、アルゴリズム(プログラム)は、SORACOM Inventory, SORACOM Harvest, SORACOM Napterといったソラコムのサービスの機能をSORACOM Mosaicが使ってカメラの中に搭載されているRaspberry Piに反映されます。
このプログラムをうまく書き換えると、写真を取る頻度を変化させたり撮った画像をカメラの内部で加工したり(要するにプログラム次第でなんでも)できます。
早速、S+ Camera Basicのサンプルプログラムをいただき、そのプログラムを解読する作業にはいりました。
その時点でできていたサンプルプログラムは「画像を5分ごとにクラウド上にアップロードする」というもので、監視カメラのような用途を想定していた僕達は「もっと細かい間隔、それこそ動画のようなものを送れないのか」と思いました。
これができないのは、単純に通信量が膨大になるからです。
監視カメラのような用途でS+ Camera Basicを用いる際、細かい間隔で画像をアップロードすることになり、これは通信量の面でも画像を大量に見なければならないという手間の面でも”イマイチ”です。
そこで僕達は今回のインターンのテーマを、S+ Camera Basicをもっと手軽に扱えるような「要約画像取得プログラム」(以下“S++ Summary”)の開発に決めました。
「要約画像」とは一定時間(一時間とか一日とか)単位に起きたことを一枚の画像にまとめたものです。
撮った画像をカメラからクラウド上に送る時には通信料がかかってしまいますが、S++ Summaryを使うことでアップロードする画像の枚数を減らして通信料を削減でき、視覚的にも大量に送られてきた画像を順番に見ていくよりはずっとわかりやすくなります。
インターン生のtakuyaがS+ Camera Basicに遠隔首振り機能(S++ Swing)をつけるとのことだったので、S++ Summaryと合わせてこれら二つの開発をS+ Camera Basicの拡張パッケージ開発:“S++ Project”として三人で進めていくことになりました。*1
前半(設計・中間発表)
まず開発するにあたって、S++ Summaryにどのような機能を持たせるかについて話し合いました。
これは、「動画を要約する」とはそもそも何を指しているのかという話です。
話し合いの結果、最終的に僕達は「動画内での代表的な動きを捉えること」を「要約」と定義し、さらに細かく言えば、
・代表物
・その代表物の動き(動線)等の情報
を画像に上手にのせることを”S++ Summary”としました。
そして、それに向けた全体の関数の流れ、必要な関数と必要な変数など、S++ Summaryを開発するにあたっての大まかな設計を二人でしました。
もちろんこれらの設計には後に細かく修正が入ったのですが、動作の大まかな挙動を共有する意味で役立ちました。
(例えば、代表物を要約画像に貼るのにも 物体検出→代表物として使うのかの判定→いくつもの代表物を画像内に適切に配置 などステップは何段階にも渡ります)
このとき中間発表会と後半戦に作るサービスのプレスリリース*2を控えていたので、そちらも同時に進めていました。
中間発表とプレスリリースを無事終えた後、頂いたフィードバックで若干の軌道修正を加え、後半戦に向かいました。
後半(開発)
いよいよ後半、開発です( ✌︎’ω’)✌︎ ✌︎(‘ω’✌︎ )
ここでは実装の細かい説明というよりはS++ Summaryを開発する上で判明した問題点のいくつかとそれの解決に向けての提案手法を書いていこうと思います。(技術的な内容が急に増えます!)
問題1 Raspberry Piの性能による問題
後半戦を開始した当初は取得した画像に対して物体検出を行い、前フレームとの同一物の判定・記録をし、定められた時間内全ての画像に対する解析を終えた後に、代表物の決定や動線の描画等を行う予定でした。
しかし、S+ Camera Basicはラズパイ*3をベースとしているため、メモリが少ない・CPU性能が低いといった制限があります。そのため、画像をためこんだ後にためこまれた画像全てに対して物体検出を行い物体の動きを解析する手法を用いることはできません。(´;ω;`)
この問題を解決する手法として、MobileNet-SSDのような処理の軽いモデルを使用して物体検出を行う方法と、画像に対して直接物体検出を行うことは避けてKNNによって背景を推定し推定された背景と画像との差分を取って動体を検出する方法の二つが提案されました。
今回のインターンシップでは精度や処理時間のことを考慮した結果後者の方法を採用しました。また、メモリを節約するために、処理を行う上で常に直前とフレームと現在のフレームからの情報以外を持ち続けない(2フレーム以上前の情報は捨てる)ようにプログラムを設計し直しました。
問題2 フレーム間の時間差の制約
物体の動きをカメラの画像から捉えるためには、直前のフレームと現在のフレームに映る物体に対して「同一の物体か」を判定することが必要です。
当初はこの判定は、直前のフレーム及び現在のフレームで検出された物体の特徴点を抽出し物体間の距離がある程度近いもののうち特徴点の類似度が高いかどうかで同一物体を判定する予定でした。この手法は、検出物が隣り合うフレームで大きくは動かない(瞬間移動/ワープしない・大きく変化しない)ことが必要で、このためにはフレーム間の時間間隔が短くなくてはなりません。*4
しかしながら、問題1で述べたような手法をとっても、1画像(720p)あたりの処理には700ms程度はかかってしまいフレーム間の処理が充分短いとは言えません。
そのため、特徴点の距離・類似度から貪欲に同一物を判定することができません。
そこで、僕達は直前のフレームと現在のフレームの物体間に、距離・輪郭の大きさ・輪郭の形状差から算出した重み付きの辺を適宜枝切りしながら貼ったグラフを構築しました。
そして、そのグラフに対して重み付き最大二部マッチングを行うことで適切に同一物体のペアを選択するようにしました。
こうすることで、特徴点の変化量が大きくても、あくまで要約画像全体として動線がうまく成立するようにマッチングが行われます。
後半(手元PC上での実験)
上では開発時に起きた問題のいくつかを取り上げましたが、実際の開発はまずiPadで撮った動画に対してノートPC上で動作するものを作りました(* ‘꒳ ‘* )
ただしノートPCとラズパイとではスペックが大きく違うので、「取得した画像のうちの97%を使用せずに破棄する」というウェイトを持たせてRaspberry Pi同等の性能で開発できるように工夫しました。
この手法は単純ですが実機にデプロイする前にノートPCで動作検証できるので、有効な手法でした。
ノートPCで開発する際はとりあえず大枠の試作版を作り、その上で徐々に改善*5していくといった方法をとりました。
ここでは、そこでの途中経過のようなものを簡単にまとめていこうと思います。
(以下の画像のモザイクはあとで編集して加えたものです。また、時間表示・フレーム表示はデバッグ用のものです)
↑この時点で僕達が当初作りたかったものが一旦完成したのですが、これを見てどうですか?
僕達は「なんか見にくい(๑-﹏-๑)…思ってたのと違う(・^・╬︎)…」って思いました。
写真では背景にも様々な色があるため単純に見にくいです。
また線が密集していて「誰がどの動線か」ということが非常に分かりづらいです。
これは広角レンズを装着したり、俯瞰からの写真になるよう設置場所を工夫し、密度を小さくすることでも改善できると思いますが、僕達はアルゴリズム面でもっと見やすくなるよう試行錯誤をはじめました。
はじめに想定していた要約画像(ver.11)を作って見たら案外見づらかったので、二人でどんどん修正していき、要約画像が色々な状況に対応できるようになりかつ視覚的に分かりやすくなっていくのはやっていて楽しかったです。
実際に運用する際にはS+ Camera Basicの強みを生かして、動線や検出などの閾値・比重をユーザーコンソール上で変更することができ、取り付ける場所によって後からチューニングすることが可能となっています。
後半(実機テスト・最終発表)
ようやく実機テストです イェイL(‘ω’)┘三└(‘ω’)」イェイ
PC上で満足のいく挙動をするコードが書けていたので、あとは実機にデプロイするだけで楽に終わるかと思っていたのですがそんなに甘くはありませんでした。
まずバグが出るのは当たり前として、実機になるとその原因究明の難易度が跳ね上がります。
PC上での実験では環境さえ整えてしまえばバグはアルゴリズム面のものがほとんどだったのですが、実機になるとそれに加えてハード面や通信面など様々な可能性がでてきます。
そうなると、一つのバグに対しての対応にかなり時間を取られてしまったり、コードだけを変えて改善するということがしづらくなってしまいます。
なので、これは反省なのですが、実機にデプロイする前にコードをしっかりと整理するべきでした。
実機テストに移った後にコードを書き換えるのはどうしても難しく、「とりあえず動きはするものの、もっと綺麗にしたい…」といったコードのまま整理できずに終わってしまいました。
そういった反省点もあるのですが、ここでは上と同じように実機テストがうまくいくまでの過程をまとめていこうと思います。
動作自体はPC上での実験通りにしっかり動いているはずなのだけれど何かうまくいかない…ということが最終週になっても続いていました。
結論として、ノートpc上でのテストではiPadで撮ったビデオを使用したため画像に対してiPad側で自動で補正が行われていて、そのお陰でうまくいっていたことが判明しました。
ここでいう「補正」とは、明るさや色温度の調整はもちろん動体に対してピントを合わせたり露出度を補正したりといったこと指しています。
時間の制約上これらを自分たちで実装するのは難しかったので、僕たちは撮った画像に対して線形変換やγ変換、画像色補正を施してコントラストを調整し、背景取得の方法をKNNから混合ガウス分布による手法に切り替えることで動体がうまく検出されるようにしました。
また、ピントが合わず代表物の境界がぼけてしまうので、代表物の表示は矩形で囲うようにしました。
実際に設置してみて「思ったより画像が暗い…(๑•́ ω •̀๑)」などがあった際に、現地に赴かなくてもアルゴリズムを変更できるのはS+の大きな強みです。
そして、、、
無事、成功しました!本当にインターン6週間の最後の最後になんとか動いたので、実際には\\\└ (‘ ω ‘) 」////ウオオオオオオオオオオオオオオオ!!!!!!!!!!!!というより安堵の方が大きかったです。
こうしてあっという間だった6週間のインターンを終えました。
メンターの方をはじめとして社員の皆さんが僕達をものすごく支えたり盛り上げたりしてくださったお陰で、刺激的で最高なインターンシップになりました。
本当にありがとうございました。
おまけ
せっかくなので、ソラコムの雰囲気やインターンの生活を知ってもらえたらいいなというコーナーです。
開発スペースはインターン生だけが隔離されているわけではなく、社員さんが働いているオフィスの中にインターン生用のスペースが確保されていました。
お昼の時間などは決まっているわけではなくて、誘われたタイミングでついていく感じでした。
ブログのはじめの方でソラコムのインターンは自由度が高いと書きましたがこれ取り組む内容に関しての話で、インターン期間中はガチプロ社員さんとの距離感がとても近く、定期的にメンターの方と進捗を共有して進め方を相談したり、疑問点や問題点をSlackやScrapboxに書いておくと鋭いツッコミがすぐに入ったりといったサポートがたくさんありました。
その上、モニターや椅子の質、飲み物完備等の物理面での環境も最高でとても恵まれた環境でした。
これは余談なのですが、ソラコムは個人の判断でリモートワークが許可されていて、満員電車や天候の影響を受けずに快適に仕事ができるようになっています。メンターの方の中にもリモートの方がいたのですが、Slack や Scrapbox を使ってスムーズに情報共有ができてとても便利でした。
また、隔週金曜日の進捗報告会 “Happy Hour” や社員さんと交流を深めるためのピザ会などを通して、様々な業務に携わっている社員さんから業務の内容から雑談までいろいろな話をしていただきとても勉強になりました。
Ishigakiという名前の畳の部屋があって結構好きでした。S++ Summaryの設計もS++ Swingの予算案もここで話し合いました。
他にもいろいろなタイプの会議スペースがあって常に新鮮な気持ちで会議ができるようになっていました。(それぞれの会議スペースは別々のトライアスロンの開催地をテーマとして設計されてるらしいです。)
オニク、オイシイ
オニク、オイシイ