AVCaptureDevice相机变焦

时间:2012-04-19 02:42:55

标签: iphone objective-c ios avcapturesession avcapture

我有一个简单的AVCaptureSession,可以在我的应用中获取相机并拍照。如何使用相机的UIGestureRecognizer实现“缩放到缩放”功能?

9 个答案:

答案 0 :(得分:42)

接受的答案实际上是过时的,我不确定它是否会实际拍摄放大图像的照片。有一种放大方法,如bcattle回答说。他回答的问题是它没有掌握用户可以放大然后从该变焦位置重新启动的事实。他的解决方案会创造一些不太优雅的跳跃。

这种最简单,最优雅的方法是使用捏合手势的速度。

-(void) handlePinchToZoomRecognizer:(UIPinchGestureRecognizer*)pinchRecognizer {
    const CGFloat pinchVelocityDividerFactor = 5.0f;

    if (pinchRecognizer.state == UIGestureRecognizerStateChanged) {
        NSError *error = nil;
        if ([videoDevice lockForConfiguration:&error]) {
            CGFloat desiredZoomFactor = device.videoZoomFactor + atan2f(pinchRecognizer.velocity, pinchVelocityDividerFactor);
            // Check if desiredZoomFactor fits required range from 1.0 to activeFormat.videoMaxZoomFactor
            device.videoZoomFactor = MAX(1.0, MIN(desiredZoomFactor, device.activeFormat.videoMaxZoomFactor));
            [videoDevice unlockForConfiguration];
        } else {
            NSLog(@"error: %@", error);
        }
    }
}

我发现将arctan函数添加到力度可以轻松缩放缩放效果。它并不完美,但效果足以满足需求。当它几乎达到1时,可能还有另一个功能可以简化缩小。

注意:此外,捏合手势的比例从0变为无穷大,0到1被捏入(缩小),1到无限被捏出(放大)。要想有一个很好的放大缩小效果,你需要有一个数学方程式。速度实际上是从无限到无穷,0是起点。

编辑:修复了范围异常的崩溃问题。感谢@garafajon

答案 1 :(得分:6)

许多人尝试通过将图层上的transform属性设置为CGAffineTransformMakeScale(gesture.scale.x, gesture.scale.y);来实现此目的 有关完全成熟的缩放缩放功能,请参阅here

答案 2 :(得分:5)

从iOS 7开始,您可以使用AVCaptureDevice scale属性直接设置缩放。

使用缩放常量将UIPinchGestureRecognizer的{​​{1}}属性绑定到videoZoomFactor。这将让您改变对口味的敏感度:

-(void) handlePinchToZoomRecognizer:(UIPinchGestureRecognizer*)pinchRecognizer {
    const CGFloat pinchZoomScaleFactor = 2.0;

    if (pinchRecognizer.state == UIGestureRecognizerStateChanged) {
        NSError *error = nil;
        if ([videoDevice lockForConfiguration:&error]) {
            videoDevice.videoZoomFactor = 1.0 + pinchRecognizer.scale * pinchZoomScaleFactor;
            [videoDevice unlockForConfiguration];
        } else {
            NSLog(@"error: %@", error);
        }
    }
}

请注意AVCaptureDevice以及与AVCaptureSession相关的所有其他内容都不是线程安全的。所以你可能不希望从主队列中这样做。

答案 3 :(得分:4)

Swift 4
将捏合手势识别器添加到最前面的视图并将其连接到此操作( pinchToZoom )。 captureDevice 应该是当前为捕获会话提供输入的实例。 pinchToZoom 正面和背面捕获设备提供平滑缩放。

  @IBAction func pinchToZoom(_ pinch: UIPinchGestureRecognizer) {

    guard let device = captureDevice else { return }

    func minMaxZoom(_ factor: CGFloat) -> CGFloat { return min(max(factor, 1.0), device.activeFormat.videoMaxZoomFactor) }

    func update(scale factor: CGFloat) {
      do {
        try device.lockForConfiguration()
        defer { device.unlockForConfiguration() }
        device.videoZoomFactor = factor
      } catch {
        debugPrint(error)
      } 
    }

    let newScaleFactor = minMaxZoom(pinch.scale * zoomFactor)

    switch sender.state {
      case .began: fallthrough
      case .changed: update(scale: newScaleFactor)
      case .ended:
        zoomFactor = minMaxZoom(newScaleFactor)
        update(scale: zoomFactor)
     default: break
   }
 }

在相机或vc上声明zoomFactor非常有用。我通常将它放在具有AVCaptureSession的同一单身人士身上。这将作为captureDevice&#39> videoZoomFactor 的默认值。

var zoomFactor: Float = 1.0

答案 4 :(得分:1)

在swift版本中,您只需在videoZoomFactor上传递缩放的数字即可放大/缩小。以下代码在UIPinchGestureRecognizer处理程序中将解决问题。

do {
    try device.lockForConfiguration()
    switch gesture.state {
    case .began:
        self.pivotPinchScale = device.videoZoomFactor
    case .changed:
        var factor = self.pivotPinchScale * gesture.scale
        factor = max(1, min(factor, device.activeFormat.videoMaxZoomFactor))
        device.videoZoomFactor = factor
    default:
        break
    }
    device.unlockForConfiguration()
} catch {
    // handle exception
}

在这里,pivotPinchScale是一个CGFloat属性,在你的控制器某处声明。

您也可以参考以下项目,了解相机如何与UIPinchGestureRecognizer配合使用。 https://github.com/DragonCherry/CameraPreviewController

答案 5 :(得分:1)

我从@Gabriel Cartier的解决方案开始(谢谢)。在我的代码中,我更倾向于使用更平滑的rampToVideoZoomFactor和更简单的方法来计算设备的比例因子。

re_path(r'^<str:pk>/$', indexView.as_view(), name='index'),

答案 6 :(得分:0)

基于@Gabriel Cartier的回答:

- (void) cameraZoomWithPinchVelocity: (CGFloat)velocity {
    CGFloat pinchVelocityDividerFactor = 40.0f;
    if (velocity < 0) {
        pinchVelocityDividerFactor = 5.; //zoom in
    }

    if (_videoInput) {
        if([[_videoInput device] position] == AVCaptureDevicePositionBack) {
            NSError *error = nil;
            if ([[_videoInput device] lockForConfiguration:&error]) {
                CGFloat desiredZoomFactor = [_videoInput device].videoZoomFactor + atan2f(velocity, pinchVelocityDividerFactor);
                // Check if desiredZoomFactor fits required range from 1.0 to activeFormat.videoMaxZoomFactor
                CGFloat maxFactor = MIN(10, [_videoInput device].activeFormat.videoMaxZoomFactor);
                [_videoInput device].videoZoomFactor = MAX(1.0, MIN(desiredZoomFactor, maxFactor));
                [[_videoInput device] unlockForConfiguration];
            } else {
                NSLog(@"cameraZoomWithPinchVelocity error: %@", error);
            }
        }
    }
}

答案 7 :(得分:0)

有一种使用捏捏识别器处理相机缩放级别的简便方法。您唯一需要做的就是采取cameraDevice.videoZoomFactor并将其设置为.began状态的识别器,例如

@objc private func viewPinched(recognizer: UIPinchGestureRecognizer) {
    switch recognizer.state {
        case .began:
            recognizer.scale = cameraDevice.videoZoomFactor
        case .changed:
            let scale = recognizer.scale
            do {
                 try cameraDevice.lockForConfiguration()
                 cameraDevice.videoZoomFactor = max(cameraDevice.minAvailableVideoZoomFactor, min(scale, cameraDevice.maxAvailableVideoZoomFactor))
                 cameraDevice.unlockForConfiguration()
            }
            catch {
                print(error)
            }
        default:
            break
    }
}

答案 8 :(得分:-2)

我正在使用iOS SDK 8.3和AVfoundation框架,并且使用以下方法为我工作:

nameOfAVCaptureVideoPreviewLayer.affineTransform = CGAffineTransformMakeScale(scaleX, scaleY) 

为了以相同的比例保存图片,我使用了以下方法:

nameOfAVCaptureConnection.videoScaleAndCropFactor = factorNumber; 

下面的代码用于获取比例

中的图像
[stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
        if(imageDataSampleBuffer != NULL){

            NSData *imageData = [AVCaptureStillImageOutput  jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
            UIImage *image = [UIImage imageWithData:imageData];
}
}];