【问题标题】:How to detect barcode using Apple Vision in CGRect only?如何仅在 CGRect 中使用 Apple Vision 检测条形码?
【发布时间】:2021-11-21 16:53:33
【问题描述】:

我有一个应用程序,它使用 CGRect(x: 0, y: 0, width: 335, height: 150) 来显示用于条形码扫描的摄像头。但是,当在相机外(不在 CGRect 中)出现条形码时,将被扫描。如何在预览层中将扫描区域限制为 CGRect?这是使用 Vision。

let captureSession = AVCaptureSession()
var previewLayer: AVCaptureVideoPreviewLayer!
var activeInput: AVCaptureDeviceInput!

lazy var detectBarcodeRequest = VNDetectBarcodesRequest { request, error in
    guard error == nil else {
        
        print("Barcode Error: \(String(describing: error?.localizedDescription))")
    
        return
    }
    
    self.processBarCode(request)
}

override func viewDidLoad() {
    super.viewDidLoad()
    
    setupSession()
    setupPreview()
    startSession()
}

func setupSession() {
    
    guard let camera = AVCaptureDevice.default(for: .video) else {
        return
        
    }
    do {
        let videoInput = try AVCaptureDeviceInput(device: camera)
        
        for input in [videoInput] {
            if captureSession.canAddInput(input) {
                captureSession.addInput(input)
            }
        }
        activeInput = videoInput
    } catch {
        print("Error setting device input: \(error)")
        return
    }
    
    let captureOutput = AVCaptureVideoDataOutput()
    
    captureOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_32BGRA)]
    captureOutput.setSampleBufferDelegate(self, queue: DispatchQueue.global(qos: DispatchQoS.QoSClass.default))
    
    captureSession.addOutput(captureOutput)

}

func setupPreview() {
    
    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    
    previewLayer.videoGravity = .resizeAspectFill
    previewLayer.connection?.videoOrientation = .portrait
    previewLayer.frame = CGRect(x: 0, y: 0, width: 335, height: 150)
    
    view.layer.insertSublayer(previewLayer, at: 0)

}//setupPreview

func startSession() {
    if !captureSession.isRunning {
        DispatchQueue.global(qos: .default).async { [weak self] in
            self?.captureSession.startRunning()
        }
    }
}

// MARK: - processBarCode
func processBarCode(_ request: VNRequest) {
    
    
    DispatchQueue.main.async {
        guard let results = request.results as? [VNBarcodeObservation] else {
            return
        }
        
        if let payload = results.first?.payloadStringValue, let symbology = results.first?.symbology {
            print("payload is \(payload) \(symbology) ")
            
        }
        
    }
    
}//processBarCode

编辑:

// MARK: - AVCaptureVideoDataOutputSampleBufferDelegate
extension CameraViewController: AVCaptureVideoDataOutputSampleBufferDelegate {
    
    func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
        
        guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
        
        let imageRequestHandler = VNImageRequestHandler(
            cvPixelBuffer: pixelBuffer,
            orientation: .up)
        
        do {
            try imageRequestHandler.perform([detectBarcodeRequest])
        } catch {
            print(error)
        }
    }//captureOutput
    
}//extension

【问题讨论】:

    标签: ios swift barcode-scanner vision


    【解决方案1】:
    extension AVCaptureVideoPreviewLayer {
        func rectOfInterestConverted(parentRect: CGRect, fromLayerRect: CGRect) -> CGRect {
            let parentWidth = parentRect.width
            let parentHeight = parentRect.height
            let newX = (parentWidth - fromLayerRect.maxX)/parentWidth
            let newY = 1 - (parentHeight - fromLayerRect.minY)/parentHeight
            let width = 1 - (fromLayerRect.minX/parentWidth + newX)
            let height = (fromLayerRect.maxY/parentHeight) - newY
    
            return CGRect(x: newX, y: newY, width: width, height: height)
        }
    }
    

    用法:

    if let rect = videoPreviewLayer?.rectOfInterestConverted(parentRect: self.view.frame, fromLayerRect: scanAreaView.frame) {
        captureMetadataOutput.rectOfInterest = rect
    }
    

    【讨论】:

    • 为了让这个答案尽可能有帮助,请添加解释你到底在做什么以及为什么。
    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
    【解决方案2】:

    func captureOutput(_:didOutput:from:) 中,您很可能会将整个图像传递给VNImageRequestHandler
    相反,您需要将图像裁剪为可见的矩形。
    另一种方法是通过regionOfInterest 将视觉锁定到图像的仅可见部分,如下面的@HurricaneOnTheMoon 建议。

    【讨论】:

    • 我已经添加了captureOutput的代码,我好像忘记了。我将如何裁剪图像?
    猜你喜欢
    • 1970-01-01
    • 2020-06-19
    • 2017-06-30
    • 2018-06-18
    • 2018-01-26
    • 1970-01-01
    • 2018-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多