【问题标题】:Pinch to zoom camera捏缩放相机
【发布时间】:2016-01-15 19:14:44
【问题描述】:

我正在尝试通过捏合来缩放相机,但遇到了两个问题。首先是它允许用户放大太多和太多,其次当我拍照时它不会把它放大。这是我的捏函数代码...

func pinch(pinch: UIPinchGestureRecognizer) {
    if let view = cameraView {
        view.transform = CGAffineTransformScale(view.transform,
            pinch.scale, pinch.scale)
            pinch.scale = 1
    }

}

如果您需要查看更多代码,请告诉我。谢谢!

【问题讨论】:

    标签: ios iphone swift camera zooming


    【解决方案1】:

    我在相机实现方面遇到了同样的问题。要解决这个问题,您需要了解两件事。

    • 最大和最小缩放必须在一个值范围内,否则会导致相机放大太多。
    • 与实际图像不保存放大的图像一样,这是一个常见的错误,网上很多解决方案都没有涵盖。这实际上是因为您只是更改了视图的缩放,而不是实际的 AVCaptureDevice 的缩放。

    要改变这两件事,你需要这样的东西:

    func pinch(pinch: UIPinchGestureRecognizer) {
       var device: AVCaptureDevice = self.videoDevice
       var vZoomFactor = ((gestureRecognizer as! UIPinchGestureRecognizer).scale)
       var error:NSError!
            do{
                try device.lockForConfiguration()
                defer {device.unlockForConfiguration()}
                if (vZoomFactor <= device.activeFormat.videoMaxZoomFactor){
                    device.videoZoomFactor = vZoomFactor
                }else{
                NSLog("Unable to set videoZoom: (max %f, asked %f)", device.activeFormat.videoMaxZoomFactor, vZoomFactor);
                }
            }catch error as NSError{
                 NSLog("Unable to set videoZoom: %@", error.localizedDescription);
            }catch _{
    
            }
    }
    

    如您所见,我为视频设备 (videoDevice) 使用了一个类变量来跟踪我用于视觉组件的捕获设备。我将缩放限制在特定范围内并更改设备上的缩放属性,而不是视图本身!

    【讨论】:

    • 缺少一件事。您必须跟踪当前缩放系数并将其用于计算应设置的缩放系数。但是感谢您的出色回答!
    • 嗨,当我尝试缩小时,您的回答让我崩溃了。你能告诉我哪里出错了吗?
    【解决方案2】:
        var device: AVCaptureDevice = self.backCamera
        var vZoomFactor = sender.scale
        var error:NSError!
        do{
            try device.lockForConfiguration()
            defer {device.unlockForConfiguration()}
            if (vZoomFactor <= device.activeFormat.videoMaxZoomFactor) {
    
                let desiredZoomFactor:CGFloat = vZoomFactor + atan2(sender.velocity, 5.0);
                device.videoZoomFactor = max(1.0, min(desiredZoomFactor, device.activeFormat.videoMaxZoomFactor));
            }
            else {
    
                NSLog("Unable to set videoZoom: (max %f, asked %f)", device.activeFormat.videoMaxZoomFactor, vZoomFactor);
            }
        }
        catch error as NSError{
    
            NSLog("Unable to set videoZoom: %@", error.localizedDescription);
        }
        catch _{
    
        }
    

    【讨论】:

      【解决方案3】:

      如果需要手动 zoomTo(2.0) 函数,可以使用这个

      // Create listener for Pinch to Zoom
      let pinchRecognizer = UIPinchGestureRecognizer(target: self, action:#selector(FSCameraView.pinchToZoom(_:)))
      pinchRecognizer.delegate = self
      self.previewViewContainer.addGestureRecognizer(pinchRecognizer)
      
      // set the zoom to a zoomed in mode from start
      setZoom(CGFloat(2.0)
      
      
      
      // and the functions
      func pinchToZoom(sender:UIPinchGestureRecognizer) {
          var vZoomFactor = ((sender as! UIPinchGestureRecognizer).scale)
          setZoom(vZoomFactor)
      }
      
      func setZoom(zoomFactor:CGFloat) {
          var device: AVCaptureDevice = self.device!
          var error:NSError!
          do{
              try device.lockForConfiguration()
              defer {device.unlockForConfiguration()}
              if (zoomFactor <= device.activeFormat.videoMaxZoomFactor) {
      
                  let desiredZoomFactor:CGFloat = zoomFactor + atan2(sender.velocity, 5.0);
                  device.videoZoomFactor = max(1.0, min(desiredZoomFactor, device.activeFormat.videoMaxZoomFactor));
              }
              else {
                  NSLog("Unable to set videoZoom: (max %f, asked %f)", device.activeFormat.videoMaxZoomFactor, zoomFactor);
              }
          }
          catch error as NSError{
              NSLog("Unable to set videoZoom: %@", error.localizedDescription);
          }
          catch _{
          }
      }
      

      【讨论】:

        【解决方案4】:

        要扩展 Ritvik Upadhyaya 的答案,您还需要保存以前的缩放系数来计算新的缩放系数,您不希望每次抬起时缩放都重置为正常手指并再次尝试缩放。

        // To track the zoom factor
        var prevZoomFactor: CGFloat = 1
        
        func pinch(pinch: UIPinchGestureRecognizer) {
            var device: AVCaptureDevice = self.videoDevice
        
            // Here we multiply vZoomFactor with the previous zoom factor if it exist. 
            // Else just multiply by 1
            var vZoomFactor = pinch.scale * prevZoomFactor
        
            // If the pinching has ended, update prevZoomFactor.
            // Note that we set the limit at 1, because zoom factor cannot be less than 1 or the setting device.videoZoomFactor will crash
            if sender.state == .ended {
                prevZoomFactor = zoomFactor >= 1 ? zoomFactor : 1
            }
        
            do {
                try device.lockForConfiguration()
                defer {device.unlockForConfiguration()}
                if (vZoomFactor <= device.activeFormat.videoMaxZoomFactor) {
                    device.videoZoomFactor = vZoomFactor
                } else {
                    print("Unable to set videoZoom: (max \(device.activeFormat.videoMaxZoomFactor), asked \(vZoomFactor))")
              }
            } catch {
                print("\(error.localizedDescription)")
            }
        }
        

        【讨论】:

        • 你好。如果 vZoomFactor 小于 1.0,应用程序不会崩溃吗?
        【解决方案5】:

        斯威夫特 3.0 || 4.0


        1.定义缩放级别。

        let minimumZoom: CGFloat = 1.0
        let maximumZoom: CGFloat = 3.0
        var lastZoomFactor: CGFloat = 1.0
        


        2.在 CameraView 上添加捏合手势。

        let pinchRecognizer = UIPinchGestureRecognizer(target: self, action:#selector(pinch(_:)))        
                    self.viewCamera.addGestureRecognizer(pinchRecognizer)
        


        3.具有zoominzoom out逻辑的捏动方法

        func pinch(_ pinch: UIPinchGestureRecognizer) {
                guard let device = videoDeviceInput.device else { return }
        
                // Return zoom value between the minimum and maximum zoom values
                func minMaxZoom(_ factor: CGFloat) -> CGFloat {
                    return min(min(max(factor, minimumZoom), maximumZoom), device.activeFormat.videoMaxZoomFactor)
                }
        
                func update(scale factor: CGFloat) {
                    do {
                        try device.lockForConfiguration()
                        defer { device.unlockForConfiguration() }
                        device.videoZoomFactor = factor
                    } catch {
                        print("\(error.localizedDescription)")
                    }
                }
        
                let newScaleFactor = minMaxZoom(pinch.scale * lastZoomFactor)
        
                switch pinch.state {
                case .began: fallthrough
                case .changed: update(scale: newScaleFactor)
                case .ended:
                    lastZoomFactor = minMaxZoom(newScaleFactor)
                    update(scale: lastZoomFactor)
                default: break
                }
            }
        


        谢谢。编码愉快??

        【讨论】:

        • 答案写得很好。谢谢!
        • 谢谢很好的例子。
        【解决方案6】:

        您可以通过简单地将 UIPinchGestureRecognizer.scale 重置为 1 来避免保存 prevZoomFactor,如下所示:

            @IBAction func pinchAction(_ sender: UIPinchGestureRecognizer) {
                guard let device = currentCaptureDevice else {return}
                var zoom = device.videoZoomFactor * sender.scale
                sender.scale = 1.0
                var error:NSError!
                do{
                    try device.lockForConfiguration()
                    defer {device.unlockForConfiguration()}
                    if zoom >= device.minAvailableVideoZoomFactor && zoom <= device.maxAvailableVideoZoomFactor {
                        device.videoZoomFactor = zoom
                    }else{
                        NSLog("Unable to set videoZoom: (max %f, asked %f)", device.activeFormat.videoMaxZoomFactor, zoom);
                    }
                }catch error as NSError{
                    NSLog("Unable to set videoZoom: %@", error.localizedDescription);
                }catch _{
                }
            }
        

        这是 Apple 在我参加的一次 WWDC 活动中推荐的,当时手势识别器刚问世。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-08
          • 2020-10-01
          • 1970-01-01
          • 1970-01-01
          • 2018-04-22
          相关资源
          最近更新 更多