如何使用Swift5通过相机仅扫描某些区域?

u59ebvdq  于 2023-09-30  发布在  Swift
关注(0)|答案(2)|浏览(141)

我想用相机扫描QRcode。扫描QRcode没有问题,
但我只想扫描特定区域我该怎么做?
我目前在整个摄像头区域的任何地方都知道QR码。

import Foundation
import UIKit
import AVFoundation

class ScannerViewController : UIViewController, AVCaptureMetadataOutputObjectsDelegate {

    @IBOutlet weak var qrcodeView: UIView!
    @IBOutlet weak var mainText: UITextView!
    @IBOutlet weak var headerBar: UINavigationBar!

    var captureSession: AVCaptureSession!
    var previewLayer: AVCaptureVideoPreviewLayer!

    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor.black
        self.qrcodeView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        captureSession = AVCaptureSession()

        guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return }
        let videoInput: AVCaptureDeviceInput

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

        if (captureSession.canAddInput(videoInput)) {
            captureSession.addInput(videoInput)
        } else {
            failed()
            return
        }

        let metadataOutput = AVCaptureMetadataOutput()

        if (captureSession.canAddOutput(metadataOutput)) {
            captureSession.addOutput(metadataOutput)

            metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
            metadataOutput.metadataObjectTypes = [.qr]
        } else {
            failed()
            return
        }

        previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        previewLayer.frame = view.layer.bounds
        previewLayer.videoGravity = .resizeAspectFill
        view.layer.insertSublayer(previewLayer, at: 0)
        captureSession.startRunning()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        if (captureSession?.isRunning == false) {
            captureSession.startRunning()
        }
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        if (captureSession?.isRunning == true) {
            captureSession.stopRunning()
        }
    }

    func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
//        let scanRect = CGRect(x: 0, y: 0, width: 200, height: 200)
//        let rectOfInterest = layer.metadataOutputRectConverted(fromLayerRect: scanRect)
//        metadataObjects.rectOfInterest = rectOfInterest

        captureSession.stopRunning()

        if let metadataObject = metadataObjects.first {
            guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return }
            guard let stringValue = readableObject.stringValue else { return }
            AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
            found(code: stringValue)
        } else {
            print("not support")
        }
    }

    func found(code: String) {
        print(code)
        self.dismiss(animated: true, completion: nil)
    }

    func failed() {
        captureSession = nil
    } 

}

就像上面的图片一样,我想只在正方形区域内扫描。
我非常需要这个。
先谢了。

cnjp1d6j

cnjp1d6j1#

您可以使用rectOfInterest属性来实现这一点
captureSession.startRunning()后添加以下代码
首先你需要使用rect转换

let rectOfInterest = videoPreviewLayer?.metadataOutputRectConverted(fromLayerRect: self.viewAreaOfScan.frame) //  videoPreviewLayer is AVCaptureVideoPreviewLayer

之后,您可以将其分配给metadataOutput中的rectOfInterest

metadataOutput.rectOfInterest = rectOfInterest ?? CGRect(x: 0, y: 0, width: 1, height: 1)
xzlaal3s

xzlaal3s2#

斯威夫特5一个非常强大的答案后,花了一整天
它将在您所需的视图中工作,就像我使用viewCamera一样,您可以根据需要使用自己的UI

@IBOutlet weak var viewCamera: UIView!

var captureSession: AVCaptureSession!
var previewLayer: AVCaptureVideoPreviewLayer!

override func viewDidLoad() {
    super.viewDidLoad()
    loadCameraForQRCodeScanning()
}

func loadCameraForQRCodeScanning() {
    captureSession = AVCaptureSession()
    guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return }
    
    let videoInput: AVCaptureDeviceInput
    
    do {
        videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
    } catch {
        return
    }

    if (captureSession.canAddInput(videoInput)) {
        captureSession.addInput(videoInput)
    } else {
        failed()
        return
    }

    let metadataOutput = AVCaptureMetadataOutput()

    if (captureSession.canAddOutput(metadataOutput)) {
        captureSession.addOutput(metadataOutput)

        metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
        metadataOutput.metadataObjectTypes = [.qr]
    } else {
        failed()
        return
    }
    
    previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    previewLayer.frame = viewCamera.bounds
    previewLayer.videoGravity = .resize
    viewCamera.layer.addSublayer(previewLayer)
    
    captureSession.startRunning()
}

相关问题