[iOS 11][Vision] QR コードを検出する

ios11_400x400

Vision で QR コードを読み取る

今回は iOS 11 からの新フレームワーク Vision を利用して QR コードを読み取ってみようと思います。
Vision の概要に関しては以下の記事をご覧ください。

[iOS 11] 画像解析フレームワークVisionで顔認識を試した結果

実行動画

1

QR コードを検出すると画面中央にその内容を表示するアプリを作りました。

どういうわけかプログラムを実行しながらの動画撮影が上手くできませんでした。
画像処理で負荷がかかっているため処理落ちしているのでしょうか?
実際はスムーズに QR コードが検知できているので、その動作を見てみたい場合は以下を参考にアプリを作成してみてください。

サンプルコード

ほとんどは以前書いたコードの流用です。
変更点のみを記載します。

private var textLayer: CATextLayer! = nil
private func setupTextLayer() {
    let textLayer = CATextLayer()
    textLayer.contentsScale = UIScreen.main.scale
    textLayer.fontSize = 20
    textLayer.alignmentMode = kCAAlignmentCenter
    textLayer.frame = CGRect(x: 0, y: 0, width: 300, height: 24)
    textLayer.cornerRadius = 4
    textLayer.backgroundColor = UIColor(white: 0.25, alpha: 0.5).cgColor
    textLayer.position = self.view.center
    textLayer.isHidden = true
    self.previewLayer.addSublayer(textLayer)
    self.textLayer = textLayer
}

QR コード検出時に画面中央に表示されるテキストレイヤーです。
viewDidLoad() で一度だけ呼び出します。

override func viewDidLoad() {
    super.viewDidLoad()
    setup()
}
private func setup() {
    setupVideoProcessing()
    setupCameraPreview()
    setupTextLayer()
}

setupVideoProcessing()setupCameraPreview() は AVFoundation フレームワークでカメラを起動するための初期化処理を行っています。
内部の処理は こちらサンプルコード(オブジェクトトラッキング) を参照してください。

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
    guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
        return
    }

    let handler = VNSequenceRequestHandler()
    let barcodesDetectionRequest = VNDetectBarcodesRequest(completionHandler: self.handleBarcodes)

    try? handler.perform([barcodesDetectionRequest], on: pixelBuffer)
}

こちらは新たなビデオフレームが書き込むたびに呼び出されるデリゲートメソッドです。
バーコード検出用のハンドラとリクエスト(VNDetectBarcodesRequest)を作成し、解析処理を実行しています。

private func handleBarcodes(request: VNRequest, error: Error?) {
    guard let barcode = request.results?.first as? VNBarcodeObservation else {
        DispatchQueue.main.async {
            self.textLayer.isHidden = true
        }
        return
    }

    if let value = barcode.payloadStringValue {
        DispatchQueue.main.async {
            self.textLayer.string = value
            self.textLayer.isHidden = false
        }
    }
}

リクエスト生成時の第二引数に渡すクロージャです。
バーコードを検出した際に呼び出されます。
ここで、VNBarcodeObservation から検出した文字列 payloadStringValue を画面中央に表示するという処理を行っています。

以上です。
やはり重要なのは Request, RequestHandler, Observation という 3 つのクラスで、これらの基本さえおさえておけば応用のプログラムを書くのは簡単ですね。

リンク

ミレニアム・ファルコン製作日記 #88

88 号 表紙

mfd_88_1

パーツ

mfd_88_2

mfd_88_3

mfd_88_4

成果

mfd_88_5

mfd_88_6

今回の作業は以下の 2 つでした。

  • ドライブ・ハウジングを組み立てる
  • ドライブ・ハウジングを取り付ける

ドライブ・ハウジングの組み立てと亜光速ドライブ LED ストリップの取り付け、作動テストを行いました。
船体後方に取り付け、問題なく LED が点灯することを確認しました。
おそらくここには青色のカバーを取り付けることになると思います。
これで初めてタトゥイーンから飛び立ったときのように、このミレニアム・ファルコンも優雅にエンジン光を輝かせるでしょう。

それではまた次回。

May the Force be with you!