如何从静态图像中读取QR码

Tom*_*hen 9 qr-code ios

我知道您可以使用AVFoundation设备的相机扫描QR码.现在问题来了,我怎样才能从静态UIImage对象中做到这一点?

Nei*_*msz 10

iOS API提供CoreImage框架中的CIDetector类.CIDetector可让您在图像中找到特定的图案,如面部,微笑,眼睛,或者在我们的案例中:QRCodes.

以下是在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 = UIImage.CIImage; // assuming underlying data is a CIImage
        //CIImage* ciImage = [CIImage initWithCGImage: UIImage.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;

    }
}
Run Code Online (Sandbox Code Playgroud)

如果存在并检测到QRCode,则返回的内容NSArray*将包含CIFeature*.如果没有QRCode,那NSArray*将是nil.如果QRCode解码失败,则NSArray*没有元素.

要获取编码的字符串:

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

在@ Duncan-C的答案中,您可以提取QRCode角并在图像上绘制QRCode的封闭边界框.

注意: 在iOS10.0 beta 6下,[qrDetector featuresInImage:ciImage options:options]使用来自cameraSampleBuffer的图像时的调用会记录此内部警告(它运行顺利,但是使用此消息向控制台发送垃圾邮件,我现在找不到摆脱它的方法) :

锁定计数为1时,最终确定CVPixelBuffer 0x170133e20.

资源 :

Apple Dev API参考 - CIDetector

Apple Dev API编程指南 - 人脸检测

  • 我发现调用CVPixelBufferLockBaseAddress(..)并忘记调用CVPixelBufferUnlockBaseAddress(..)会导致该警告("最终确定CVPixelBuffer ......锁定计数为1".我的猜测是QR代码库在某处执行此操作在他们的AV处理. (5认同)

Dun*_*n C 8

芯的图像具有CIDetector类,与CIDetectorTypeQRCode用于检测QR码.您可以为静止图像或视频提供Core Image滤镜.

那应该满足你的需求.有关详细信息,请参阅Xcode文档.

来自ShinobiControls的每天iOS8Github回购包括一个LiveDetection项目,该项目展示了如何从视频源和静止图像中使用CIDetectorTypeQRCode.看起来它还没有针对Swift 2.0进行更新,我无法在Xcode 7.2.1下进行编译,但performQRCodeDetection项目中的函数已经编译完成.(编译问题是使用代码处理CVPixelBuffersSwift中必须处理的所有可怕的类型转换,如果您想要做的只是在静态图像中找到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)
}
Run Code Online (Sandbox Code Playgroud)


Sha*_*ali 8

关于返回测试消息,这里的答案都不是非常简单的。做了一个对我来说很好用的小扩展:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Sah*_*nda 7

@Neimsz的答案的 Swift 4版本

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
    }
Run Code Online (Sandbox Code Playgroud)

如何使用

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

在执行过程中不会产生 Finalizing CVPixelBuffer 0x170133e20 while lock count is 1

我使用了以下QRCode图像(QRCode = https://jingged.com

(在具有iOS版本11.2的iPhone 6模拟器上进行了测试)

在此处输入图片说明

输出:

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
Run Code Online (Sandbox Code Playgroud)


Ale*_*nko 5

如果你只需要一个字符串,你可以使用这样的代码:

class QRToString {

    func string(from image: UIImage) -> String {

        var qrAsString = ""
        guard let detector = CIDetector(ofType: CIDetectorTypeQRCode,
                                        context: nil,
                                        options: [CIDetectorAccuracy: CIDetectorAccuracyHigh]),
            let ciImage = CIImage(image: image),
            let features = detector.features(in: ciImage) as? [CIQRCodeFeature] else {
                return qrAsString
        }

        for feature in features {
            guard let indeedMessageString = feature.messageString else {
                continue
            }
            qrAsString += indeedMessageString
        }

        return qrAsString
    }
}
Run Code Online (Sandbox Code Playgroud)


Bad*_*hah 2

使用Zbar SDK从静态图像中读取QRcode。

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. 
}
Run Code Online (Sandbox Code Playgroud)

下面的链接将为您提供帮助。

使用 ios-zbar-sdk 扫描静态 uiimage