簡體   English   中英

iOS 點擊對焦

[英]iOS tap to focus

我使用此代碼在 iOS 自定義相機 App 中實現了 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()
        }
    }
}

使用videoView: UIView顯示視頻和cameraDevice: AVCaptureDevice ,以下似乎對我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()
        }
    }
} 

請注意,我必須交換xy坐標,並將x coord從1重新映射到0而不是0到1 - 不知道為什么會出現這種情況但似乎有必要讓它正常工作(盡管它是有點棘手的測試它)

編輯: Apple的文檔解釋了坐標轉換的原因。

另外,設備可以支持關注焦點。 您使用focusPointOfInterestSupported測試支持。 如果支持,則使用focusPointOfInterest設置焦點。 您傳遞一個CGPoint,其中{0,0}表示圖片區域的左上角,{1,1}表示橫向模式的右下角,右側的主頁按鈕 - 即使設備處於縱向模式,這也適用。

在我的例子我已經使用了.ContinuousAutoFocus.ContinuousAutoExposure ,但文件表明.AutoFocus是正確的選擇。 奇怪的是文檔沒有提到.AutoExpose ,但我在我的代碼中使用它並且它工作正常。

我還修改了我的示例代碼以包含.focusPointOfInterestSupported.exposurePointOfInterestSupported測試 - 文檔還提到使用isFocusModeSupported:isExposureModeSupported:給定焦點/曝光模式的方法來測試它在設置之前是否在給定設備上可用,但是我假設設備支持興趣點模式,那么它也支持自動模式。 這一切似乎在我的應用程序中正常工作。

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
        }
    }
}
 device.focusPointOfInterest = focusPoint
 device.focusMode = AVCaptureFocusMode.AutoFocus
 device.exposurePointOfInterest = focusPoint
 device.exposureMode = AVCaptureExposureMode.ContinuousAutoExposure

我不知道為什么會這樣,但確實如此。

設置焦點的更好方法是:

  • 首先計算興趣點:

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

你應該閱讀關於focusPointOfInterest Apple 文檔 ,它說三件重要的事情:

  1. 為此屬性設置值不會啟動聚焦操作。 要將相機聚焦在感興趣的點上,首先設置此屬性的值,然后將focusMode屬性設置為autoFocus或continuousAutoFocus。

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

您必須按正確的順序調用方法:

if(device.lockForConfiguration(nil)) {

    device.focusPointOfInterest = CGPointMake(focus_x, focus_y)
    device.focusMode = AVCaptureFocusMode.ContinuousAutoFocus

    device.exposureMode = AVCaptureExposureMode.ContinuousAutoExposure
    device.unlockForConfiguration()
}

在設置焦點模式之前設置關注點,否則焦點將在之前的關注點上進行。

這同樣適用於exposurePointOfInterest

斯威夫特 5.0 版本

// The back camera as default device
var captureDevice: AVCaptureDevice? {
    return AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
}

// The camera view.
var cameraView: UIView!

// The layer that contains the camera output
var previewLayer: AVCaptureVideoPreviewLayer

// The focus square view - the yellow one ;)
var squareFocusView: UIView

// User taps on screen to select focus
@IBAction func tapToFocus(_ sender: UITapGestureRecognizer) {
    // make sure we capture one tap only
    if (sender.state == .ended) {
        
        guard let captureDevice = captureDevice else {
            return
        }
        
        let tappedFocusPoint = sender.location(in: cameraView)
        
        // we need to move the focus point to be the center of the tap instead of (0.0, 0.0)
        let centerX = tappedFocusPoint.x - (squareFocusView.frame.size.width / 2.0)
        let centerY = tappedFocusPoint.y - (squareFocusView.frame.size.height / 2.0)

        let focusPoint = CGPoint(x: centerX, y: centerY)
        
        // we need to remap the point because of different coordination systems.
        let convertedFocusPoint = previewLayer.captureDevicePointConverted(fromLayerPoint: focusPoint)
        
        do {
            // changing focusMode and exposureMode requires the device config to be locked.
            try captureDevice.lockForConfiguration()
            
            if (captureDevice.isFocusModeSupported(.autoFocus) && captureDevice.isFocusPointOfInterestSupported) {
                captureDevice.focusPointOfInterest = convertedFocusPoint
                captureDevice.focusMode = .autoFocus
            }
            
            if (captureDevice.isExposureModeSupported(.autoExpose) && captureDevice.isExposurePointOfInterestSupported) {
                captureDevice.exposurePointOfInterest = convertedFocusPoint
                captureDevice.exposureMode = .autoExpose
            }
            
            // unlocks device config
            captureDevice.unlockForConfiguration()
            
        } catch {
            // handle error here
        }
    }
}

Swift 4:

   public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    var touchPoint = touches.first as! UITouch
    let cameraView = cameraViewController.view
    var screenSize = cameraView!.bounds.size
    var focusPoint = CGPoint(x: touchPoint.location(in: cameraView).y / screenSize.height, y: 1.0 - touchPoint.location(in: cameraView).x / screenSize.width)
    
    
    
    
    if #available(iOS 10.0, *) {
        let device = AVCaptureDevice.default(.builtInWideAngleCamera,
                                             for: .video, position: .unspecified)
        
        do{
            try device?.lockForConfiguration()
            
            if device!.isFocusPointOfInterestSupported {
                        device!.focusPointOfInterest = focusPoint
                device!.focusMode = AVCaptureDevice.FocusMode.autoFocus
                    }
            if device!.isExposurePointOfInterestSupported {
                        device!.exposurePointOfInterest = focusPoint
                device!.exposureMode = AVCaptureDevice.ExposureMode.autoExpose
                    }
                    device!.unlockForConfiguration()
        }catch{
            
        }
           
  
            
        
    } else {
        // Fallback on earlier versions
    }
     
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM