web-dev-qa-db-ja.com

静止画像からQRコードを読み取る方法

AVFoundationを使用して、デバイスのカメラでQRコードをスキャンできることを知っています。ここで問題が発生しました。静的UIImageオブジェクトからこれを行うにはどうすればよいですか?

11
Tom Shen

IOS APIは、CoreImageフレームワークからCIDetectorクラスを提供します。 CIDetectorを使用すると、顔、笑顔、目、または私たちの場合はQRコードなど、画像内の特定のパターンを見つけることができます。

Objective-CのUIImageからQRCodeを検出するコードは次のとおりです。

-(NSArray *)detectQRCode:(UIImage *) image
{
    @autoreleasepool {
        NSLog(@"%@ :: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
        NSCAssert(image != nil, @"**Assertion Error** detectQRCode : image is nil");

        CIImage* ciImage = image.CIImage; // assuming underlying data is a CIImage
        //CIImage* ciImage = [[CIImage alloc] initWithCGImage: image.CGImage];
        // to use if the underlying data is a CGImage

        NSDictionary* options;
        CIContext* context = [CIContext context];
        options = @{ CIDetectorAccuracy : CIDetectorAccuracyHigh }; // Slow but thorough
        //options = @{ CIDetectorAccuracy : CIDetectorAccuracyLow}; // Fast but superficial

        CIDetector* qrDetector = [CIDetector detectorOfType:CIDetectorTypeQRCode
                                                    context:context
                                                    options:options];
        if ([[ciImage properties] valueForKey:(NSString*) kCGImagePropertyOrientation] == nil) {
            options = @{ CIDetectorImageOrientation : @1};
        } else {
            options = @{ CIDetectorImageOrientation : [[ciImage properties] valueForKey:(NSString*) kCGImagePropertyOrientation]};
        }

        NSArray * features = [qrDetector featuresInImage:ciImage
                                                 options:options];

        return features;

    }
}

QRCodeが存在し検出された場合、返されたNSArray*にはCIFeature*が含まれます。 QRCodeがない場合、NSArray*nilになります。 QRCodeのデコードが失敗した場合、NSArray*には要素がありません。

エンコードされた文字列を取得するには:

if (features != nil && features.count > 0) {
    for (CIQRCodeFeature* qrFeature in features) {
        NSLog(@"QRFeature.messageString : %@ ", qrFeature.messageString);
    }
}

@ Duncan-Cの回答のように、QRCodeのコーナーを抽出して、QRCodeを囲むバウンディングボックスを画像上に描画できます。

注:iOS10.0ベータ6では、cameraSampleBufferからの画像を使用する場合の[qrDetector featuresInImage:ciImage options:options]の呼び出しにより、この内部警告がログに記録されます(スムーズに実行されます)しかし、このメッセージでコンソールをスパムし、私は今のところそれを取り除く方法を見つけることができませんでした):

ロックカウントが1のときのCVPixelBuffer 0x170133e20のファイナライズ。

出典:

Apple Dev APIリファレンス-CIDetector

Apple Dev APIプログラミングガイド-顔検出

11
Neimsz

@NeimszのSwift 4バージョン answer

func detectQRCode(_ image: UIImage?) -> [CIFeature]? {
        if let image = image, let ciImage = CIImage.init(image: image){
            var options: [String: Any]
            let context = CIContext()
            options = [CIDetectorAccuracy: CIDetectorAccuracyHigh]
            let qrDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: context, options: options)
            if ciImage.properties.keys.contains((kCGImagePropertyOrientation as String)){
                options = [CIDetectorImageOrientation: ciImage.properties[(kCGImagePropertyOrientation as String)] ?? 1]
            }else {
                options = [CIDetectorImageOrientation: 1]
            }
            let features = qrDetector?.features(in: ciImage, options: options)
            return features

        }
        return nil
    }

使い方

if let features = detectQRCode(#imageLiteral(resourceName: "qrcode")), !features.isEmpty{
            for case let row as CIQRCodeFeature in features{
                    print(row.messageString ?? "nope")
                }
        }

そして実行中にこれはFinalizing CVPixelBuffer 0x170133e20 while lock count is 1を生成しません

次のQRCode画像を使用しました(QRCode = https://jingged.com

(iOSバージョン11.2のiPhone 6シミュレータでテスト済み)

enter image description here

出力:

2018-03-14 15:31:13.159400+0530 TestProject[25889:233062] [MC] Lazy loading NSBundle MobileCoreServices.framework
2018-03-14 15:31:13.160302+0530 TestProject[25889:233062] [MC] Loaded MobileCoreServices.framework
https://jingged.com
8
Sahil Manchanda

Core ImageにはCIDetectorクラスがあり、QRコードを検出するためのCIDetectorTypeQRCodeがあります。コアイメージフィルターには、静止画像またはビデオをフィードできます。

それはあなたのニーズを満たすはずです。詳細については、Xcodeのドキュメントを参照してください。

Github repo iOS8-day-by-day のShinobiControlsには、CIDetectorTypeQRCodeの使用方法を示すプロジェクトLiveDetectionが含まれています。ビデオフィードと静止画像から。 Swift 2.0では更新されていないようです。Xcode7.2.1でコンパイルすることはできませんでしたが、関数performQRCodeDetectionプロジェクトはコンパイルします(コンパイルの問題は、SwiftでCVPixelBuffersを処理するために処理しなければならないすべての恐ろしい型キャストを処理するコードにあります。これは、QRCodesを見つけるだけでかまいません。静止画像。)

編集:

これがそのサイトの主要なメソッドです(Swift)

func performQRCodeDetection(image: CIImage) -> (outImage: CIImage?, decode: String) {
  var resultImage: CIImage?
  var decode = ""
  if let detector = detector {
    let features = detector.featuresInImage(image)
    for feature in features as! [CIQRCodeFeature] {
      resultImage = drawHighlightOverlayForPoints(image, 
        topLeft: feature.topLeft, 
        topRight: feature.topRight,
        bottomLeft: feature.bottomLeft, 
        bottomRight: feature.bottomRight)
      decode = feature.messageString
    }
  }
  return (resultImage, decode)
}
8
Duncan C

テストメッセージを返すことに関して、ここでの答えはどれも非常に簡単ではありませんでした。私にとってうまくいく小さな拡張を作りました:

https://Gist.github.com/freak4pc/3f7ae2801dd8b7a068daa957463ac645

extension UIImage {
    func parseQR() -> [String] {
        guard let image = CIImage(image: self) else {
            return []
        }

        let detector = CIDetector(ofType: CIDetectorTypeQRCode,
                                  context: nil,
                                  options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])

        let features = detector?.features(in: image) ?? []

        return features.compactMap { feature in
            return (feature as? CIQRCodeFeature)?.messageString
        }
    }
}
3
Shai Mishali

ZbarSDKを使用して、静的画像からQRコードを読み取ります。

ZBar-SDK-iOS

Zbar SDKの起動については、このチュートリアルを確認してください。

ZBar SDK統合チュートリアル

そして、静止画像をスキャンしてみます。

Zbarスキャナークラスを使用して画像をスキャンします。

ここにドキュメントがあります。

ZBarImageScanner。

例として、Zbarスキャナークラスの使用方法、

ZBarImageScanner *scandoc = [[ZBarImageScanner alloc]init];
NSInteger resultsnumber = [scandoc scanImage:yourUIImage];
if(resultsnumber > 0){
    ZBarSymbolSet *results = scandoc.results;
    //Here you will get result. 
}

以下のリンクが役立ちます。

scaning-static-uiimage-using-ios-zbar-sdk

2
Badal Shah