iOS でカメラから QR コードを読むときに人間の感覚に近い感じで認識させたい。

概要

  • https://github.com/dnpp73/QRCodeReader を作ったときの話。
  • コンピュータが画像から QR コードを認識する早さと、人間がカメラを QR コードに向ける早さは違う。
    • 人間の動きの方が圧倒的に遅くコンピュータが認識する方が圧倒的に速いので、人間の感覚に近くなるような仕組みを作った。
  • カメラの制御コードがレガシーなのでその内直したい。
  • 一応 Swift Package Manager にも対応してある。

詳細

このライブラリが一応の完成を見たのは 2019 年の 8 月頃の話。記憶も曖昧なところがあるんだけど、その内ブログのネタにしようと思っていたら 1 年半以上経ってしまった。

時間の流れがおかしい。

実装上の工夫

iOS のカメラから得られる画像を素朴にそのまま使うと想像以上にサイズが大きい。大きいサイズのまま CIDetector に放り込んでしまうと動作がかなり重くなってしまう。

こういう場合は前処理するのが良い。画像認識させる前に縮小し、実際の認識エリアとして使う画像中央付近だけになるようにトリミングをすると、パフォーマンスとバッテリーの持ちと使い勝手のバランスが取れるようになる。

画像認識を人間の感覚に合わせる。

実際の画面を見てもらうと伝わると思うので画面収録をした。

Flicker Noise Reduction

Raw Message の部分がチラついているが Message の部分は安定しているのが見てとれると思う。

機械の気持ちと人間の気持ちはかなり違う。標準的な人間は 1 フレームだけ QR コードが写ったくらいでは反応できないが、機械からするとバッチリ判別出来てしまう。逆に機械は強めの手ブレや枠外へのフレームアウトの発生が 1 フレームであっても検出不可能になるが、人間からすると数フレーム以内に回復してくれれば認識され続けていて欲しい。

パラメタを調整しながら自分で試した経験則だが、カメラを QR コードに向けて検出をするような用途の場合は数百ミリ秒ほど遅延させてやると心地良く感じるようだ。

高周波成分を除去すれば良いのでローパスフィルタの実装をした。カメラからの入力は 30 fps 程度なので、単純な多数決アルゴリズムで実装したところ良い結果が得られたのでそのようにしている。

今後の展望

AVCaptureStillImageOutput が iOS 10 くらいのときに Deprecated になり、 AVCapturePhotoOutput を使うことが推奨されてから久しいが、iOS 14 の現在でもまだなんとか動いてくれている。その内なんとかします。

締め

このライブラリは leafee というプロダクトで使うために作ったのだが、ありがたいことに「折角なのでライブラリとして公開していいよ」とのことだったので、ペタっと MIT ライセンスを貼って日曜 OSS みたいな感じで公開している。

他にも最近 (?) 作った iOS 向けのライブラリで、 ターミナルエミュレータ を作ったときの話や、 中身の実装が秘匿されていて色々な問題を起こしがちな巨大バイナリの SDK を入れずに SNS ログインをするやつ を作ったときの話もあるんだけど、気が向いたら何か書きます。

追記 (2020/12/31)

iOS で動くターミナルエミュレータを作っていた話 を書いた。