[iOS] AVFoundation(AVCaptureMetadataOutput)でQRコードリーダーを作ってみた

[iOS] AVFoundation(AVCaptureMetadataOutput)でQRコードリーダーを作ってみた

Clock Icon2017.01.04

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

本記事は、AVFoundationを使用したQRコードの読み取りを紹介するものです。

AVFoundationを使用する場合の共通的な処理については下記に纏めましたので、是非、ご参照下さい。
[iOS] AVFundationを使用して、「ビデオ録画」や「連写カメラ」や「QRコードリーダー」や「バーコードリーダー」を作ってみた

2 入出力

QRコードの読み取りを実装する場合、入力として、カメラ(今回は背面)を使用し、出力として、メタデータであるAVCaptureMetadataOutputを設定します。 001

下記のコードは、セッションを生成して、上記のとおり入出力をセットしている例です。

// セッションのインスタンス生成
let captureSession = AVCaptureSession()

// 入力(背面カメラ)
let videoDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
let videoInput = try! AVCaptureDeviceInput.init(device: videoDevice)
captureSession.addInput(videoInput)

// 出力(メタデータ)
let metadataOutput = AVCaptureMetadataOutput()
captureSession.addOutput(metadataOutput)

3 AVCaptureMetadataOutput

AVCaptureMetadataOutputオブジェクトは、指定されたメタデータ検出し、その処理のためにデリゲートに転送します。

(1)metadataObjectTypes

検出対象のメタデータのタイプは、metadataObjectTypesプロパティに指定します。

指定できるタイプは、下記のとおりです。

NSString 種類
AVMetadataObjectTypeUPCECode UPC-E コード
AVMetadataObjectTypeCode39Code Code 39 コード
AVMetadataObjectTypeCode39Mod43Code Code 39 mod 43 コード
AVMetadataObjectTypeEAN13Code EAN-13 (including UPC-A) コード(JANコード標準タイプ)
AVMetadataObjectTypeEAN8Code EAN-8 コード(JANコード短縮タイプ)
AVMetadataObjectTypeCode93Code Code 93 コード
AVMetadataObjectTypeCode128Code Code 128 コード
AVMetadataObjectTypePDF417Code PDF417 コード
AVMetadataObjectTypeQRCode QR コード
AVMetadataObjectTypeAztecCode Aztec コード
AVMetadataObjectTypeInterleaved2of5Code Interleaved 2 of 5 コード
AVMetadataObjectTypeITF14Code ITF14 コード
AVMetadataObjectTypeDataMatrixCode DataMatrix コード

参考:Machine Readable Object Types

このプロパティに新しい配列を割り当てる場合、availableMetadataObjectTypesプロパティによって返される配列に存在するものしか指定できません。

if 0 < (metadataOutput.availableMetadataObjectTypes as! [String]).index(of: AVMetadataObjectTypeQRCode)! {
    metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode]
}

後に出てくる、captureOutput(_:didOutputMetadataObjects:from :)メソッド内では、オブジェクトの種類が分かりますので、ここでは、availableMetadataObjectTypesをそのまま設定しておいても良いかもしれません。

metadataOutput.metadataObjectTypes = metadataOutput.availableMetadataObjectTypes

(2) setMetadataObjectsDelegate(_:queue:)

メタデータを検出時の処理するためのデリゲートとディスパッチキューの設定は、setMetadataObjectsDelegate(_:queue:)メソッドを使用します。

第1パラメータにはメタデータが検出された際に通知するデリゲートオブジェクトを指定します。なお、このオブジェクトは、AVCaptureMetadataOutputObjectsDelegateプロトコルを実装している必要があります。

また、ディスパッチキューについては、受信された順序でメタデータオブジェクトが確実に配信されるように、シリアルキューである必要があります。

// QRコードを検出した際のデリゲート設定
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)

メタデータ検出時には、captureOutput(_:didOutputMetadataObjects:from:)がコールされます。

なお、検出されたメタデータは、配列で提供されます。この中で、目的のタイプであるかを確認して処理することになります。

検出された、AVMetadataMachineReadableCodeObjectクラスはAVMetadataObjectクラスのサブクラスであり、 そのプロパティであるstringValueにQRコードに格納された文字列が取得できます。

func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
    // 複数のメタデータを検出できる
    for metadata in metadataObjects as! [AVMetadataMachineReadableCodeObject] {
        // QRコードのデータかどうかの確認
        if metadata.type == AVMetadataObjectTypeQRCode {
            if metadata.stringValue != nil {
                // 検出データを取得
                textField.text = metadata.stringValue!
            }
        }
    }
}

(3)検出位置

AVCaptureMetadataOutputを使用してメータデータを検出した場合、その検出位置を取得することが出来ます。

002

本サンプルでは、予めマーカとなるビューを作成しています。

// QRコードをマークするビュー
qrView = UIView()
qrView.layer.borderWidth = 4
qrView.layer.borderColor = UIColor.red.cgColor
qrView.frame = CGRect(x: 0, y: 0, width: 0, height: 0)
view.addSubview(qrView)

そして、QRコードを検出した時点で、ビューとして生成しているAVCaptureVideoPreviewLayertransformedMetadataObjectメソッドでメタデータのレイヤ座標に変換し、マーカの位置を変更しています。

// 検出位置を取得
let barCode = videoLayer?.transformedMetadataObject(for: metadata) as! AVMetadataMachineReadableCodeObject
qrView!.frame = barCode.bounds

4 動作確認

実際に動作している様子です。


QR Code Generatorのページを見ています。

5 最後に

今回は、QRコードの読み込みを書いてみましたが、AVCaptureMetadataOutputを使用すると、極めて簡単な事が分かりました。

動作している様子を見ていただくと分かるのですが、画面全体が、検出対象になっているので、少し、操作性が悪いかもしれません。検出範囲の指定については、「バーコードの読み取り」の方でやってみたいと思います。

コードは下記に置いています。気になるところが有りましたら、ぜひ教えてやってください。
github [GitHub] https://github.com/furuya02/AVCaptureMetadataOutputSample_QRCodeReader

アイコンは、下記のものを利用させて頂きました。
http://jp.freepik.com/

6 参考資料


API Reference AVCaptureMetadataOutput
[iOS] AVFundationを使用して、「ビデオ録画」や「連写カメラ」や「QRコードリーダー」や「バーコードリーダー」を作ってみた

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.