iPhoneの動画解析で青信号を安全に渡りたい


:::note info
この記事は[LITALICO Engineers Advent Calendar 2022 カレンダー2](https://qiita.com/advent-calendar/2022/litalico)の7日目の記事です
:::

# 概要

この記事では、個人の活動として開発している、青信号を安全に渡るためのiPhoneアプリの話をしたいと思っています。本記事で触れているアプリは、まだ、未公開です、理由としては、データ数を増やし、きちんと検証を行った上で公開した方が良いと考えているためです。今後、検証を行い、利用者の方の安全も含め、問題ないようでしたら公開して行きたいと考えています。

# なぜ、作るのか

NHKの番組を見ていたところ、視覚障害の方の団体が、音響式信号の鳴動時間の延長に対して、要望をあげたという内容が報道されました。音響式信号の６割余りは騒音などの対応として、早朝や深夜は音が鳴らないよう設定しているそうで、それに対して、前述の要望がなされ、それを受けて所管の警察は、一部は、24時間音が鳴るように、一部は、鳴動時間の延長を設定したということでした。

上記自体も非常に考えさせられる内容だったのですが、上記の番組中で、視覚障害の方のおっしゃっていた「そもそも、音響式信号が少なく、設置されていない細い道は渡るのが怖い」という話が気になり、全国の音響式信号の設置数を調べました。音響式信号は、[令和４年３月末現在、全国で20,838基](https://www.npa.go.jp/bureau/traffic/seibi2/annzen-shisetu/hyoushiki-shingouki/onkyou.html)、それに対して、[歩行者用灯器は約103万灯](https://www.npa.go.jp/bureau/traffic/seibi2/annzen-shisetu/hyoushiki-shingouki/led/led.html)で、割合としては、2%となります。各警察組織ごとに、計画を立て、整備を進めているとのこと（参考：[警視庁の取り組み](https://www.keishicho.metro.tokyo.lg.jp/kotsu/iken_yobo/shingo_faq/onnkyo_shingo.html)）ですが、自分にも何かできることはないかと考え、検討を開始しました。

# 検討案

## 検討案1: Bluetoothなどを用いて、信号の状態をブロードキャストで通知

このアイディアは早い段階で没にしました。理由としては、音響用信号と同じく、機器の設置が必要なため、徐々に設置台数を増やす必要があるのと、設置自体のハードルが高く、簡単に試すことができないためです。ただ、近しい発想で実現されている地域があったので共有します。信号機自体に、自身の状態をブロードキャストで通知する装置を設置し、各利用者のスマホで、それを受け取り、音声などで伝える仕組みを元々考えていました。ほぼ同じことを高度化ＰＩＣＳという仕組みで行なっているそうです。とても良い取り組みだと思います。

[兵庫県警 高度化PICSについて](https://www.police.pref.hyogo.lg.jp/traffic/regulation/pics/index.htm)

## 検討案2: スマホのカメラ機能で、動画を撮影し、動画から動画解析で、青信号を検知できないか

こちらは、本記事の本題のアイディアとなります。

1. iPhoneを胸ポケットに入れる
1. 信号近辺で、音声で、動画撮影開始の合図
1. 撮影した動画を、画像解析し、赤から青に変わったタイミングで、音声で通知する

当初は、動画解析は、クラウドサービスを用いることを考えていたのですが、
通信状況によっては、時間がかかり、撮影した時点から、解析した結果を返すのが遅くなるので、
iPhone内で処理が完結する方法を検討しました。

歩行者用青信号の時間は、横断する道路の幅などによって確保値が設定されていますが、
一般的には歩行速度を秒速１メートルとして計算されています。
例えば、対向片側１車線の道路を横断する距離は、大体15mくらいなので、
青信号は、15m ÷ 1m/s = 15秒、これに数秒追加して、18秒程度に設定されているとします。
青の点滅時間も、横断する距離によって変わりますが、上記の場合、8秒程度です。

上記の中で、青信号の検知に、5秒かかるとしたら、下記のように、致命的な状況が発生してしまいます。
青信号が点滅したとアプリから通知　→　3秒後には、赤に変わってるが、通知されない（その5秒後に通知）

![信号間隔.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277180/858797ee-d631-ced0-4cb2-103e2b9e8b36.png)


# 赤から青に変わったの検知しよう

## iPhone上ので動画解析1（Core MLの利用）

まずは、赤から青に信号が変わった際の検知を考えます。

iPhoneでは、Core MLフレームワークが利用できます。
[サンプルコード](https://developer.apple.com/documentation/vision/understanding_a_dice_roll_with_vision_and_object_detection)も豊富なため、Core MLを使って、アプリに物体検知を組み込み、青信号に変わったことを判別することを考えました。

- カメラをライブキャプチャ用に設定
- Core MLモデルを組み込み
- 結果を解析して、オブジェクト（=信号機）を分類する
- 信号機で点灯している色を判別
    - 赤が検出された状態から、青が検出される状態に変わった　→ 信号が赤から青に変わった

```Swift
let objectRecognition = VNCoreMLRequest(model: model, completionHandler: { (request, error) in
    DispatchQueue.main.async(execute: {
        guard let requestResponse = request.results else { return }
        for observation in requestResponse {
            guard let objectObservation = observation as? VNRecognizedObjectObservation,
             objectObservation.labels[0].identifier == "traffic light" else {
                continue
            }

            // 信号機に分類された画像に対して、色を確認する
            ...
            
            // 分類された情報を保持
            currentObjectObservation.boundingBox = objectObservation.boundingBox
            currentObjectObservation.color = xxxx // red or blue
            ...

            // 近しいboundingBoxで、検知された信号機の前の画像と比較して、色が赤から青に変わったか
            if intersectionOverUnion(previousObjectObservation.boundingBox, currentObjectObservation.boundingBox) > 0.85
             && previousObjectObservation.color == red && currentObjectObservation.color == blue {
                // 通知の処理
                ...

            }

            // 次の比較用に、値の入れ替え
            previousObjectObservation = currentObjectObservation
        }
```

上記の方法で、一旦、信号の変化自体は検出できたが、想定より通知まで時間がかかりました。（1〜3秒程度）
確認したところ、問題点は、下の2つであり、標準のモデルを使った場合だとうまく解決できないことがわかりました。

- 他のオブジェクトも検出しており、オブジェクトを検出した後、信号機を検出した場合のみ、色を判定としているため、処理に無駄が多い
- 歩行者用信号と、車用信号を分けて物体検知できない

## iPhone上ので動画解析2（YOLOv3 カスタムモデル）

Core MLの標準モデルの物体検知だと、今回の用途では、要件を満たさないことがわかったので、
カスタムモデルを作って、物体検知をすることにしました。

Core MLでも、物体検出では、YOLOv3がモデルとして使われておりまして、
このYOLOv3のカスタムモデルを作成して、アプリに組み込むことを考えます。

### YOLOv3のカスタムモデルの作成

この辺りは、多くの記事が書かれていますので、詳細は割愛しますが、
以下の流れで、カスタムモデルを作成しました。

- 画像データの収集
    - 家の近所の信号機をひたすら撮影しました。青: 250枚、赤: 280枚、点滅時の無灯: 120枚
- アノテーションの付与
    - 様々なツールがありますが、今回は、[VoTT](https://github.com/microsoft/VoTT)というツールを使っています
- データセットの変換
    - 上記のVoTTで、変換ツールが用意されています
- 学習する
    - 家のPCは、そこそこ良いGPUのPC使ってますが、10000ステップの学習に、9時間かかりました。。。

### YOLOv3カスタムモデルをアプリに組み込み

そのままだと、作成したカスタムモデルは、アプリに組み込めないので、
[Core ML Tools](https://github.com/apple/coremltools)を使って、Core MLに変換します。

注）　YOLOのバージョンによっては、Core ML Toolsをそのまま使うだけでは、うまく変換できないので、注意が必要です。
その辺りも、多くの方が記事にされていて、助けになると思いますので、参照なさってください。

この変換した後モデルを、xcodeに追加し、アプリに組み込みます。

```Swift
let objectRecognition = VNCoreMLRequest(model: model, completionHandler: { (request, error) in
    DispatchQueue.main.async(execute: {
        guard let requestResponse = request.results else { return }
        for observation in requestResponse {
            if let objectObservation = observation as? VNRecognizedObjectObservation,
             objectObservation.labels[0].identifier == "blue light" else {
                currentObjectObservation.isBlue = true
                currentObjectObservation.isRed = false

                // 近しいboundingBoxで、赤信号が検知されたか
                if intersectionOverUnion(previousObservation.boundingBox, currentObjectObservation.boundingBox) > 0.85 
                  && previousObjectObservation.isRed {
                    // 通知の処理
                    ...
                }

                // 次の比較用に、値の入れ替え
                previousObjectObservation = currentObjectObservation
            }
        }
```

# 青信号の点滅を検知しよう

##  LED信号の点滅（青の点滅とは別に）

実は、若干、ここでハマりました。
ドライブレコーダーをお使いの方はわかると思うのですが、
LED信号を動画撮影した際に、うまく撮影できないことがあります。

参考： [ドライブレコーダーでLED信号機が消える現象](https://mofulog.blogspot.com/2017/12/Dashcam-TrafficSignal-Lost.html)

iPhoneで動画を撮影する際は、フレームレートの指定ができるので、上記の参考記事のように、
勝ち合わないフレームレートに設定すれば問題ありません。
（今回は、私が東日本に住んでいますので、30fpsにしたところ、問題は発生しませんでした）

ちなみに、青信号自体の点滅は、当たり前ですが、上記ほど、高速ではなく、
0.5秒間隔なので、青と消えている状態の検知の時間差でも確認できるのですが、
その場合、画像解析しなければいけない回数がえらいことになるので、不採用としました。

## 信号のフレームアウトの対策

原理的には、青信号の点滅も、赤から青への変換と同じく、楽に検知できるだろうと考えていたのですが、作成したアプリを確認している際に、恐ろしいことに気づきまして。。

赤から青に変わる際は、信号を待っている、つまり、人が移動していないので、動画に映る信号がほとんど動かないし、フレームアウトすることもないのですが、青信号の点滅を検知しなければいけないのは、横断している最中のため、人が移動しているし、場合によって、信号自体がフレームアウトしてしまいます。フレーム内に、信号を収め続けてもらうのは難しく、また、boundingBoxも、変わるため、上記だとうまく、青の点滅が検知できませんでした。

魚眼レンズを用いて、なんとか、信号を捉えることも考えたのですが、そうすると、画像解析の精度が悪くなってしまうため、別の方法を考えることにしました。

## 信号機の青信号の確保値を記録する

信号機の周期は、交通状況によって、変化します。
ですが、前述の青信号の確保値を下回らないように、信号機の周期は設定されています。

そのため、信号機の青信号の確保値を記録して、
赤から青に変わった後、その確保値内であれば、確実に青であるとして、通知を出すように変更しました。

![名称未設定ファイル.drawio (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277180/06ac2ef5-5fdb-d03d-7b88-168b0a3762a1.png)

# 今後の課題

以下、今後、クリアしたい課題について、整理します

- 信号が多い交差点などで、進行方向の信号と、その他の信号をどう見分けるか
    - 実際に検証したところ、胸ポケットに入れての運用の場合、体の向きを進行方向と考えた場合、ほぼほぼ一致するが、奥の信号や、隣の信号がフレーム内に入り、検知されるケースはあった。
        - 検知された信号の中から、最も大きいサイズのものを一旦、進行方向の信号として、処理しているが、この方法で問題となるケースがないか検証の必要がある

- 信号機の青信号の確保値の記録に関して、信号が変わるのを何回も待って、記録する必要がある
    - アプリを公開する際には、位置情報から、他の利用者の記録した青信号の確保値を参照できるようにするなど、考慮が必要
        - 警察でこういうデータ公開してくれないだろうか、難しい気もする

- 事故にもかかわることなので、検証をどれくらいしたら、公開しても良いのか、判断が難しい
    - 自分の住んでいる地域以外でも問題ないかの確認は必要
    - 上記の通り、判断の基準が難しい、１００％に限りなく近い、青信号の通知が必要と思っています

- スマホの電池をとてもとても使う
    - これは、もう少し効率化できる（検知の適切な間隔など）と思うので、考えます
        - 省エネ運用にして、検知精度を落とすのは絶対に避けなければならないです、難しい。。


# 最後に

記事読んでいただき、ありがとうございます。
上記の通り、まだまだ、改善ポイントはあると思いますので、継続して取り組んでいきます。

LITALICOでは、現在、上記のような分野は、直接、取り組めていない部分もあるのですが、
ゆくゆくは、LITALICOとして、実現したい未来のため、取り組むタイミングが来るんじゃないかなと勝手に思っています。また、現在も、いろいろな事業を通じて、安定してサービス提供しながら、障がいのない社会の実現に向けて取り組んでいます。

少しでも、興味を持っていただいた方いらっしゃいましたら、ぜひ、[採用情報](https://litalico.co.jp/recruit/)からお問い合わせください。私は、こういう分野が大好きなので、一緒に話ができる方が更に増えれば、とても嬉しいです。