CTOの夏です今回は先日iOSでリリースした通知ぼかし機能について、裏でどういうことをしているのかについて軽く紹介したいと思います。)を用いて、スマホ画面を直接収録・配信することで、配信用のSDKを各ゲームやアプリに埋め込んでもらう必要がなく、ユーザさんが色々なアプリを気軽に切り替えながら友達と雑談を楽しんだり、ゲームを通じて新しい友達を作ることができます。その反面、配信者が適切な設定を行っていない場合、意図しないプッシュ通知が視聴者に表示されてしまう場合もあります。Mirrativでは配信準備画面に注意文言と啓蒙動画を載せていますが、どうしても設定が漏れたりする場合があるため、配信者が注意しなくても、プッシュ通知が視聴者に見えない仕組みを以前から検討していました。利用することで、通知を受信したタイミングで配信を一時的に停止する設定を入れています。副業の方と整理し、以下のような要件で実装してもらうことになりました。モザイクをかけて配信したいただしMirrativアプリの通知はぼかさなくて良い配信へのコメントがぼかされてしまうと、視聴者が「配信者がコメントを読めない」という誤解を招く場合がある対象は画面上部からスライドインしてくるバナー通知のみ。通知センターに表示される通知等はモザイクをかけないで良い能動的なアクションが必要となる通知は、配信者の注意によって防止できる同様の理由で、配信者が通知をタップした場合等はモザイクが外れてしまっても良いつまりこいつです。副業の方に実装をお願いする以前、iOS11から利用できるVisionフレームワークの短形検知を利用したプロトタイプを試していたのですが、ゲームなどが動いているバックグラウンドで、OSに一番殺されやすいプロセスの中、さらに配信しながら行う処理であることを考えると、CPU使用率やメモリ使用量などが懸念点となり、汎用的な手法を取るより、プッシュ通知という特定の領域に絞って自前で検知アルゴリズムを実装することになりました。基本方針の検討iOSには現状、他アプリからのプッシュ通知イベントをフックする手段が無いため、配信用にサンプルされた画像から通知の存在有無を判定し、その領域を検出する画像処理が必要となります。通知領域が検出できれば、あとは単純にその領域に対してモザイクをかければよいでしょう。考えうる方針としては以下があると思われます。必要となる、デバッグが困難である等のデメリットがあります。既存アルゴリズムは、例えば古典的なCanny法やHough変換などを用いることは可能であり、うまくすれば将来的なUIの変更等に対して非常に頑健に作れる可能性があるものの、基本的に計算量が大きくなるというデメリットがあります。通知ぼかしはゲームアプリ等のプレイ中にも常時動かす処理であるため、計算量は限界まで削減したい所です。これら既存アルゴリズムの対象が主に風景などの自然写真であるのに対して、今回の対象は固定的な通知領域UIであるため、その削減余地は非常に大きいと言えます(エッジの角度を一切気にしないで良い、出現位置を事前に調べることが可能、etc)。以上から、今回は通知領域検出に特化したルールベースのアプローチを取ります。整理すると、メリットとデメリットは以下となります。2-a)デメリット閾値等を手動で微調整する必要があるOSアップデートによって通知領域の形状が変更されるなどした場合、閾値を再調整する必要が出てくるかもしれない端末解像度の違いなどに対して感度が高い新しい解像度の端末が発売されるために、データを追加する必要があるただしこの運用コストを多少緩和するアプリを作った。今回は、メリットに上げた点を優先するためにこれらのデメリットを犠牲にしました。現行アプローチの継続に軍配が上がると思われます。検出したい通知領域は、例えば以下のような角丸矩形ですが、プッシュ通知は画面上部からスライドインしてくるため、上のような完全な角丸矩形でしか検出できない場合、スライドイン中の通知内容が見えてしまうことになります。よって、以下のような角丸矩形の下部を検出し、その領域を画面最上端まで拡張した領域を検出することにします。以下2点によって定義できるでしょう。外縁がエッジで囲まれている内部が塗りつぶされているこれらは機械処理しやすいよう、以下のように換言できます。外縁に大きな輝度変化が存在する内部に大きな輝度変化が存在しない外縁をまたぐ赤矢印の部分に大きな輝度変化が存在し、内部の青矢印の部分に存在しなければ、領域とみなすことができそうです。矢印の間隔を小さくしていくことで精度は向上しますが、パフォーマンスの関係上、適度に間引くことにします。ため、適当な閾値を探す必要があります。輝度変化を捉える手法はいくつかありますが、ここでは一次微分の分散を用いることにします。具体的には、まず下図中の黄点のように矢印線上のいくつかの点をサンプリングします。その上でRGBそれぞれの一次微分(つまり画素値の差分)を計算し、それらの分散(dv)を下式によって計算します。ここでpiはi番目の画素値、Dは画素間の距離です。dvをRGBそれぞれについて計算し、最大のものを特徴量として使用します。最初にグレースケール化してから計算すると特定ケースにおいて精度が落ちたので、今回はRGBごとに計算するようにしています。このdv値を、事前に調べておいた閾値と比較し、大きければエッジがあり、小さければエッジが無いと判定することが可能となります。閾値は、外縁・内部ともに2.0が一番精度が高そうでしたが、ここは調整の余地がありますし、将来UIに変更が入った場合も調整する必要が出てくる可能性があります。検出ロジック上記のアルゴリズムによって、矢印の両端点が与えられた場合に、それらを繋ぐ直線状にエッジが存在するか否かを判定することが可能となりました。これを用いて、与えられた画像の全領域内に通知領域が存在するか否かを判定していきます。基本的な流れとしては、以下になります。(角丸は通知領域を特徴づける有力な特性であるため強めに評価する。横線部はそもそもの端点が少ないためこちらも強めに評価する)inner(内部)の場合、スコアは常に1で良いそれぞれのスコアの平均値が基準を満たしているかを、閾値によって判定する直感的な解釈としては、innerについてはエッジが存在すると判定された矢印の個数の割合。それぞれ1.0と10.0が効果的でした。これによって、例えば真っ白な画面を判定する際などに、全ての端点ペアを走査することなく即座に検出処理を中止することが可能となり、多少パフォーマンスと検出精度が向上します。上述のアルゴリズムを用いる際、各端末の解像度ごとに通知領域の出現位置を事前に調べておくことが、精度やパフォーマンスの観点から非常に重要となります。miniでは通知領域のx座標が異なりますが、これを事前情報として持っておかないと一定範囲のxに対して検出メソッドの呼び出しをループしなければならなくなり、計算量が飛躍的に増大してしまいます。逆に端末ごとに固定値を調べておくことができれば、x座標を決め打ちすることが可能となります。この事前情報を調査するため、単にローカル通知を表示するためだけのアプリを実装し、各シミュレータで動かして、通知が表示されたスクショを撮影し、それらに対して非常に単純なロジックによって通知領域を検出して、以下のような端末解像度毎の出現位置を割り出しました。上述した手法を用いれば一応通知領域は検出できますが、まだパフォーマンスに改善余地があります。通知領域が存在する可能性のある全領域を30fpsで検索していると流石に重く、手元のiPhone7ではCPU使用率が30-50%程度となりました。よって、どうにかして探索範囲を狭める必要があります。対象範囲を狭めることができれば結果的に誤検知が減り精度の向上も期待できます。ここでは、通知領域の位置の時間的変位が利用できます。噛み砕いて言うと、以下のような想定を置くことが可能です。(必ず上からスライドインしてくるため)前フレームにおいて、ある位置に通知領域が検出された場合、その周辺を優先して探索すればよい余談ですが、通知領域のスライドアニメーションは一般的なease-in/outなので、これを利用してシグモイド関数等を使って線形モデルよりも精度の高い出現位置予測を出来そうですが、試してみたところそこまで精度が上がらなかったのでやめました。前回の検出位置という状態変数を持つことにより、いくつか問題が出てきます。具体的には以下のようなものをケアする必要があります。(fail-safe的に)Mirrativからの通知だけモザイクをかけない通知領域を検出した場合、その通知領域内のアイコン部分を調べ、もしMirrativのアプリアイコンと一致していれば通知領域なしと判定します。こちらに関しては、SADを用いた単純なテンプレートマッチングを行っています。アルゴリズム詳細はこのへんのサイトを参照して下さい。ImageのCIFilterのうちCIPixellateを適用してモザイクをかけています。Mirrativ以外の通知がぼかされていなかったりと一部不具合も残っているため、現在CSチームと協力して不具合が起きている箇所の動画を収集しており、さらなる改善に繋げようとしております。20:33Tweet関連記事2019-12-12ミラティブにてクラロワAPIを利用したイベントをやってみたこんにちわ。