How do I use the metadataOutputRectOfInterestForRect method and rectOfInterest property to scan a specific area? (QR Code)

前端 未结 8 1939
时光说笑
时光说笑 2020-12-04 18:00

I am building a QR code scanner with Swift and everything works in that regard. The issue I have is that I am trying to make only a small area of the entire visible A

相关标签:
8条回答
  • 2020-12-04 18:34

    In iOS 9.3.2 I was able to make metadataoutputRectOfInterestForRect work calling it right after startRunning method of AVCaptureSession:

    captureSession.startRunning()
    let visibleRect = previewLayer.metadataOutputRectOfInterestForRect(previewLayer.bounds)
    captureMetadataOutput.rectOfInterest = visibleRect
    
    0 讨论(0)
  • 2020-12-04 18:36

    /// After

    captureSession.startRunning()
    

    /// Add this

    if let videoPreviewLayer = self.videoPreviewLayer {
    self.captureMetadataOutput.rectOfInterest =
    videoPreviewLayer.metadataOutputRectOfInterest(for:
    self.getRectOfInterest())
    
    
    fileprivate func getRectOfInterest() -> CGRect {
            let centerX = (self.frame.width / 2) - 100
            let centerY = (self.frame.height / 2) - 100
            let quadr: CGFloat = 200
    
            let myRect = CGRect(x: centerX, y: centerY, width: quadr, height: quadr)
    
            return myRect
        }
    
    0 讨论(0)
  • 2020-12-04 18:40

    I managed to create an effect of having a region of interest. I tried all the proposed solutions but the region was either a CGPoint.zero or had inappropriate size (after converting frames to a 0-1 coordinate). It's actually a hack for those who can't get the regionOfInterest to work and doesn't optimize the detection.

    In:

    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) 
    

    I have the following code:

    let visualCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj)
    if self.viewfinderView.frame.contains(visualCodeObject.bounds) { 
        //visual code is inside the viewfinder, you can now handle detection
    }
    
    0 讨论(0)
  • 2020-12-04 18:41

    I know there are already solutions present and it's pretty late but i achieved mine by capturing the complete view image and then cropping it with specific rect.

     func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
    
    if let imageData = photo.fileDataRepresentation() {
        print(imageData)
        capturedImage = UIImage(data: imageData)
    
        var crop = cropToPreviewLayer(originalImage: capturedImage!)
    
        let sb = UIStoryboard(name: "Main", bundle: nil)
        let s = sb.instantiateViewController(withIdentifier: "KeyFobScanned") as! KeyFobScanned
        s.image = crop
        self.navigationController?.pushViewController(s, animated: true)
    
    }
    }
    
    private func cropToPreviewLayer(originalImage: UIImage) -> UIImage? {
    guard let cgImage = originalImage.cgImage else { return nil }
    
    let scanRect = CGRect(x: stackView.frame.origin.x, y: stackView.frame.origin.y, width: innerView.frame.size.width, height: innerView.frame.size.height)
    
    let outputRect = videoPreviewLayer.metadataOutputRectConverted(fromLayerRect: scanRect)
    
    let width = CGFloat(cgImage.width)
    let height = CGFloat(cgImage.height)
    
    let cropRect = CGRect(x: outputRect.origin.x * width, y: outputRect.origin.y * height, width: outputRect.size.width * width, height: outputRect.size.height * height)
    
    if let croppedCGImage = cgImage.cropping(to: cropRect) {
        return UIImage(cgImage: croppedCGImage, scale: 1.0, orientation: originalImage.imageOrientation)
    }
    
    return nil
    }
    
    0 讨论(0)
  • 2020-12-04 18:43

    To read a QRCode/BarCode from a small rect(specific region) from a full camera view.

    <br> **Mandatory to keep the below line after (start running)** <br>
    [captureMetadataOutput setRectOfInterest:[_videoPreviewLayer metadataOutputRectOfInterestForRect:scanRect] ];
    
    [_captureSession startRunning];
    [captureMetadataOutput setRectOfInterest:[_videoPreviewLayer metadataOutputRectOfInterestForRect:scanRect] ];
    

    Note:

    1. captureMetadataOutput --> AVCaptureMetadataOutput
    2. _videoPreviewLayer --> AVCaptureVideoPreviewLayer
    3. scanRect --> Rect where you want the QRCode to be read.
    0 讨论(0)
  • 2020-12-04 18:44

    I wrote the following:

    videoPreviewLayer?.frame = view.layer.bounds
    videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
    

    And this worked for me, but I still don't know why.

    0 讨论(0)
提交回复
热议问题