🦊

WebRTC(Amazon Chime SDK JS)で超解像を使ってみた

8 min read

この記事は、こちらの記事を改変したものになります。
https://cloud.flect.co.jp/entry/2021/09/14/105249

こんにちは。

前回の記事では、Amazon Chime SDK JSを用いたビデオ会議システムやゲーム配信システム(Among us auto mute)において、複数ユーザのビデオ映像を単一の映像に合成することでデータ通信量を削減する方法をご紹介しました。
今回は、データ通信量を削減する別の方法として、ビデオ映像の送信時には解像度を落として受信後に超解像技術を用いる方法を試みてみましたので、これを紹介したいと思います。

下図が実際にやったときの画像です。一番右側の画像が超解像を使用した結果です。赤線左右で左のほうが高解像度化されています。
cap_画面収録 2021-09-09 13 36 55_00:00:02_03

画像だと潰れてしまってわかりにくいと思うので、次のリンクから動画をダウンロードして確認してみてください。
download

今回の試みについて

超解像とビデオ会議

超解像は入力された画像を高解像度化して出力する技術のことです。定義や手法はいろいろあるようですが、ここではDeep Learningを用いて画像の高解像度化を行う技術だと考えてください。最近では、NVIDIAが TensorRTに最適化されたモデルとSDKを提供して話題になっていました(参考)。日本ではSoftbankがNVIDIAと組んで、ビデオ会議へ適用する実証実験をしたりしているみたいです(参考)。

image
NVIDIA DEVELOPER BLOGより

今回の試みの目的

今回のアイデアはデータの送信時には低解像の画像を使用し、データを受信した各クライアントで超解像技術により高解像度化して表示するというアイデアです。低解像度の画像を送信するのでデータ転送量(送信データ量、受信データ量)の削減が期待できます。
今回は、Amazon Chime SDK JSを用いたアプリケーションに適用して効果が出るか検証してみたいと思います。
なお、上記のNVIDIAのSDKはリポジトリを見る限り、ブラウザ上では動かないようなので、今回は超解像の部分は独自に実装します。

超解像: ESPCN

Deep Learningを用いた超解像は、上記のNVIDAのモデル以外にも多く提案されています。
今回はビデオ会議で使用するためリアルタイムに処理できることが要件となります。
今回我々が使用するESPCN(efficient sub-pixel convolutional neural network)は、リアルタイムでの処理に使用することを想定して提案されている超解像技術です。

Screenshot from 2021-09-09 16-40-48
論文より抜粋

ESPCNは2016年にtwitterから提案されているものです。変化の早いDeep Learning業界において、現在(2021年)となってはかなり古いものではないかと思いますが、私の調べた限りでは現在のところESCPNを超える軽量、高速なモデルの提案は見当たりませんでした[1]OpenCVのBencmarkでも圧倒的な速さを示しています。また、ESPCNはffmpegでも超解像モジュールとして使用されているなどの実績もあります。

これらの理由から、今回はESPCNを用いて超解像を実装することとしました。

ところで、このモデルの詳細は論文を参照していただきたいですが、読んでみて個人的に一番面白いと思ったポイントは、画像をYCbCrのカラースペースで扱い、輝度信号のみ超解像処理を加えると言うアイデアです。(このアイデア自体は別の論文で提案されていたものです。)人間の目は輝度信号に一番敏感なので輝度信号を高解像度化するだけでもある程度高品質な超解像ができるというもので、これにより処理するデータ量を大幅に削減でき高速に処理できるようになるというものです。「どうせバレないから大丈夫」と、mp3の圧縮技術を聞いたときと同じような感覚です。なお、このモデルのメインのポイントはタイトルにあるとおり、sub-pixel convolution layerとpixel shuffle(depth_to_space)だと重いますが、これらについては論文を読んでください。

ESPCNのデモ

今回はTensorflowでESPCNのモデルを作成して訓練を行いました。下の図は240x250の画像を480x500に高解像化したものです。左の図がESPCNを用いて高解像度化したものです。右の図がHTMLCanvasElementのdrawImageを用いて画像を拡大したものです。(まだWebRTCで転送はしていません。)
左の方がかなりはっきりと輪郭や服のシワが表現されているのが解ると思います。もし、ブログ上の画像だとわかりにくいという方は、デモページを作成していますので使ってみてください[2]

Screenshot from 2021-09-09 17-45-38

下図は幅も高さも2倍に高解像度化したときの処理時間を示したグラフです。横軸が入力画像の横幅です。縦軸は処理時間(msec)です。処理時間を3つの環境で測定しています。青色がRTX1660を搭載したPCでTensorflowJSで動かしたものです。赤色はM1 MacBook Air上でWasm/SIMD版のTensorflowLiteで動かしたものです。TensorflowJSで動かすよりTensorflowLiteの方が高速に可動したためこちらを採用しました。黒色はThinkPad(corei5 8350U 1.7GH)上で、Wasm/SIMD版のTensorflowLiteで動かしたものです。こちらもTensorflowJSよりTensorflowLiteの方が高速でした。

Screenshot from 2021-09-09 20-20-39

Thinkpadはかなり古いPCなので、RTX1660搭載のPCとMBAだけを見ると、幅が240Pxあたりまであれば100msec以内(=10fps以上)で動きそうです[3]。ということで、以降、幅240pxのデータを用いることを前提に検証を進めていきます。

なお、幅と高さを3倍に高解像度化した場合と4倍にした場合も計測してみましたが、これらの処理時間も同じ傾向でした。データは付録に記載しています。

実験

それでは、WebRTCで送信する画像は低解像度のものにして受信側で高解像度化するシステムで次の2点を検証してきたいと思います。

  • どのくらいデータ転送量を少なくできるのか
  • 超解像を用いてどの程オリジナルの映像に近い状態に復元できるのか

構成と評価方法

Screenshot from 2021-09-09 21-30-43

上図は今回の実験の構成です。単一のブラウザ内で2つのChime Clientを同時動かします。一方が解像度を下げた後の映像を送信し、他方がその映像を受信します。受信後はESPCNを用いて高解像度化を行います。
この構成において、(1)受信するデータ容量を確認します。また、(2)高解像化によりどの程度オリジナルの映像を復元できているか、そのクオリティを確認します。

受信するデータ量を確認する際には、送信元は動画を流します。WebRTCの映像エンコーダが賢くて差分データしか送らないため、静止画だとデータがほとんど送信されないためです。一方で、高解像度化による復元のクオリティを確認する際には、送信タイミングと受信タイミングでラグがあるので、動画を使用すると高解像度化したタイミングで映像のフレームが進んでおり送信元の画像がわからなくなってしまいます。このため、高解像度化による復元のクオリティを確認する際には、同一の静止画を一定時間流し続けて高解像度化が終わった段階でその画像の復元のクオリティを確認します。復元のクオリティの確認にはPSNRとSSIMを使用します。PSNRとSSIMの算出方法は、こちらのOpenCVのドキュメントに従っています。どちらの評価においても、入力される映像のサイズは480x360の画像とします。

結果

(1) 受信データ量

まず、受信するデータ量の変化です。

https://www.youtube.com/watch?v=B2kcbEIAihY

オリジナルのサイズで映像を転送すると、送信側も受信側も300〜400KiB/Secのデータ量ですが、1/2の解像度で転送すると一気に100〜150KiB/Secまで減らすことができます。1/3や1/4の解像度で転送すると徐々に減りますが減り幅は少なくなります。

(2) クオリティ

次の動画は480x360の映像を240x180の映像に低解像化して転送したものを、再度480x360に高解像度化したものです。赤い線の左側がESPCNで高解像度化したものです。赤い線の右側はHTMLCanvasElementのdrawImageでリサイズしたものです。

https://www.youtube.com/watch?v=3b1DY5MNyaQ

ESPCNの方はかなり鮮明になっていると思います。youtubeの動画だとわかりにくい場合は下記のリンクから映像をダウンロードしてみてください。
download

下のグラフは静止画を使ってPSMRとSSIMを用いて類似性を検証した結果を示しています。
使用した静止画はDIV2K datasetのテストデータ(画像枚数100枚)です。

Screenshot from 2021-09-13 11-34-47

実験を行ってわかったことですが、受信する映像がネットワークの状況等の影響で毎回微妙に異なってしまうらしく、評価するたびにPSNR, SSIMの値が変わってしまいました。
このため、この値は大まかな傾向を見るための参考値程度と考えたほうがいいかもしれません。
上記の映像か今回行った実験のコードを後述するリポジトリに格納するので、各自の目で確認していただいたほうが良いと思います。
いずれにせよ、HTMLCanvasElementのdrawImageを用いて拡大するよりESPCNを用いたほうがよりオリジナルの画像に近いものとなります。
一方で、幅と高さを2倍に解像度を上げる場合であっても、オリジナルの画像と見分けがつかないレベルではないです。

考察

今回、オリジナルの解像度が480x360の映像を幅と高さを1/2にすることにより大幅に(半分以下)データ転送量を削減できました。しかし、高さと幅を1/3や1/4と解像度を落としていってもデータ転送量の削減率は徐々に鈍化していきました。
一方で、PSNRやSSIMだと直感的にはわかりにくいのでデモを見ていただくのが良いかと思いますが、幅と高さを1/2にしたときと1/3, 1/4にしたときの映像の劣化具合はかなり違って見えると思います。

どの程度の映像の劣化が許容されるかは、ユースケースや個人の感覚によってしまうので判断は難しいです。また、データ転送量とのトレードオフになると思います。
個人的には、元の画像の1/2の解像度でデータの送受信をするくらいであれば、人間の目では大きな映像の劣化はないので、多くのケースで実用に耐えるのではないかと考えます。
これに加え、ESPCNを用いて高解像度化することで映像の劣化が抑えられることになるので、より適用可能なケースが増えるのではないかと考えられます。

まとめ

今回は、ビデオ映像の送信時に解像度を落として送信し、受信後に超解像技術を用いることでデータ通信量を削減できないかという試みをしてみました。
実験の結果、単純にHTMLCanvasElementのdrawImageで解像度を戻す(リサイズする)より、より良く映像を復元できることが確認できたと思います(多分に主観が入る)。
画質が劣化することは避けられないので、こういうケースなら必ず使える、というのは難しいですが、超解像(ESPCN)を用いることで帯域が制限される環境で解像度を落として転送するという選択肢を選びやすくなると考えています。

また、今回は触れなかったですが現在のAmazon Chime SDK JSが扱える解像度の上限は1280x720ですので、クライアント側でこれを超える解像度を使用したいと考える場合にも適用可能ではないかと考えています[4]

リポジトリ

今回実験で使用したコードはこちらのリポジトリに格納してあります。

https://github.com/w-okada/flect-chime-exp-001-sr

付録

ESPCNで高解像度化したときの処理時間(x3とx4)

Screenshot from 2021-09-09 20-30-03

謝辞

人物の画像、人物の動画、背景画像はこちらのサイトの画像を使わせていただきました。

https://pixabay.com/ja/
https://www.pakutaso.com/

Disclaimer

本ブログのデモの使用または使用不能により生じたいかなる直接損害・間接損害・波及的損害・結果的損害 または特別損害についても、一切責任を負いません。

脚注
  1. より良いものがあれば、是非コメントをください! ↩︎

  2. ここで用いたデモはこのリポジトリに格納されています。 ↩︎

  3. RTX1660の環境で入力画像の幅が240pxを超えた段階で大幅に処理時間が伸びる理由はRTX1660の使用率が80%を超えていたので、おそらく処理限界に達しているからだと思われます。実際、TensoflowLiteを使用するほうが僅かに高速化される。 ↩︎

  4. (ただし、この場合は、かなりの性能のハードウェアが必要となる可能性があります。) ↩︎

Discussion

ログインするとコメントできます