iOS点按即可关注

Kri*_*hna 20 ios avcapturesession swift

我使用此代码在iOS自定义相机应用程序中实现Tap-to-Focus,但它无法正常工作.这是代码

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    let touchPer = touches.anyObject() as UITouch
    let screenSize = UIScreen.mainScreen().bounds.size
    var focus_x = touchPer.locationInView(self.view).x / screenSize.width
    var focus_y = touchPer.locationInView(self.view).y / screenSize.height

    if let device = captureDevice {
        if(device.lockForConfiguration(nil)) {
            device.focusMode = AVCaptureFocusMode.ContinuousAutoFocus

            device.focusPointOfInterest = CGPointMake(focus_x, focus_y)
            device.exposureMode = AVCaptureExposureMode.ContinuousAutoExposure
            device.unlockForConfiguration()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Cod*_*ody 23

通过videoView: UIView显示视频,cameraDevice: AVCaptureDevice以下似乎对我有用:

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    var touchPoint = touches.first as! UITouch
    var screenSize = videoView.bounds.size
    var focusPoint = CGPoint(x: touchPoint.locationInView(videoView).y / screenSize.height, y: 1.0 - touchPoint.locationInView(videoView.x / screenSize.width)

    if let device = cameraDevice {
        if(device.lockForConfiguration(nil)) {
            if device.focusPointOfInterestSupported {
                device.focusPointOfInterest = focusPoint
                device.focusMode = AVCaptureFocusMode.AutoFocus
            }
            if device.exposurePointOfInterestSupported {
                device.exposurePointOfInterest = focusPoint
                device.exposureMode = AVCaptureExposureMode.AutoExpose
            }
            device.unlockForConfiguration()
        }
    }
} 
Run Code Online (Sandbox Code Playgroud)

请注意,我必须交换xy坐标,并将xcoord从1 重新映射到0而不是0到1 -  不知道为什么会出现这种情况但似乎有必要让它正常工作(虽然这有点棘手测试它).

编辑:Apple的文档解释了坐标转换的原因.

另外,设备可以支持关注焦点.您使用focusPointOfInterestSupported测试支持.如果支持,则使用focusPointOfInterest设置焦点.您传递一个CGPoint,其中{0,0}表示图片区域的左上角,{1,1}表示横向模式的右下角,右侧的主页按钮 - 即使设备处于纵向模式,这也适用.

在我的例子我一直在使用.ContinuousAutoFocus.ContinuousAutoExposure,但文件表明.AutoFocus是正确的选择.奇怪的是文档没有提及.AutoExpose,但我在我的代码中使用它,它工作正常.

我还修改了示例代码以包括.focusPointOfInterestSupported.exposurePointOfInterestSupported测试-文档也提到使用isFocusModeSupported:isExposureModeSupported:方法对于给定的聚焦/曝光模式,以测试它是否是可用的设置之前,给定的设备上,但我假定如果设备支持的点兴趣模式然后它也支持自动模式.这一切似乎在我的应用程序中正常工作.

  • 更简单的是,如果你使用的是AVCaptureVideoPreviewLayer类,你可以使用captureDevicePointOfInterestForPoint (2认同)

Dev*_*t10 10

Swift 3.0解决方案

将Cody的答案转换为Swift 3的工作解决方案.

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touchPoint = touches.first! as UITouch
    let screenSize = cameraView.bounds.size
    let focusPoint = CGPoint(x: touchPoint.location(in: cameraView).y / screenSize.height, y: 1.0 - touchPoint.location(in: cameraView).x / screenSize.width)

    if let device = captureDevice {
        do {
            try device.lockForConfiguration()
            if device.isFocusPointOfInterestSupported {
                device.focusPointOfInterest = focusPoint
                device.focusMode = AVCaptureFocusMode.autoFocus
            }
            if device.isExposurePointOfInterestSupported {
                device.exposurePointOfInterest = focusPoint
                device.exposureMode = AVCaptureExposureMode.autoExpose
            }
            device.unlockForConfiguration()

        } catch {
            // Handle errors here
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Kri*_*hna 8

 device.focusPointOfInterest = focusPoint
 device.focusMode = AVCaptureFocusMode.AutoFocus
 device.exposurePointOfInterest = focusPoint
 device.exposureMode = AVCaptureExposureMode.ContinuousAutoExposure
Run Code Online (Sandbox Code Playgroud)

我不知道为什么会这样,但确实如此.


Osc*_*and 6

你应该阅读苹果文档focusPointOfInterest,它说三个重要的事情:

  1. 为该属性设置值不会启动聚焦操作。要将相机聚焦在兴趣点上,首先设置此属性的值,然后将 focusMode 属性设置为 autoFocus 或 continueAutoFocus。

  2. 此属性的 CGPoint 值使用坐标系,其中 {0,0} 是图片区域的左上角,{1,1} 是右下角。无论实际的设备方向如何,此坐标系始终相对于具有右侧主页按钮的横向设备方向。您可以使用 AVCaptureVideoPreviewLayer 方法在此坐标系和视图坐标之间进行转换。

  3. 在更改此属性的值之前,您必须调用 lockForConfiguration() 以获取对设备配置属性的独占访问权限。否则,设置此属性的值会引发异常。完成设备配置后,调用 unlockForConfiguration() 以释放锁定并允许其他设备配置设置。

这是一个实现所有这些的实现:

// In your camera preview view    
@objc private func cameraViewTapped(with gestureRecognizer: UITapGestureRecognizer) {
    let location = gestureRecognizer.location(in: self)
    addFocusIndicatorView(at: location) // If you want to indicate it in the UI

    // This is the point you want to pass to your capture device
    let captureDeviceLocation = previewLayer.captureDevicePointConverted(fromLayerPoint: location)

    // Somehow pass the point to where your AVCaptureDevice is
    viewDelegate?.cameraPreviewView(self, didTapToFocusAt: captureDeviceLocation) 
}


// In your camera controller
func focus(at point: CGPoint) {
    guard let device = videoDevice else {
        return
    }

    guard device.isFocusPointOfInterestSupported, device.isExposurePointOfInterestSupported else {
        return
    }

    do {
        try device.lockForConfiguration()

        device.focusPointOfInterest = point
        device.exposurePointOfInterest = point

        device.focusMode = .continuousAutoFocus
        device.exposureMode = .continuousAutoExposure

        device.unlockForConfiguration()
    } catch {
        print(error)
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @AshleyMills 接受的答案没有提到“AVCaptureVideoPreviewLayer.captureDevicePointConverted(fromLayerPoint:)” - 甚至以笨拙的手动方式这样做。这是 Swift 4,接受的答案在 Swift 2 中。此外,这个答案有来源,并遵循 Swift 风格约定/最佳实践。我不明白你为什么认为这需要投反对票。 (2认同)

Yog*_*ngh 5

设置关注点的更好方法:

  • 首先计算兴趣点:

     let devicePoint: CGPoint = (self.previewView.layer as!  AVCaptureVideoPreviewLayer).captureDevicePointOfInterestForPoint(gestureRecognizer.locationInView(gestureRecognizer.view))
    
    Run Code Online (Sandbox Code Playgroud)
  • 之后,设置关注点:

    let device: AVCaptureDevice! = self.videoDeviceInput!.device
    
        do {
            try device.lockForConfiguration()
    
            if device.focusPointOfInterestSupported && device.isFocusModeSupported(focusMode){
    
                device.focusPointOfInterest = devicePoint
                device.focusMode = focusMode
            }
    
            device.unlockForConfiguration()
    
        }catch{
            print(error)
        }
    
    Run Code Online (Sandbox Code Playgroud)