AV Foundation camera scan within box

1.9k Views Asked by At

enter image description here

I am able to scan barcode with full camera resolution successfully but i want that it should scan barcodes only within a particular frame(box which is centrally placed). if barcode lies outside that frame it should not scan.

var session         : AVCaptureSession = AVCaptureSession()
    var previewLayer    : AVCaptureVideoPreviewLayer!
    var highlightView   : UIView = UIView()

func opencamera()
    {
      if session.running
        {

        }
        else
        {
            session = AVCaptureSession()

            // Set the captureDevice.

            let videoCaptureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)

            session.sessionPreset = AVCaptureSessionPresetInputPriority
            // Create input object.
            let videoInput: AVCaptureDeviceInput?

            do {
                videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
            } catch {
                return
            }

            // Add input to the session.
            if (session.canAddInput(videoInput)) {
                session.addInput(videoInput)
            } else {
                scanningNotPossible()
            }
            let metadataOutput = AVCaptureMetadataOutput()

            // Add output to the session.
            if (session.canAddOutput(metadataOutput)) {
                session.addOutput(metadataOutput)

                // Send captured data to the delegate object via a serial queue.
                metadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())

                // Set barcode type for which to scan: EAN-13.
                //metadataOutput.metadataObjectTypes = metadataOutput.availableMetadataObjectTypes
                metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeUPCECode,
                                                      AVMetadataObjectTypeCode39Code,
                                                      AVMetadataObjectTypeCode39Mod43Code,
                                                      AVMetadataObjectTypeEAN13Code,
                                                      AVMetadataObjectTypeEAN8Code,
                                                      AVMetadataObjectTypeCode93Code,
                                                      AVMetadataObjectTypeCode128Code,
                                                      AVMetadataObjectTypePDF417Code,

                ]

            } else {
                scanningNotPossible()
            }
            previewLayer = AVCaptureVideoPreviewLayer(session: session);
            previewLayer.frame = self.view.frame

            previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
            previewLayer?.position = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds))
                           image.layer.addSublayer(previewLayer);
                            session.startRunning()
        }
    }
    func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {

        //var highlightViewRect = CGRectZero

        // var barCodeObject : AVMetadataObject!

        var detectionString : String!

        let barCodeTypes = [AVMetadataObjectTypeUPCECode,
                            AVMetadataObjectTypeCode39Code,
                            AVMetadataObjectTypeCode39Mod43Code,
                            AVMetadataObjectTypeEAN13Code,
                            AVMetadataObjectTypeEAN8Code,
                            AVMetadataObjectTypePDF417Code,
                            ]


        // The scanner is capable of capturing multiple 2-dimensional barcodes in one scan.
        for metadata in metadataObjects {

            for barcodeType in barCodeTypes {


                let decodedData:  AVMetadataMachineReadableCodeObject =  metadata as! AVMetadataMachineReadableCodeObject
                if metadata.type == barcodeType {

                                           detectionString = (metadata as! AVMetadataMachineReadableCodeObject).stringValue
                    if(metadata.type  == AVMetadataObjectTypeEAN13Code){
                        if (detectionString.hasPrefix("0") && detectionString.characters.count > 1){
                            detectionString = String(detectionString.characters.dropFirst())
                        }

                    }
                    AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
                    self.session.stopRunning()

                    break
                }



            }
        }

        print(detectionString)

        self.previewLayer.removeFromSuperlayer()
        self.highlightView.removeFromSuperview()

    }
1

There are 1 best solutions below

0
On

Try setting a rectOfInterest for your AVCaptureMetaDataOutput.

self.metadataOutput.rectOfInterest = [self.previewLayer metadataOutputRectOfInterestForRect:myRectOfInterest];

As per documentation

rectOfInterest A rectangle of interest for limiting the search area for visual metadata.

The value of this property is a CGRect value that determines the object’s rectangle of interest for each frame of video.

The rectangle's origin is top left and is relative to the coordinate space of the device providing the metadata.

Specifying a rectangle of interest may improve detection performance for certain types of metadata. Metadata objects whose bounds do not intersect with the rectOfInterest will not be returned.

The default value of this property is a rectangle of (0.0, 0.0, 1.0, 1.0).

Note that the value is not your pixels. Take a look at SO answers here and here for more info.