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

时间:2016-03-12 10:34:18

标签: ios qr-code

我知道您可以使用AVFoundation使用设备的相机扫描QR码。现在出现了问题,如何从静态UIImage对象中执行此操作?

6 个答案:

答案 0 :(得分: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;

    }
}

如果存在并检测到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 beta 6下,当使用来自cameraSampleBuffer的图像时,对[qrDetector featuresInImage:ciImage options:options]的调用会记录此内部警告(它运行顺利,但是使用此消息向控制台发送垃圾邮件,我找不到摆脱它的方法现在):

  

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

来源:

Apple Dev API Reference - CIDetector

Apple Dev API Programming guide - Face detection

答案 1 :(得分:8)

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

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

来自ShinobiControls的Github repo iOS8-day-by-day包括一个项目LiveDetection,它显示如何从视频源和静止图像中使用CIDetectorTypeQRCode。看起来它还没有针对Swift 2.0进行更新,我无法在Xcode 7.2.1下进行编译,但是项目中的函数performQRCodeDetection正在编译。 (编译问题是使用代码来处理在Swift中处理CVPixelBuffers时必须处理的所有可怕的类型转换,如果您只想在静态图像中找到QRCodes,则无关紧要。)< / p>

编辑:

以下是该网站的关键方法(在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)
}

答案 2 :(得分:5)

  

Swift 4版本的@ Neimsz&#39; s 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

答案 3 :(得分:2)

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

ZBar-SDK-iOS

请查看本教程有关Zbar SDK的调查。

ZBar SDK Integration Tutorial

然后尝试扫描静态图像。

使用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

答案 4 :(得分:2)

在返回测试消息方面,这里的答案没有一个非常简单。做了一个对我来说很好的扩展:

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
        }
    }
}

答案 5 :(得分:1)

如果只需要一个字符串,则可以使用以下代码:

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
    }
}
相关问题