投稿日

ソラコム サマーインターン参加記2019 〜動画を要約するエッジ処理カメラをつくる〜

こんにちは。インターン生のjuro, piyoです。
8月の頭から6週間、ソラコムのサマーインターンシップに参加させていただきました。

この記事ではインターンシップ中にやったことを紹介しつつ、ソラコムの雰囲気をお伝えできたらなと思っています。  

初めに成果物を

制作経緯や内容等詳しくは後述しますが、簡潔に言うと僕達の制作物は「動画を要約するカメラ」です。

例えば、このような動画があった時に

f:id:jupy:20190910102302g:plain

以下のように一枚の画像に情報を圧縮することができます。

f:id:jupy:20190910105111j:plain

前半(テーマ決め)

そもそもソラコムのインターンはかなりプログラムの自由度が高く、取り組むプロジェクトや達成すべきノルマといったものが特に設定されていません。
そのため、はじめの一週間はインターンを通じて取り組むプロジェクトを決めることが目標でした。
ソラコム自体のサービスについて調べたり、ソラコムのデバイスやAWSのサービスを自分たちで組み合わせて簡単なデモを作ったりしていました。

f:id:jupy:20190904133940p:plain
使ったデバイス達
f:id:jupy:20190904173553p:plain

加速度センサーを用いた地震計
f:id:jupy:20190905144945j:plain

ボタンを押すとその日の天気予報をLINEに送るデモ ボタンの端子を接触させたままロッカーにしまって帰宅したため、退社後にも無限に通知が来た

またMaker Faire Tokyo 2019Hello SORACOMといったイベントに参加したりもしました。

f:id:jupy:20190904173455p:plain

Maker Faire Tokyo 2019

簡単なデモやイベント、社員さんの説明などを通じて僕達が特に興味を持ったものが今年の7月にリリースされたばかりの”S+ Camera Basic”と呼ばれるデバイスでした。  

f:id:jupy:20190903131247p:plain

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を使うことでアップロードする画像の枚数を減らして通信料を削減でき、視覚的にも大量に送られてきた画像を順番に見ていくよりはずっとわかりやすくなります。

f:id:jupy:20190905133355j:plain

ちなみに作る前のイメージ図(雑)はこんな感じでした。(赤文字が「物体の位置」と「その動き」と「物体がその場所にいた時刻」を表していて、数分に起こった出来事が一枚の画像に集約されています)

インターン生のtakuyaがS+ Camera Basicに遠隔首振り機能(S++ Swing)をつけるとのことだったので、S++ Summaryと合わせてこれら二つの開発をS+ Camera Basicの拡張パッケージ開発:“S++ Project”として三人で進めていくことになりました。*1  

前半(設計・中間発表)

まず開発するにあたって、S++ Summaryにどのような機能を持たせるかについて話し合いました。
これは、「動画を要約する」とはそもそも何を指しているのかという話です。
話し合いの結果、最終的に僕達は「動画内での代表的な動きを捉えること」を「要約」と定義し、さらに細かく言えば、
 ・代表物
 ・その代表物の動き(動線)等の情報
を画像に上手にのせることを”S++ Summary”としました。

そして、それに向けた全体の関数の流れ、必要な関数と必要な変数など、S++ Summaryを開発するにあたっての大まかな設計を二人でしました。

f:id:jupy:20190904110445j:plain

関数設計
f:id:jupy:20190904111504p:plain

関数概要(一部)
f:id:jupy:20190910133548p:plain

変数仕様(一部)

もちろんこれらの設計には後に細かく修正が入ったのですが、動作の大まかな挙動を共有する意味で役立ちました。
(例えば、代表物を要約画像に貼るのにも 物体検出→代表物として使うのかの判定→いくつもの代表物を画像内に適切に配置 などステップは何段階にも渡ります)

このとき中間発表会と後半戦に作るサービスのプレスリリース*2を控えていたので、そちらも同時に進めていました。

f:id:jupy:20190905173016p:plain

中間発表スライド
f:id:jupy:20190905173039p:plain

中間発表スライド2
f:id:jupy:20190904112420p:plain

プレスリリース冒頭

中間発表とプレスリリースを無事終えた後、頂いたフィードバックで若干の軌道修正を加え、後半戦に向かいました。  

後半(開発)

いよいよ後半、開発です( ✌︎’ω’)✌︎ ✌︎(‘ω’✌︎ )

ここでは実装の細かい説明というよりはS++ Summaryを開発する上で判明した問題点のいくつかとそれの解決に向けての提案手法を書いていこうと思います。(技術的な内容が急に増えます!)

問題1 Raspberry Piの性能による問題
後半戦を開始した当初は取得した画像に対して物体検出を行い、前フレームとの同一物の判定・記録をし、定められた時間内全ての画像に対する解析を終えた後に、代表物の決定や動線の描画等を行う予定でした。
しかし、S+ Camera Basicはラズパイ*3をベースとしているため、メモリが少ない・CPU性能が低いといった制限があります。そのため、画像をためこんだ後にためこまれた画像全てに対して物体検出を行い物体の動きを解析する手法を用いることはできません。(´;ω;`)

f:id:jupy:20190912121629p:plain

この問題を解決する手法として、MobileNet-SSDのような処理の軽いモデルを使用して物体検出を行う方法と、画像に対して直接物体検出を行うことは避けてKNNによって背景を推定し推定された背景と画像との差分を取って動体を検出する方法の二つが提案されました。
今回のインターンシップでは精度や処理時間のことを考慮した結果後者の方法を採用しました。また、メモリを節約するために、処理を行う上で常に直前とフレームと現在のフレームからの情報以外を持ち続けない(2フレーム以上前の情報は捨てる)ようにプログラムを設計し直しました。

問題2 フレーム間の時間差の制約
物体の動きをカメラの画像から捉えるためには、直前のフレームと現在のフレームに映る物体に対して「同一の物体か」を判定することが必要です。
当初はこの判定は、直前のフレーム及び現在のフレームで検出された物体の特徴点を抽出し物体間の距離がある程度近いもののうち特徴点の類似度が高いかどうかで同一物体を判定する予定でした。この手法は、検出物が隣り合うフレームで大きくは動かない(瞬間移動/ワープしない・大きく変化しない)ことが必要で、このためにはフレーム間の時間間隔が短くなくてはなりません。*4

f:id:jupy:20190904172720p:plain

しかしながら、問題1で述べたような手法をとっても、1画像(720p)あたりの処理には700ms程度はかかってしまいフレーム間の処理が充分短いとは言えません。
そのため、特徴点の距離・類似度から貪欲に同一物を判定することができません。 

そこで、僕達は直前のフレームと現在のフレームの物体間に、距離・輪郭の大きさ・輪郭の形状差から算出した重み付きの辺を適宜枝切りしながら貼ったグラフを構築しました。
そして、そのグラフに対して重み付き最大二部マッチングを行うことで適切に同一物体のペアを選択するようにしました。
こうすることで、特徴点の変化量が大きくても、あくまで要約画像全体として動線がうまく成立するようにマッチングが行われます。

後半(手元PC上での実験)

上では開発時に起きた問題のいくつかを取り上げましたが、実際の開発はまずiPadで撮った動画に対してノートPC上で動作するものを作りました(* ‘꒳ ‘* )
ただしノートPCとラズパイとではスペックが大きく違うので、「取得した画像のうちの97%を使用せずに破棄する」というウェイトを持たせてRaspberry Pi同等の性能で開発できるように工夫しました。
この手法は単純ですが実機にデプロイする前にノートPCで動作検証できるので、有効な手法でした。

ノートPCで開発する際はとりあえず大枠の試作版を作り、その上で徐々に改善*5していくといった方法をとりました。
ここでは、そこでの途中経過のようなものを簡単にまとめていこうと思います。

(以下の画像のモザイクはあとで編集して加えたものです。また、時間表示・フレーム表示はデバッグ用のものです)  

f:id:jupy:20190904155101j:plain

初めてまともにうまくいったもの。結構手応えがあったのだが、全て違う往復時のpiyoであることがうまく伝わらずあまりウケは良くなかった(ver.11 )
f:id:jupy:20190904155519j:plain

嬉しくなってver11.を実機に組み込んだら、無が生まれた┌(´・ω・┐`)┐。
実機への移植の難しさを知った。
f:id:jupy:20190904161227j:plain

二部マッチングを組み込んだ。各々の人が別の部屋に入ったのがちゃんと分かる(ver.14)

↑この時点で僕達が当初作りたかったものが一旦完成したのですが、これを見てどうですか?
僕達は「なんか見にくい(๑-﹏-๑)…思ってたのと違う(・^・╬︎)…」って思いました。

f:id:jupy:20190912122949j:plain

最初にイメージしていたものとの比較

写真では背景にも様々な色があるため単純に見にくいです。
また線が密集していて「誰がどの動線か」ということが非常に分かりづらいです。
これは広角レンズを装着したり、俯瞰からの写真になるよう設置場所を工夫し、密度を小さくすることでも改善できると思いますが、僕達はアルゴリズム面でもっと見やすくなるよう試行錯誤をはじめました。

f:id:jupy:20190904160202j:plain

時刻表示や色の改善、移動方向を表す矢印が増えた。
かなり分かりやすくなった(⋈◍>◡<◍)。✧(ver.18)
f:id:jupy:20190905135051j:plain

代表物の表示を明確にした。色々な状況にも対応できるようにした。(ver.22)

はじめに想定していた要約画像(ver.11)を作って見たら案外見づらかったので、二人でどんどん修正していき、要約画像が色々な状況に対応できるようになりかつ視覚的に分かりやすくなっていくのはやっていて楽しかったです。

実際に運用する際にはS+ Camera Basicの強みを生かして、動線や検出などの閾値・比重をユーザーコンソール上で変更することができ、取り付ける場所によって後からチューニングすることが可能となっています。  

後半(実機テスト・最終発表)

ようやく実機テストです イェイL(‘ω’)┘三└(‘ω’)」イェイ
PC上で満足のいく挙動をするコードが書けていたので、あとは実機にデプロイするだけで楽に終わるかと思っていたのですがそんなに甘くはありませんでした。

まずバグが出るのは当たり前として、実機になるとその原因究明の難易度が跳ね上がります。
PC上での実験では環境さえ整えてしまえばバグはアルゴリズム面のものがほとんどだったのですが、実機になるとそれに加えてハード面や通信面など様々な可能性がでてきます。
そうなると、一つのバグに対しての対応にかなり時間を取られてしまったり、コードだけを変えて改善するということがしづらくなってしまいます。
なので、これは反省なのですが、実機にデプロイする前にコードをしっかりと整理するべきでした。
実機テストに移った後にコードを書き換えるのはどうしても難しく、「とりあえず動きはするものの、もっと綺麗にしたい…」といったコードのまま整理できずに終わってしまいました。

そういった反省点もあるのですが、ここでは上と同じように実機テストがうまくいくまでの過程をまとめていこうと思います。

f:id:jupy:20190910102806j:plain

はじめての実機デプロイ。芸術作品(´・ ω ・ `)カナー
f:id:jupy:20190910102843j:plain

実機で初めてうまくいった時の画像。カメラのアングルがあまりよくない。
f:id:jupy:20190910102703j:plain

ついにテスト設置(。・_・。)ノ!
f:id:jupy:20190910102609j:plain

設置後初のテスト。
アルゴリズムがうまくいっていなかったせいでものすごいことになってます…
f:id:jupy:20190910103302j:plain

修正して翌日に試したら赤みがかってしまった。
これはS+の標準仕様のカメラにIRカットフィルタがついてないことが原因だった。
(今回はデモ向けにIRカットフィルタ有りに取り替えていただきました。)
f:id:jupy:20190910103744j:plain

腕や足が分離してしまってうまくいかない。

動作自体はPC上での実験通りにしっかり動いているはずなのだけれど何かうまくいかない…ということが最終週になっても続いていました。
結論として、ノートpc上でのテストではiPadで撮ったビデオを使用したため画像に対してiPad側で自動で補正が行われていて、そのお陰でうまくいっていたことが判明しました。
ここでいう「補正」とは、明るさや色温度の調整はもちろん動体に対してピントを合わせたり露出度を補正したりといったこと指しています。
時間の制約上これらを自分たちで実装するのは難しかったので、僕たちは撮った画像に対して線形変換やγ変換、画像色補正を施してコントラストを調整し、背景取得の方法をKNNから混合ガウス分布による手法に切り替えることで動体がうまく検出されるようにしました。
また、ピントが合わず代表物の境界がぼけてしまうので、代表物の表示は矩形で囲うようにしました。

実際に設置してみて「思ったより画像が暗い…(๑•́ ω •̀๑)」などがあった際に、現地に赴かなくてもアルゴリズムを変更できるのはS+の大きな強みです。

そして、、、

f:id:jupy:20190912132447j:plain

成功\\\└ (‘ ω ‘) 」////ウオオオオオオオオオオオオオオオ!!!

無事、成功しました!本当にインターン6週間の最後の最後になんとか動いたので、実際には\\\└ (‘ ω ‘) 」////ウオオオオオオオオオオオオオオオ!!!!!!!!!!!!というより安堵の方が大きかったです。

こうしてあっという間だった6週間のインターンを終えました。
メンターの方をはじめとして社員の皆さんが僕達をものすごく支えたり盛り上げたりしてくださったお陰で、刺激的で最高なインターンシップになりました。
本当にありがとうございました。

おまけ

せっかくなので、ソラコムの雰囲気やインターンの生活を知ってもらえたらいいなというコーナーです。

f:id:jupy:20190904112902j:plain

開発環境(物理)

開発スペースはインターン生だけが隔離されているわけではなく、社員さんが働いているオフィスの中にインターン生用のスペースが確保されていました。
お昼の時間などは決まっているわけではなくて、誘われたタイミングでついていく感じでした。

ブログのはじめの方でソラコムのインターンは自由度が高いと書きましたがこれ取り組む内容に関しての話で、インターン期間中はガチプロ社員さんとの距離感がとても近く、定期的にメンターの方と進捗を共有して進め方を相談したり、疑問点や問題点をSlackやScrapboxに書いておくと鋭いツッコミがすぐに入ったりといったサポートがたくさんありました。
その上、モニターや椅子の質、飲み物完備等の物理面での環境も最高でとても恵まれた環境でした。

f:id:jupy:20190912152248p:plain

リアルタイムに同時に編集できるScrapbox、便利すぎる( ˘ω˘ )

これは余談なのですが、ソラコムは個人の判断でリモートワークが許可されていて、満員電車や天候の影響を受けずに快適に仕事ができるようになっています。メンターの方の中にもリモートの方がいたのですが、Slack や Scrapbox を使ってスムーズに情報共有ができてとても便利でした。

f:id:jupy:20190910130458j:plain

ピザ会の様子。普段あまり話すことのない社員さんからの貴重なお話をたくさん聞けました。

また、隔週金曜日の進捗報告会 “Happy Hour” や社員さんと交流を深めるためのピザ会などを通して、様々な業務に携わっている社員さんから業務の内容から雑談までいろいろな話をしていただきとても勉強になりました。

f:id:jupy:20190904170812j:plain

Ishigaki

Ishigakiという名前の畳の部屋があって結構好きでした。S++ Summaryの設計もS++ Swingの予算案もここで話し合いました。
他にもいろいろなタイプの会議スペースがあって常に新鮮な気持ちで会議ができるようになっていました。(それぞれの会議スペースは別々のトライアスロンの開催地をテーマとして設計されてるらしいです。)

f:id:jupy:20190904112820j:plain

中間発表会お疲れBBQ

オニク、オイシイ

f:id:jupy:20190904171113j:plain

個人的に気に入っていた、ソラコムの目の前にあるハンバーグ。レアなのがいい

オニク、オイシイ

*1:takuya の参加記も公開される予定です

*2:プレスリリースは新サービスをリリースする時の報道機関に向けた告知のことなのですが、そのサービスを使うメリットを自分たちの中で明確にするためにソラコムではサービスを作る前にプレスリリースを書く文化があるらしいです。

*3:Raspberry Pi 3B+

*4:フレーム間が十分に短い場合、ブロックマッチング法や勾配法などのアルゴリズムを用いたオプティカルフロー推定を行うことで移動物体の動きを推定できるそうです。

*5:Kaizen SORACOM カルチャー