gpt4 book ai didi

ios - 如何使用 metadataOutputRectOfInterestForRect 方法和 rectOfInterest 属性扫描特定区域? (二维码)

转载 作者:IT王子 更新时间:2023-10-29 05:04:25 25 4
gpt4 key购买 nike

我正在使用 Swift 构建一个二维码扫描仪,在这方面一切正常。我遇到的问题是,我试图让整个可见 AVCaptureVideoPreviewLayer 的一小部分区域能够扫描二维码。我发现,为了指定屏幕的哪个区域能够读取/捕获 QR 码,我必须使用名为 rectOfInterestAVCaptureMetadataOutput 属性。问题是当我将它分配给 CGRect 时,我无法扫描任何东西。在网上做了更多研究后,我发现一些建议我需要使用一种名为 metadataOutputRectOfInterestForRect 的方法将 CGRect 转换为属性 rectOfInterest 可以实际使用的正确格式。但是,我现在遇到的一个大问题是,当我使用此方法时 metadataoutputRectOfInterestForRect 我收到一个错误,指出 CGAffineTransformInvert: singular matrix。谁能告诉我为什么会出现此错误?我相信我正在根据 Apple 开发人员文档正确使用此方法,并且我相信我需要根据我在网上找到的所有信息来使用此方法来实现我的目标。我将包含到目前为止找到的文档的链接以及我用来扫描二维码的函数的代码示例

代码示例

func startScan() {
// Get an instance of the AVCaptureDevice class to initialize a device object and provide the video
// as the media type parameter.
let captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)

// Get an instance of the AVCaptureDeviceInput class using the previous device object.
var error:NSError?
let input: AnyObject! = AVCaptureDeviceInput.deviceInputWithDevice(captureDevice, error: &error)

if (error != nil) {
// If any error occurs, simply log the description of it and don't continue any more.
println("\(error?.localizedDescription)")
return
}

// Initialize the captureSession object.
captureSession = AVCaptureSession()
// Set the input device on the capture session.
captureSession?.addInput(input as! AVCaptureInput)

// Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session.
let captureMetadataOutput = AVCaptureMetadataOutput()
captureSession?.addOutput(captureMetadataOutput)

// calculate a centered square rectangle with red border
let size = 300
let screenWidth = self.view.frame.size.width
let xPos = (CGFloat(screenWidth) / CGFloat(2)) - (CGFloat(size) / CGFloat(2))
let scanRect = CGRect(x: Int(xPos), y: 150, width: size, height: size)

// create UIView that will server as a red square to indicate where to place QRCode for scanning
scanAreaView = UIView()
scanAreaView?.layer.borderColor = UIColor.redColor().CGColor
scanAreaView?.layer.borderWidth = 4
scanAreaView?.frame = scanRect
view.addSubview(scanAreaView!)

// Set delegate and use the default dispatch queue to execute the call back
captureMetadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
captureMetadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode]



// Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer.
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
videoPreviewLayer?.frame = view.layer.bounds
captureMetadataOutput.rectOfInterest = videoPreviewLayer!.metadataOutputRectOfInterestForRect(scanRect)
view.layer.addSublayer(videoPreviewLayer)

// Start video capture.
captureSession?.startRunning()

// Initialize QR Code Frame to highlight the QR code
qrCodeFrameView = UIView()
qrCodeFrameView?.layer.borderColor = UIColor.greenColor().CGColor
qrCodeFrameView?.layer.borderWidth = 2
view.addSubview(qrCodeFrameView!)
view.bringSubviewToFront(qrCodeFrameView!)

// Add a button that will be used to close out of the scan view
videoBtn.setTitle("Close", forState: .Normal)
videoBtn.setTitleColor(UIColor.blackColor(), forState: .Normal)
videoBtn.backgroundColor = UIColor.grayColor()
videoBtn.layer.cornerRadius = 5.0;
videoBtn.frame = CGRectMake(10, 30, 70, 45)
videoBtn.addTarget(self, action: "pressClose:", forControlEvents: .TouchUpInside)
view.addSubview(videoBtn)


view.bringSubviewToFront(scanAreaView!)

}

请注意导致错误的兴趣行是这样的:captureMetadataOutput.rectOfInterest = videoPreviewLayer!.metadataOutputRectOfInterestForRect(scanRect)

我尝试过的其他事情是直接将 CGRect 作为参数传递,这导致了同样的错误。我还传入了 scanAreaView!.bounds 作为参数,因为它确实是我正在寻找的确切大小/区域,并且也会导致同样的错误。我已经在其他人的在线代码示例中看到过这样做,他们似乎没有我遇到的错误。以下是一些示例:

AVCaptureSession barcode scan

Xcode AVCapturesession scan Barcode in specific frame (rectOfInterest is not working)

Apple 文档

metadataOutputRectOfInterestForRect

rectOfInterest

我正在用作指定区域的 scanAreaView 的图像我试图使视频预览层的唯一可扫描区域:

enter image description here

最佳答案

我真的无法阐明 metadataOutputRectOfInterestForRect 的问题,但是,您也可以直接设置该属性。您需要预先指定视频的宽度和高度分辨率。我很快使用了 640*480 设置。如文档中所述,这些值必须是

"extending from (0,0) in the top left to (1,1) in the bottom right, relative to the device’s natural orientation".

参见 https://developer.apple.com/documentation/avfoundation/avcaptureoutput/1616304-metadataoutputrectofinterestforr

下面是我试过的代码

var x = scanRect.origin.x/480
var y = scanRect.origin.y/640
var width = scanRect.width/480
var height = scanRect.height/640
var scanRectTransformed = CGRectMake(x, y, width, height)
captureMetadataOutput.rectOfInterest = scanRectTransformed

我刚刚在 iOS 设备上对其进行了测试,它似乎可以正常工作。

编辑

至少我已经解决了 metadataOutputRectOfInterestForRect 问题。我相信您必须在相机已正确设置并正在运行后执行此操作,因为相机的分辨率尚不可用。

首先在viewDidLoad()中添加一个通知观察者方法

NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("avCaptureInputPortFormatDescriptionDidChangeNotification:"), name:AVCaptureInputPortFormatDescriptionDidChangeNotification, object: nil)

然后添加如下方法

func avCaptureInputPortFormatDescriptionDidChangeNotification(notification: NSNotification) {

captureMetadataOutput.rectOfInterest = videoPreviewLayer.metadataOutputRectOfInterestForRect(scanRect)

}

然后您可以在此处重置 rectOfInterest 属性。然后,在您的代码中,您可以在 didOutputMetadataObjects 函数中显示 AVMetadataObject

var rect = videoPreviewLayer.rectForMetadataOutputRectOfInterest(YourAVMetadataObject.bounds)

dispatch_async(dispatch_get_main_queue(),{
self.qrCodeFrameView.frame = rect
})

我试过了,矩形总是在指定区域内。

关于ios - 如何使用 metadataOutputRectOfInterestForRect 方法和 rectOfInterest 属性扫描特定区域? (二维码),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32401364/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com