AVCaptureDevice Camera Zoom

前端 未结 9 588
没有蜡笔的小新
没有蜡笔的小新 2021-01-31 19:51

I have a simple AVCaptureSession running to get a camera feed in my app and take photos. How can I implement the \'pinch to zoom\' functionality using a UIGestureRecognize

相关标签:
9条回答
  • 2021-01-31 19:57

    Many have tried to do this by setting the transform property on the layer to CGAffineTransformMakeScale(gesture.scale.x, gesture.scale.y); See here for a full fledged implementation of pinch-to-zoom.

    0 讨论(0)
  • 2021-01-31 19:59

    I am using iOS SDK 8.3 and the AVfoundation framework and for me using the following method worked for :

    nameOfAVCaptureVideoPreviewLayer.affineTransform = CGAffineTransformMakeScale(scaleX, scaleY) 
    

    For saving the picture with the same scale I used the following method:

    nameOfAVCaptureConnection.videoScaleAndCropFactor = factorNumber; 
    

    The code bellow is for getting the image in the scale

    [stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
            if(imageDataSampleBuffer != NULL){
    
                NSData *imageData = [AVCaptureStillImageOutput  jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
                UIImage *image = [UIImage imageWithData:imageData];
    }
    }];
    
    0 讨论(0)
  • 2021-01-31 20:07

    based on @Gabriel Cartier 's answer :

    - (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);
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-31 20:10

    The accepted answer is actually outdated and I'm not sure it will actually take the photo of the zoomed in image. There is a method to zoom in like bcattle answer says. The problem of his answer is that it does not take in charge the fact that the user can zoom in and then restart from that zoom position. His solution will create some kind of jumps that are not really elegant.

    The easiest and most elegant way of doing this is to use the velocity of the pinch gesture.

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

    I found that adding the arctan function to the velocity will ease the zoom in zoom out effect a bit. It is not exactly perfect but the effect is good enough for the needs. There could probably be another function to ease the zoom out when it almost reaches 1.

    NOTE: Also, the scale of a pinch gesture goes from 0 to infinite with 0 to 1 being pinching in (zoom out) and 1 to infinite being pinching out (zoom in). To get a good zoom in zoom out effect with this you'd need to have a math equation. Velocity is actually from -infinite to infinite with 0 being the starting point.

    EDIT: Fixed crash on range exception. Thanks to @garafajon!

    0 讨论(0)
  • 2021-01-31 20:10

    Since iOS 7 you can set the zoom directly with the videoZoomFactor property of AVCaptureDevice.

    Tie the scale property of the UIPinchGestureRecognizer to thevideoZoomFactor with a scaling constant. This will let you vary the sensitivity to taste:

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

    Note that AVCaptureDevice, along everything else related to AVCaptureSession, is not thread safe. So you probably don't want to do this from the main queue.

    0 讨论(0)
  • 2021-01-31 20:13

    In swift version, you can zoom in/out by simply passing scaled number on videoZoomFactor. Following code in UIPinchGestureRecognizer handler will solve the issue.

    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
    }
    

    In here, pivotPinchScale is a CGFloat property that declared in your controller somewhere.

    You may also refer to following project to see how camera works with UIPinchGestureRecognizer. https://github.com/DragonCherry/CameraPreviewController

    0 讨论(0)
提交回复
热议问题