Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read QR code from static image

Tags:

I know that you can use AVFoundation to scan a QR code using the device's camera. Now here comes the problem, how can I do this from an static UIImage object?

like image 935
Tom Shen Avatar asked Mar 12 '16 10:03

Tom Shen


People also ask

Can I read a QR code from an image?

While you can use your camera to scan QR codes that aren't on your phone, you'll need to install an app to read QR codes from existing pictures. Fortunately, the best QR code apps are free and super easy to use!

How do I redirect an existing static QR code?

Can Static QR Code be edited or redirected to a new URL? Unfortunately, Static QR Codes can't be edited or redirected to a new URL once they are finalized. This is why we recommend choosing a Dynamic QR Code solution so that there is always the option to update the content later.


2 Answers

Swift 4 version of @Neimsz'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 } 

How to use

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

And during the execution this doesn't produce the Finalizing CVPixelBuffer 0x170133e20 while lock count is 1

I used the following QRCode Image (QRCode = https://jingged.com)

(Tested on iPhone 6 simulator with iOS version 11.2)

enter image description here

Output:

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 
like image 115
Sahil Avatar answered Oct 10 '22 05:10

Sahil


The iOS API provides the CIDetector class from CoreImage framework. CIDetector let you find specific patterns in images, like faces, smiles, eyes, or in our case : QRCodes.

Here is the code to detect a QRCode from an UIImage in Objective-C:

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

The returned NSArray* will contain CIFeature* if a QRCode is present and detected. If there was no QRCode, the NSArray* will be nil. If the QRCode decoding fails, the NSArray* will have no element.

To obtain the encoded string :

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

As in the answer of @Duncan-C, you can then extract QRCode corners and draw an enclosing bounding box of the QRCode on the image.

Note : Under iOS10.0 beta 6, the call to [qrDetector featuresInImage:ciImage options:options] when using images coming from the cameraSampleBuffer logs this internal warning (it runs smoothly but spam the console with this message, and I could not find a way to get rid of it for now):

Finalizing CVPixelBuffer 0x170133e20 while lock count is 1.

Source :

Apple Dev API Reference - CIDetector

Apple Dev API Programming guide - Face detection

like image 33
Neimsz Avatar answered Oct 10 '22 03:10

Neimsz