Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS tap to focus

Tags:

I used this code to achieve Tap-to-Focus in iOS custom camera App, but it isn't working. Here's the code

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()
        }
    }
}
like image 626
Krishna Avatar asked Jan 22 '15 10:01

Krishna


People also ask

How do I turn on iOS focus?

Go to Settings > Focus. at the top right, then tap Custom. Enter a name for your Focus, then tap Return. Choose a color and an icon to represent your Focus, then tap Next.

Does iOS have a focus mode?

Apple in iOS 15 introduced Focus mode, an expansion of Do Not Disturb that allows you to set up different permissions for apps, contacts, and more depending on what you're doing. You can have separate tasks for when you're at work, when you're studying, when you're at home, and more.


2 Answers

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)) {
            if device.focusPointOfInterestSupported {
                device.focusPointOfInterest = focusPoint
                device.focusMode = AVCaptureFocusMode.AutoFocus
            }
            if device.exposurePointOfInterestSupported {
                device.exposurePointOfInterest = focusPoint
                device.exposureMode = AVCaptureExposureMode.AutoExpose
            }
            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).

Edit: Apple's documentation explains the reason for the coordinate transformation.

In addition, a device may support a focus point of interest. You test for support using focusPointOfInterestSupported. If it’s supported, you set the focal point using focusPointOfInterest. You pass a CGPoint where {0,0} represents the top left of the picture area, and {1,1} represents the bottom right in landscape mode with the home button on the right—this applies even if the device is in portrait mode.

In my example I had been using .ContinuousAutoFocus and .ContinuousAutoExposure, but the documentation indicates .AutoFocus is the right choice. Oddly the documentation makes no mention of .AutoExpose, but I'm using it in my code and it works fine.

I also modified my example code to include .focusPointOfInterestSupported and .exposurePointOfInterestSupported tests — the documentation also mentions using the isFocusModeSupported: and isExposureModeSupported: methods for a given focus/exposure mode to test whether it is available on a given device before setting it, but I assume if the device supports the point of interest modes then it also supports the auto modes. It all seems to work fine in my app.

like image 108
Cody Avatar answered Sep 27 '22 17:09

Cody


Swift 3.0 Solution

Converted Cody's answer into a working solution with 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
        }
    }
}
like image 11
Devbot10 Avatar answered Sep 28 '22 17:09

Devbot10