如何仅在 CGRect 中使用 Apple Vision 检测条形码?
Posted
技术标签:
【中文标题】如何仅在 CGRect 中使用 Apple Vision 检测条形码?【英文标题】:How to detect barcode using Apple Vision in CGRect only? 【发布时间】: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
【问题讨论】:
【参考方案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的代码,我好像忘记了。我将如何裁剪图像?以上是关于如何仅在 CGRect 中使用 Apple Vision 检测条形码?的主要内容,如果未能解决你的问题,请参考以下文章