Установите фокус камеры на точку касания с помощью Swift

API для быстрого использования камеры кажется совсем другим, и мне трудно сфокусировать камеру на какой-либо точке. Когда пользователь касается экрана, я хочу, чтобы камера сфокусировалась на этой точке.

Это мой код:

 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()
        }
    }

Но это не похоже на работу.

Любые предложения приветствуются!

7 ответов

Решение

Оказывается, это очень просто:

_currentDevice.lockForConfiguration(nil)
_currentDevice.focusPointOfInterest = tap.locationInView(self)
_currentDevice.unlockForConfiguration()

Обновленный ответ от @ryantxr для 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
                }
            }
        }
    }

Лучшее решение, так как оно работает правильно для всех videoGravity режимы, также когда соотношение сторон слоя предварительного просмотра отличается от соотношения устройства:

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
}

Обновленный ответ от @Code для 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
            }
        }
    }
}

Я использовал AVFoundation библиотека и обертка, что диспетчер камеры. Я делюсь с примером кода. Вы можете адаптировать свой проект. Кстати, вы не можете сфокусировать камеру с помощью фронтальной камеры. Это не поддерживает это. Вы можете регулировать экспозицию только для фронтальной камеры. С помощью редкой камеры вы можете сделать это.

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")
            }
        }
    }
}

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)
  }
}

Этот вопрос, возможно, является дубликатом касания iOS для фокусировки, где я разместил это (надеюсь, явное) решение, которое сработало для меня:

С 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)) {
            device.focusPointOfInterest = focusPoint
            device.focusMode = AVCaptureFocusMode.ContinuousAutoExposure
            device.exposurePointOfInterest = focusPoint
            device.exposureMode = AVCaptureExposureMode.ContinuousAutoExposure
            device.unlockForConfiguration()
        }
    }
}

Обратите внимание, что я должен был поменять x а также y координаты и переназначить x Координаты от 1 до 0 вместо 0 до 1 - не уверен, почему так должно быть, но кажется, что необходимо заставить его работать правильно (хотя это тоже немного сложно проверить).

Другие вопросы по тегам