4

I'm currently trying to use iOS 7's newest api's to scan code 39 barcodes, but it's driving me crazy. I have to hold the phone a specific way really still for like 10 seconds in order for it to detect it. I compared it to Red Laser, Zbar, etc and they could analyze it in 1 second even if it was a little skewed. I'm not sure if it's because of the way that I load my capture session or what. I'd appreciate the help. Any suggestions on how to improve performance?

Here's how I load the scanner in my viewDidLoad method:

    //Initialize Laser View
    laserView = [[UIView alloc] init];
    laserView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleBottomMargin;
    laserView.layer.borderColor = [UIColor redColor].CGColor;
    laserView.layer.borderWidth = 8;
    laserView.layer.cornerRadius = 10;
    [self.view addSubview:laserView];

    //Start Session
    scannerSession = [[AVCaptureSession alloc] init];
    scannerDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    //Define Error Messages
    NSError *error = nil;

    //Define Input
    scannerInput = [AVCaptureDeviceInput deviceInputWithDevice:scannerDevice error:&error];

    //Check if Device has a Camera
    if (scannerInput) {
        [scannerSession addInput:scannerInput];
    } else {
        NSLog(@"Error: %@", error);
    }

    // Locks the configuration
    BOOL success = [scannerDevice lockForConfiguration:nil];
    if (success) {
        if ([scannerDevice isAutoFocusRangeRestrictionSupported]) {

            // Restricts the autofocus to near range (new in iOS 7)
            [scannerDevice setAutoFocusRangeRestriction:AVCaptureAutoFocusRangeRestrictionNear];
        }
    }
    // unlocks the configuration
    [scannerDevice unlockForConfiguration];

    //Define Output & Metadata Object Types
    scannerOutput = [[AVCaptureMetadataOutput alloc] init];
    [scannerOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
    [scannerSession addOutput:scannerOutput];
    scannerOutput.metadataObjectTypes = [scannerOutput availableMetadataObjectTypes];

    //Create Video Preview Layer
    scannerPreviewLayer = [AVCaptureVideoPreviewLayer layerWithSession:scannerSession];
    scannerPreviewLayer.frame = self.view.bounds;
    scannerPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.view.layer addSublayer:scannerPreviewLayer];

    //Start Session
    [scannerSession startRunning];
    [self.view bringSubviewToFront:cancelButton];
    [self.view bringSubviewToFront:laserView];

And:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {

    //Prepare Laser View
    CGRect laser = CGRectZero;

    //Format Date
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"M/d"];

    //Format Time
    NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
    [timeFormatter setDateFormat:@"h:ma"];

    //Define Barcode Types to Recognize
    AVMetadataMachineReadableCodeObject *barCodeObject;
    NSString *idNumber = nil;
    NSArray *barCodeTypes = @[AVMetadataObjectTypeCode39Code];

    if ([metadataObjects count] > 1) {

        NSLog(@"%lu Barcodes Found.", (unsigned long)[metadataObjects count]);

    }

    //Get String Value For Every Barcode (That Matches The Type We're Looking For)
    for (AVMetadataObject *metadata in metadataObjects) {


        for (NSString *type in barCodeTypes) {


            //If The Barcode Is The Type We Need Then Get Data
            if ([metadata.type isEqualToString:type]) {

                barCodeObject = (AVMetadataMachineReadableCodeObject *)[scannerPreviewLayer transformedMetadataObjectForMetadataObject:(AVMetadataMachineReadableCodeObject *)metadata];
                laser = barCodeObject.bounds;
                idNumber = [(AVMetadataMachineReadableCodeObject *)metadata stringValue];
                break;
            }
        }

        // If IDNumber Found
        if (idNumber != nil) {

            //Stop Session
            [scannerSession stopRunning];
            [self vibrate];

            NSLog(@"ID: %@", idNumber);

            break;
        }

        //If IDNumber Is Not Found
        else {

            NSLog(@"No ID Found.");
        }
    }

    //Update Laser
    laserView.frame = laser;
}
KingPolygon
  • 4,753
  • 7
  • 43
  • 72

4 Answers4

1

I had a similar problem with the AVCaptureSession, the capture was very slow and sometimes it took long time to finish it.

Don't know if my solution is the one that is good for you but definetly can be helpfull to somebody else looking for this problem, like i did.

AVCaptureSession *captureSession = [AVCaptureSession new];
captureSession.sessionPreset = AVCaptureSessionPresetHigh;

With this code you force the camera to a high quality preset.

Hope this will help someone.

MajinDageta
  • 250
  • 3
  • 14
1

Try zooming in a little... videoDevice.videoZoomFactor = 2.0;

MichaelG
  • 103
  • 1
  • 8
0

A lot of it has to do with the quality of the image (focus, glare, lighting, etc.) Under really good conditions, you should get scanning that is nearly instantaneous.

Senseful
  • 86,719
  • 67
  • 308
  • 465
0

I suggested you put a NSLog in your delegate function captureOutput:

You will see that it gets called many times just for scanning a barcode once. Initializing NSDateFormatter is a very expensive operation per Why is allocating or initializing NSDateFormatter considered "expensive"?.

I would suggest that you create the NSDateFormatter outside of the delegate function and re-use it instead of creating it every time the function is called. This should make your app more responsive.

Community
  • 1
  • 1
Laurent Rivard
  • 509
  • 4
  • 13