我使用此代码在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()
}
}
}
答案 0 :(得分:21)
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()
}
}
}
请注意,我必须交换x
和y
坐标,并将x
坐标重新映射为1而不是0到1 - 不知道为什么应该是这样的,但似乎有必要让它正常工作(虽然测试它也有点棘手)。
编辑:Apple's documentation解释了坐标转换的原因。
此外,设备可以支持关注焦点。您使用focusPointOfInterestSupported测试支持。如果支持,则使用focusPointOfInterest设置焦点。您传递一个CGPoint,其中{0,0}表示图片区域的左上角,{1,1}表示横向模式的右下角,右侧的主页按钮 - 即使设备处于纵向模式,这也适用
在我的示例中,我一直在使用.ContinuousAutoFocus
和.ContinuousAutoExposure
,但文档指出.AutoFocus
是正确的选择。奇怪的是,文档没有提及.AutoExpose
,但我在我的代码中使用它并且它工作正常。
我还修改了我的示例代码以包含.focusPointOfInterestSupported
和.exposurePointOfInterestSupported
测试 - 文档还提到了使用isFocusModeSupported:
和isExposureModeSupported:
方法进行给定的焦点/曝光模式在设置之前测试它是否在给定设备上可用,但我假设如果设备支持兴趣点模式,那么它也支持自动模式。这一切似乎都在我的应用程序中正常工作。
答案 1 :(得分:9)
Swift 3.0解决方案
使用Swift 3将Cody的答案转换为可行的解决方案。
<line x1="40" y1="40" x2="100" y2="100" desc="directional line" />
<line x1="54.1" y1="54.1" x2="85.9" y2="85.9" desc="actual part of line" />
答案 2 :(得分:7)
device.focusPointOfInterest = focusPoint
device.focusMode = AVCaptureFocusMode.AutoFocus
device.exposurePointOfInterest = focusPoint
device.exposureMode = AVCaptureExposureMode.ContinuousAutoExposure
我不知道为什么会这样,但确实如此。
答案 3 :(得分:4)
设置焦点的更好方法是:
首先计算兴趣点:
let devicePoint: CGPoint = (self.previewView.layer as! AVCaptureVideoPreviewLayer).captureDevicePointOfInterestForPoint(gestureRecognizer.locationInView(gestureRecognizer.view))
之后设置了焦点:
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)
}
答案 4 :(得分:3)
您应该在focusPointOfInterest
上阅读Apple docs,其中包含三个重要内容:
为此属性设置值不会启动聚焦操作。要将相机对焦于感兴趣的点,请先设置此属性的值,然后将focusMode属性设置为autoFocus或continuousAutoFocus。
此属性的CGPoint值使用坐标系,其中{0,0}是图片区域的左上角,{1,1}是右下角。 无论实际的设备方向如何,此坐标系始终相对于横向设备方向,主菜单按钮位于右侧。您可以使用AVCaptureVideoPreviewLayer方法在此坐标系和视图坐标之间进行转换。
- 醇>
在更改此属性的值之前,必须调用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)
}
}
答案 5 :(得分:0)
您必须按正确的顺序调用方法:
if(device.lockForConfiguration(nil)) {
device.focusPointOfInterest = CGPointMake(focus_x, focus_y)
device.focusMode = AVCaptureFocusMode.ContinuousAutoFocus
device.exposureMode = AVCaptureExposureMode.ContinuousAutoExposure
device.unlockForConfiguration()
}
在设置对焦模式之前设置关注点,否则焦点将在之前的兴趣点上进行。
同样适用于exposurePointOfInterest
。