Sian 发表于 2015-5-22 14:16:41

使用AVFoundation自定义相机如何调整相机焦距

本帖最后由 Sian 于 2015-5-22 14:19 编辑

1、如何使用AVFoundation框架自定义相机请先参照 http://www.yusian.com/bbs/thread-10503-1-1.html

2.1、上述帖子中有讲到,如果需要对焦,可以通过AVCaptureDevice的setFocusPointOfInterest:方法来实现,传入一个CGPoint值,但这里的CGPoint不是View上面的点,而是范围的0~1的相对百分点;

2.2、这个CGPoint如何得来呢,我们在点击屏幕时可以监听相关View的点击事件,添加一个UITapGestureRecognizer手势,在点时后,可以通过UITapGestureRecognizer的locationInView:方法得到CGPoint,这是一个绝对值,即点击了相关View上的某个点,有了这个点,再通过AVCaptureVideoPreviewLayer的一个转换方法:captureDevicePointOfInterestForPoint:可以将绝对点转换成相对点。

2.3、得到CGPoint后,就可以调用AVCaptureDevice(即摄像头)的setFocusPointOfInterest:方法来实现了,但需要注意的是,这个方法不能直接调用,要分三步曲来完成:锁定AVCaptureDevice,修改参数值,解锁AVCaptureDevice。一般形式如:/// 对焦事件
- (void)focusAtPoint:(CGPoint)point
{
    AVCaptureDevice *device = self.deviceInput.device;
    NSError *error;
    if ( && )
    {
      if () {
            ;   // 对焦点
            ;// 曝光点
            ;// 自动对焦模式
            ;
      } else {
            NSLog(@"Error: %@", error);
      }
    }
}
3、自动对焦实现了,如何调节焦距呢?

3.1、这里所谓的调节焦距不是对焦的意思,而是在拍摄远景时所需要的放大(拉近)影像

3.2、有两种方式来实现,第一种方式,通过放大AVCaptureVideoPreviewLayer及AVCaptureStillImageOutput的videoScaleAndCropFactor属性来实现,简单一点讲就是把预览图层放大,这样在屏幕上就只能看到一部分影像了,然后在捕捉生成图片时做相同倍数的放大,裁剪超出部分的像素实现,这种方式好比原本拍摄的照片是4000*3000的分辨率,现在通过放大只取中间2000*1500的部分输出同样大小的照片,最终的效果就是放大了图像。(如果这部分看不懂,说明没有理解AVFoundation的工作原理,参照:http://www.yusian.com/bbs/thread-10580-1-1.html)

3.3、另一种方式,通过调节AVCaptureDevice的videoZoomFactor属性来实现焦距的调整,这种方式事实上是在图像取景的时候就进行了相关调整,取摄像头的部分影像进入sesstion,这样更合理,并且前面那种方式有个问题:因为是通过放大图层来模拟拉近焦距,所以实际上图层是不清晰的,对焦也没什么效果。然而第二种方式中videoZoomFactor属性需要iOS7以上才支持。

3.4、设置videoZoomFactor属性与对焦一样同样需要三部曲来实现,锁定Device、设置属性、解锁Device

/// 调整摄像头焦距
- (void)setDevice:(AVCaptureDevice *)device videoZoomFactor:(CGFloat)scale
{
    ;
    device.videoZoomFactor = scale;
    ;
}4、关键代码示例:
//
//SACameraCtrl.m
//Test
//
//Created by 余西安 on 15/4/13.
//Copyright (c) 2015年 Sian. All rights reserved.
//

#import "SACameraCtrl.h"
#import "SAPreview.h"
#import "SAPhotoViewCtrl.h"
#import <AVFoundation/AVFoundation.h>
#import <CoreMotion/CoreMotion.h>
#define SourcePath [ pathForResource:@"SAImagePickerController.bundle" ofType:nil]

@interface SACameraCtrl () <UIAccelerometerDelegate>
{
    CGFloat _deviceScale;
}
// 输入流预览图层
@property (nonatomic, strong)   AVCaptureVideoPreviewLayer*previewLayer;

@property (weak, nonatomic) IBOutlet SAPreview *preview;

// AVCaptureSession对象来执行输入设备和输出设备之间的数据传递
@property (nonatomic, strong)   AVCaptureSession            *session;

// 设备输入流
@property (nonatomic, strong)   AVCaptureDeviceInput      *deviceInput;

// 照片输出流
@property (nonatomic, strong)   AVCaptureStillImageOutput   *imageOutput;

// 摄像头焦倍
@property (nonatomic, assign)   CGFloat         deviceScale;

// 图片输出视图
@property (nonatomic, strong)   UIImageView   *cameraShowView;

// 摄像头数组
@property (nonatomic, strong, readonly) NSArray   *devices;       // AVCaptureDevices

// 闪光灯切换按钮
@property (weak, nonatomic) IBOutlet    UIButton    *flashButton;

@end

@implementation SACameraCtrl

- (void)viewDidLoad
{
    ;
    // 创建交互流
    self.session = [ init];
    self.session.sessionPreset = AVCaptureSessionPresetPhoto;
   
    // 媒体输入
    AVCaptureDevice *device = ;
    ;
    self.deviceInput = ;
    if();

    // 媒体输出
    self.imageOutput = [ init];
    self.imageOutput.outputSettings = @{AVVideoCodecKey : AVVideoCodecJPEG};
    AVCaptureConnection * connection = ;
    connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
    if();
   
    // 媒体预览
    self.previewLayer = ;
    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspect;
    ;
    ;
}


#pragma mark - 前后摄像头
- (NSArray *)devices
{
    return ;
}

- (void)viewWillAppear:(BOOL)animated
{
    ;
    self.deviceScale = 1.0;
    self.previewLayer.frame = self.preview.layer.bounds;
    self.navigationController.navigationBar.hidden = YES;
    ;
    ;
}

- (void)viewDidAppear:(BOOL)animated
{
    ;
    [ setStatusBarHidden:YES];
}

- (void)viewWillDisappear:(BOOL)animated
{
    ;
    [ setStatusBarHidden:NO];
}

- (void)viewDidDisappear:(BOOL)animated
{
    ;
    ;
}

/// 媒体预览图层手势事件
- (void)setPreviewGesture
{
    // 注册一个手势事件来实现对焦功能
    UITapGestureRecognizer *tap = [ initWithTarget:self action:@selector(tapPreview:)];
    UIPinchGestureRecognizer *pinch = [ initWithTarget:self action:@selector(pinchPreview:)];
    ;
    if (.systemVersion.floatValue >= 7.0) ;
}

/// 预览图层点击事件
- (void)tapPreview:(UITapGestureRecognizer *)gesture
{
    CGPoint point = ;
    CGPoint p = ;
    ;
    // 对焦动画
    self.preview.aperture.center = point;
    ;
}

/// 焦距调整事件
- (void)pinchPreview:(UIPinchGestureRecognizer *)gesture
{
    CGFloat scale = self.deviceScale + (gesture.scale - 1);
    if (scale > 5) scale = 5;   // 最大5倍焦距
    if (scale < 1) scale = 1;   // 最小1倍焦距
    ;
    // 缩放结束时记录当前倍焦
    if (gesture.state == UIGestureRecognizerStateEnded) self.deviceScale = scale;
}

/// 对焦事件
- (void)focusAtPoint:(CGPoint)point
{
    AVCaptureDevice *device = self.deviceInput.device;
    NSError *error;
    if ( && )
    {
      if () {
            ;   // 对焦点
            ;// 曝光点
            ;// 自动对焦模式
            ;
      } else {
            NSLog(@"Error: %@", error);
      }
    }
}

/// 摄像头切换事件
- (IBAction)switchCamera:(UIButton *)sender
{
    if (self.devices.count < 2) return;
   
    NSInteger oldIndex = ;
    NSInteger newIndex = (oldIndex + 1) % self.devices.count;
    AVCaptureDevice *newDevice = ;
    AVCaptureDeviceInput *newInput = ;
    if (newInput) {
      ;
      ;
      ;
      ;
      self.deviceInput = newInput;
      self.flashButton.hidden = !newDevice.isFlashAvailable;
    }
}

/// 取消事件
- (IBAction)cancel:(UIButton *)sender
{
    ;
}

/// 拍照事件
- (IBAction)shutter:(UIButton *)sender
{
    sender.userInteractionEnabled = NO;
    AVCaptureConnection * connection = ;
    connection.videoOrientation = AVCaptureVideoOrientationPortrait;
    connection.videoScaleAndCropFactor = 1.0;   // 获取流比例
    if (!connection) {
      NSLog(@"take photo failed!");
      return;
    }
   
    [self.imageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
      if (imageDataSampleBuffer == NULL) {
            return;
      }
      NSData * imageData = ;
      UIImage * image = ;
      SAPhotoViewCtrl *photoView = [ initWithImage:image];
      ;
      sender.userInteractionEnabled = YES;
    }];
}

/// 调整摄像头焦距
- (void)setDevice:(AVCaptureDevice *)device videoZoomFactor:(CGFloat)scale
{
    ;
    device.videoZoomFactor = scale;
    ;
}

/// 闪光灯开关按钮
- (IBAction)overTurn:(UIButton *)sender
{
    sender.tag = (sender.tag + 1) % 3;
    NSString *imageName = ;
    forState:UIControlStateNormal];
    ;
}

/// 切换闪光灯模式
- (void)setDevice:(AVCaptureDevice *)device FlashMode:(AVCaptureFlashMode)flashModel
{
    if (device.isFlashAvailable == NO) return;
    if () {
      device.flashMode = flashModel;
    }
    ;
}

@end
5、Demo下载
**** Hidden Message *****

活在梦里丶 发表于 2015-6-26 16:40:27

看一下效果

喵了个咪 发表于 2015-7-10 10:42:47

学习学习{:3_52:}

nullptr 发表于 2015-10-12 18:31:08

haoahoahao

ccclp 发表于 2016-5-12 14:23:36

看看效果,学习学习,
页: [1]
查看完整版本: 使用AVFoundation自定义相机如何调整相机焦距