可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
The API for using the camera in swift seems a but different and I am having a hard time focusing the camera on a point. When the user taps the screen I want the camera to focus on that point
This is my code:
func focusCamera(point:CGPoint)
{
var screenRect:CGRect = bounds
var focusX = Float(point.x/screenRect.width)
var focusY = Float(point.y/screenRect.height)
_currentDevice.lockForConfiguration(nil)
_currentDevice.setFocusModeLockedWithLensPosition(focusX)
{
time in
self._currentDevice.unlockForConfiguration()
}
_currentDevice.setFocusModeLockedWithLensPosition(focusY)
{
time in
self._currentDevice.unlockForConfiguration()
}
}
But it doesnt seem to work.
Any suggestions are more than welcome!
回答1:
Updated answer from @ryantxr for Swift 3:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let screenSize = videoView.bounds.size
if let touchPoint = touches.first {
let x = touchPoint.location(in: videoView).y / screenSize.height
let y = 1.0 - touchPoint.location(in: videoView).x / screenSize.width
let focusPoint = CGPoint(x: x, y: y)
if let device = captureDevice {
do {
try device.lockForConfiguration()
device.focusPointOfInterest = focusPoint
//device.focusMode = .continuousAutoFocus
device.focusMode = .autoFocus
//device.focusMode = .locked
device.exposurePointOfInterest = focusPoint
device.exposureMode = AVCaptureExposureMode.continuousAutoExposure
device.unlockForConfiguration()
}
catch {
// just ignore
}
}
}
}
回答2:
Better solution, as it works correctly for all videoGravity
modes, also when the preview layer aspect ratio is different from the device ratio:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
guard let touchPoint = touches.first else { return }
// precondition: the videoView contains the previewLayer, and the frames of the two are being kept equal
let touchPointInPreviewLayer = touchPoint.location(in: videoView)
let focusPoint = previewLayer.captureDevicePointOfInterest(for: touchPointInPreviewLayer)
// etc
}
回答3:
Updated answer from @Code for Swift 2.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let screenSize = videoView.bounds.size
if let touchPoint = touches.first {
let x = touchPoint.locationInView(videoView).y / screenSize.height
let y = 1.0 - touchPoint.locationInView(videoView).x / screenSize.width
let focusPoint = CGPoint(x: x, y: y)
if let device = captureDevice {
do {
try device.lockForConfiguration()
device.focusPointOfInterest = focusPoint
//device.focusMode = .ContinuousAutoFocus
device.focusMode = .AutoFocus
//device.focusMode = .Locked
device.exposurePointOfInterest = focusPoint
device.exposureMode = AVCaptureExposureMode.ContinuousAutoExposure
device.unlockForConfiguration()
}
catch {
// just ignore
}
}
}
}
回答4:
Turns out its very simple:
_currentDevice.lockForConfiguration(nil)
_currentDevice.focusPointOfInterest = tap.locationInView(self)
_currentDevice.unlockForConfiguration()
回答5:
This question maybe is a duplicate of iOS tap to focus, where I posted this (hopefully explicit) solution that worked for me:
With a videoView: UIView
displaying the video, and cameraDevice: AVCaptureDevice
, the following seems to work for me:
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)) {
device.focusPointOfInterest = focusPoint
device.focusMode = AVCaptureFocusMode.ContinuousAutoExposure
device.exposurePointOfInterest = focusPoint
device.exposureMode = AVCaptureExposureMode.ContinuousAutoExposure
device.unlockForConfiguration()
}
}
}
Note that I had to swap the x
and y
coordinates, and remap the x
coord from 1 to 0 instead of 0 to 1 — not sure why that should be the case but it seems to be necessary to get it to work right (though it's a little tricky to test it too).
回答6:
Swift 2.0
if let device = captureDevice {
do {
try device.lockForConfiguration()
device.focusPointOfInterest = focusPoint
device.focusMode = AVCaptureFocusMode.ContinuousAutoFocus
device.exposurePointOfInterest = focusPoint
device.exposureMode = AVCaptureExposureMode.ContinuousAutoExposure
} catch let error as NSError {
print(error.localizedDescription)
}
}
回答7:
I used AVFoundation
library and a wrapper that Camera Manager.
I am sharing to code sample. You can adapt your project.
By the way, you cannot focus the camera using front-camera. It doesn't support it. You can only adjust exposure for front-camera. By rare-camera, you can do it.
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let screenSize = cameraView.bounds.size
let frameSize:CGSize = view.frame.size
if let touchPoint = touches.first {
var location:CGPoint = touchPoint.locationInView(cameraView)
if cameraManager.cameraDevice == .Front {
print("Front camera is used")
location.x = frameSize.width - location.x;
}
else {
print("Back camera is used")
}
let x = location.x / frameSize.width
let y = 1.0 - (location.x / frameSize.width)
let focusPoint = CGPoint(x: x, y: y)
print("POINT : X: \(x), Y: \(y)")
let captureDevice = (AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo) as! [AVCaptureDevice]).filter{$0.position == .Back}.first
if let device = captureDevice {
do {
try device.lockForConfiguration()
let support:Bool = device.focusPointOfInterestSupported
if support {
print("focusPointOfInterestSupported: \(support)")
device.focusPointOfInterest = focusPoint
// device.focusMode = .ContinuousAutoFocus
device.focusMode = .AutoFocus
// device.focusMode = .Locked
device.unlockForConfiguration()
print("Focus point was set successfully")
}
else{
print("focusPointOfInterestSupported is not supported: \(support)")
}
}
catch {
// just ignore
print("Focus point error")
}
}
}
}