[iOS] AVFoundation(AVCaptureMetadataOutput)でQRコードリーダーを作ってみた
1 はじめに
本記事は、AVFoundationを使用したQRコードの読み取りを紹介するものです。
AVFoundationを使用する場合の共通的な処理については下記に纏めましたので、是非、ご参照下さい。
[iOS] AVFundationを使用して、「ビデオ録画」や「連写カメラ」や「QRコードリーダー」や「バーコードリーダー」を作ってみた
2 入出力
QRコードの読み取りを実装する場合、入力として、カメラ(今回は背面)を使用し、出力として、メタデータであるAVCaptureMetadataOutputを設定します。
下記のコードは、セッションを生成して、上記のとおり入出力をセットしている例です。
// セッションのインスタンス生成 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を使用してメータデータを検出した場合、その検出位置を取得することが出来ます。
本サンプルでは、予めマーカとなるビューを作成しています。
// 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コードを検出した時点で、ビューとして生成しているAVCaptureVideoPreviewLayerのtransformedMetadataObjectメソッドでメタデータのレイヤ座標に変換し、マーカの位置を変更しています。
// 検出位置を取得 let barCode = videoLayer?.transformedMetadataObject(for: metadata) as! AVMetadataMachineReadableCodeObject qrView!.frame = barCode.bounds
4 動作確認
実際に動作している様子です。
QR Code Generatorのページを見ています。
5 最後に
今回は、QRコードの読み込みを書いてみましたが、AVCaptureMetadataOutputを使用すると、極めて簡単な事が分かりました。
動作している様子を見ていただくと分かるのですが、画面全体が、検出対象になっているので、少し、操作性が悪いかもしれません。検出範囲の指定については、「バーコードの読み取り」の方でやってみたいと思います。
コードは下記に置いています。気になるところが有りましたら、ぜひ教えてやってください。
[GitHub] https://github.com/furuya02/AVCaptureMetadataOutputSample_QRCodeReader
アイコンは、下記のものを利用させて頂きました。
http://jp.freepik.com/
6 参考資料
API Reference AVCaptureMetadataOutput
[iOS] AVFundationを使用して、「ビデオ録画」や「連写カメラ」や「QRコードリーダー」や「バーコードリーダー」を作ってみた