AVFoundation点击以聚焦反馈矩形

Ale*_*der 20 iphone avfoundation ipad ios

我正在开发一个iphone应用程序,我直接使用AVFoundation通过相机捕获视频.

我已经实现了一项功能来tap to focus为用户启用该功能.

- (void) focus:(CGPoint) aPoint;
{
#if HAS_AVFF
    Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice");
    if (captureDeviceClass != nil) {        
        AVCaptureDevice *device = [captureDeviceClass defaultDeviceWithMediaType:AVMediaTypeVideo];
        if([device isFocusPointOfInterestSupported] &&
           [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
            CGRect screenRect = [[UIScreen mainScreen] bounds];
            double screenWidth = screenRect.size.width;
            double screenHeight = screenRect.size.height;
            double focus_x = aPoint.x/screenWidth;
            double focus_y = aPoint.y/screenHeight;
            if([device lockForConfiguration:nil]) {
                [device setFocusPointOfInterest:CGPointMake(focus_x,focus_y)];
                [device setFocusMode:AVCaptureFocusModeAutoFocus];
                if ([device isExposureModeSupported:AVCaptureExposureModeAutoExpose]){
                    [device setExposureMode:AVCaptureExposureModeAutoExpose];
                }
                [device unlockForConfiguration];
            }
        }
    }
#endif
}
Run Code Online (Sandbox Code Playgroud)

到目前为止一直很好,但我错过了照片应用程序中的反馈矩形.有没有办法告诉AVFoundation Framework显示这个反馈矩形还是我必须自己实现这个功能?

Ani*_*nil 35

这就是我所做的:这是创建当用户点击相机覆盖图时显示的正方形的类.

CameraFocusSquare.h

#import <UIKit/UIKit.h>
@interface CameraFocusSquare : UIView
@end


CameraFocusSquare.m

#import "CameraFocusSquare.h"
#import <QuartzCore/QuartzCore.h>

const float squareLength = 80.0f;
@implementation FBKCameraFocusSquare

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code

        [self setBackgroundColor:[UIColor clearColor]];
        [self.layer setBorderWidth:2.0];
        [self.layer setCornerRadius:4.0];
        [self.layer setBorderColor:[UIColor whiteColor].CGColor];

        CABasicAnimation* selectionAnimation = [CABasicAnimation
                                                animationWithKeyPath:@"borderColor"];
        selectionAnimation.toValue = (id)[UIColor blueColor].CGColor;
        selectionAnimation.repeatCount = 8;
        [self.layer addAnimation:selectionAnimation
                          forKey:@"selectionAnimation"];

    }
    return self;
}
@end
Run Code Online (Sandbox Code Playgroud)

在您收到水龙头的视图中,执行以下操作:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [[event allTouches] anyObject];
    CGPoint touchPoint = [touch locationInView:touch.view];
    [self focus:touchPoint];

    if (camFocus)
    {
        [camFocus removeFromSuperview];
    }
    if ([[touch view] isKindOfClass:[FBKVideoRecorderView class]])
    {
        camFocus = [[CameraFocusSquare alloc]initWithFrame:CGRectMake(touchPoint.x-40, touchPoint.y-40, 80, 80)];
        [camFocus setBackgroundColor:[UIColor clearColor]];
        [self addSubview:camFocus];
        [camFocus setNeedsDisplay];

        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:1.5];
        [camFocus setAlpha:0.0];
        [UIView commitAnimations];
    }
}

- (void) focus:(CGPoint) aPoint;
{
    Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice");
    if (captureDeviceClass != nil) {
        AVCaptureDevice *device = [captureDeviceClass defaultDeviceWithMediaType:AVMediaTypeVideo];
        if([device isFocusPointOfInterestSupported] &&
           [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
            CGRect screenRect = [[UIScreen mainScreen] bounds];
            double screenWidth = screenRect.size.width;
            double screenHeight = screenRect.size.height;
            double focus_x = aPoint.x/screenWidth;
            double focus_y = aPoint.y/screenHeight;
            if([device lockForConfiguration:nil]) {
                [device setFocusPointOfInterest:CGPointMake(focus_x,focus_y)];
                [device setFocusMode:AVCaptureFocusModeAutoFocus];
                if ([device isExposureModeSupported:AVCaptureExposureModeAutoExpose]){
                    [device setExposureMode:AVCaptureExposureModeAutoExpose];
                }
                [device unlockForConfiguration];
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Pel*_*avn 13

添加到Anil的精彩答案:您应该看看AVCaptureVideoPreviewLayercaptureDevicePointOfInterestForPoint:而不是自己进行计算.它将为您提供更加一致的焦点(可从iOS 6和前进中获得).

- (void) focus:(CGPoint) aPoint;
{
    Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice");
    if (captureDeviceClass != nil) {
        AVCaptureDevice *device = [captureDeviceClass defaultDeviceWithMediaType:AVMediaTypeVideo];
        if([device isFocusPointOfInterestSupported] &&
           [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {

            CGPoint focusPoint = [self.captureVideoPreviewLayer captureDevicePointOfInterestForPoint:aPoint];
            if([device lockForConfiguration:nil]) {
                [device setFocusPointOfInterest:CGPointMake(focusPoint.x,focusPoint.y)];
                [device setFocusMode:AVCaptureFocusModeAutoFocus];
                if ([device isExposureModeSupported:AVCaptureExposureModeAutoExpose]){
                    [device setExposureMode:AVCaptureExposureModeAutoExpose];
                }
                [device unlockForConfiguration];
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

该文档可在此处获得: https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVCaptureVideoPreviewLayer_Class/index.html#//apple_ref/occ/instm/AVCaptureVideoPreviewLayer/captureDevicePointOfInterestForPoint:


ode*_*ens 9

Swift实现:

CameraFocusSquare视图:

class CameraFocusSquare: UIView,CAAnimationDelegate {

internal let kSelectionAnimation:String = "selectionAnimation"

fileprivate var _selectionBlink: CABasicAnimation?

convenience init(touchPoint: CGPoint) {
    self.init()
    self.updatePoint(touchPoint)
    self.backgroundColor = UIColor.clear
    self.layer.borderWidth = 2.0
    self.layer.borderColor = UIColor.orange.cgColor
    initBlink()
}

override init(frame: CGRect) {
    super.init(frame: frame)
}

fileprivate func initBlink() {
    // create the blink animation
    self._selectionBlink = CABasicAnimation(keyPath: "borderColor")
    self._selectionBlink!.toValue = (UIColor.white.cgColor as AnyObject)
    self._selectionBlink!.repeatCount = 3
    // number of blinks
    self._selectionBlink!.duration = 0.4
    // this is duration per blink
    self._selectionBlink!.delegate = self
}



required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

/**
 Updates the location of the view based on the incoming touchPoint.
 */

func updatePoint(_ touchPoint: CGPoint) {
    let squareWidth: CGFloat = 100
    let frame: CGRect = CGRect(x: touchPoint.x - squareWidth / 2, y: touchPoint.y - squareWidth / 2, width: squareWidth, height: squareWidth)
    self.frame = frame
}
/**
 This unhides the view and initiates the animation by adding it to the layer.
 */

func animateFocusingAction() {

    if let blink = _selectionBlink {
        // make the view visible
        self.alpha = 1.0
        self.isHidden = false
        // initiate the animation
        self.layer.add(blink, forKey: kSelectionAnimation)
    }

}
/**
 Hides the view after the animation stops. Since the animation is automatically removed, we don't need to do anything else here.
 */

public func animationDidStop(_ anim: CAAnimation, finished flag: Bool){
    if flag{
        // hide the view
        self.alpha = 0.0
        self.isHidden = true
    }
}
Run Code Online (Sandbox Code Playgroud)

}

手势动作:

 open func tapToFocus(_ gesture : UILongPressGestureRecognizer) {

    if (gesture.state == UIGestureRecognizerState.began) {

        let touchPoint:CGPoint = gesture.location(in: self.previewView)

        if let fsquare = self.focusSquare {
            fsquare.updatePoint(touchPoint)
        }else{
            self.focusSquare = CameraFocusSquare(touchPoint: touchPoint)
            self.previewView.addSubview(self.focusSquare!)
            self.focusSquare?.setNeedsDisplay()
        }

        self.focusSquare?.animateFocusingAction()

        let convertedPoint:CGPoint = self.previewLayer!.captureDevicePointOfInterest(for: touchPoint)

        let currentDevice:AVCaptureDevice = self.videoDeviceInput!.device

        if currentDevice.isFocusPointOfInterestSupported && currentDevice.isFocusModeSupported(AVCaptureFocusMode.autoFocus){

            do {

                try currentDevice.lockForConfiguration()
                currentDevice.focusPointOfInterest = convertedPoint
                currentDevice.focusMode = AVCaptureFocusMode.autoFocus

                if currentDevice.isExposureModeSupported(AVCaptureExposureMode.continuousAutoExposure){
                    currentDevice.exposureMode = AVCaptureExposureMode.continuousAutoExposure
                }
                currentDevice.isSubjectAreaChangeMonitoringEnabled = true
                currentDevice.unlockForConfiguration()

            } catch {

            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


mik*_*eho 7

@Anil的答案是一个很好的开始,但它对我不起作用.我希望能够让用户继续能够选择一个焦点,而不是只选择一次(这是他的解决方案所做的).感谢@Anil指出我正确的方向.

我的解决方案存在一些差异.

  1. 我希望能够重用焦点方块和动画,而不是只重复一次.
  2. 我希望动画在完成后消失(我无法得到@ Anil的解决方案).
  3. 而不是使用initWithFrame:,我实现了自己的initWithTouchPoint:.
  4. 我有一种专门为焦点动作设置动画的方法.
  5. 我还有一种更新帧位置的方法.
  6. 框架的大小在CameraFocusSquare其中,这意味着根据需要更容易查找和更新大小.

CameraFocusSquare.h

@import UIKit;

@interface CameraFocusSquare : UIView

- (instancetype)initWithTouchPoint:(CGPoint)touchPoint;
- (void)updatePoint:(CGPoint)touchPoint;
- (void)animateFocusingAction;

@end
Run Code Online (Sandbox Code Playgroud)

CameraFocusSquare.m

#import "CameraFocusSquare.h"

@implementation CameraFocusSquare {
    CABasicAnimation *_selectionBlink;
}

/**
 This is the init method for the square. It sets the frame for the view and sets border parameters. It also creates the blink animation.
 */
- (instancetype)initWithTouchPoint:(CGPoint)touchPoint {
    self = [self init];
    if (self) {
        [self updatePoint:touchPoint];
        self.backgroundColor = [UIColor clearColor];
        self.layer.borderWidth = 2.0f;
        self.layer.borderColor = [UIColor orangeColor].CGColor;

        // create the blink animation
        _selectionBlink = [CABasicAnimation
                animationWithKeyPath:@"borderColor"];
        _selectionBlink.toValue = (id)[UIColor whiteColor].CGColor;
        _selectionBlink.repeatCount = 3;  // number of blinks
        _selectionBlink.duration = 0.4;  // this is duration per blink
        _selectionBlink.delegate = self;
    }
    return self;
}

/**
 Updates the location of the view based on the incoming touchPoint.
 */
- (void)updatePoint:(CGPoint)touchPoint {
    CGFloat squareWidth = 50;
    CGRect frame = CGRectMake(touchPoint.x - squareWidth/2, touchPoint.y - squareWidth/2, squareWidth, squareWidth);
    self.frame = frame;
}

/**
 This unhides the view and initiates the animation by adding it to the layer.
 */
- (void)animateFocusingAction {
    // make the view visible
    self.alpha = 1.0f;
    self.hidden = NO;
    // initiate the animation
    [self.layer addAnimation:_selectionBlink forKey:@"selectionAnimation"];
}

/**
 Hides the view after the animation stops. Since the animation is automatically removed, we don't need to do anything else here.
 */
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag {
    // hide the view
    self.alpha = 0.0f;
    self.hidden = YES;
}

@end
Run Code Online (Sandbox Code Playgroud)

我在视图之上发起了所有这些.这使我具有更大的灵活性,并将我的UI代码与我的控制器代码分开(想想MVC).

PreviewView.h

@import UIKit;

@interface PreviewView : UIView

- (IBAction)tapToFocus:(UITapGestureRecognizer *)gestureRecognizer;

@end
Run Code Online (Sandbox Code Playgroud)

PreviewView.m

#import "PreviewView.h"
#import "CameraFocusSquare.h"

@implementation PreviewView {
    CameraFocusSquare *_focusSquare;
}

- (IBAction)tapToFocus:(UITapGestureRecognizer *)gestureRecognizer {
    CGPoint touchPoint = [gestureRecognizer locationOfTouch:0 inView:self];
    if (!_focusSquare) {
        _focusSquare = [[CameraFocusSquare alloc] initWithTouchPoint:touchPoint];
        [self addSubview:_focusSquare];
        [_focusSquare setNeedsDisplay];
    }
    else {
        [_focusSquare updatePoint:touchPoint];
    }
    [_focusSquare animateFocusingAction];
}

@end
Run Code Online (Sandbox Code Playgroud)

最后,在我的UIViewController子类中,我UITapGestureRecognizer创建并附加到视图中.我也在这里实现了tap-to-focus代码.

CameraViewController.m

- (void)viewDidLoad {
    // do other initialization stuff here

    // create the tap-to-focus gesture
    UITapGestureRecognizer *tapToFocusRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapToFocus:)];
    tapToFocusRecognizer.numberOfTapsRequired = 1;
    tapToFocusRecognizer.numberOfTouchesRequired = 1;
    [self.previewView addGestureRecognizer:tapToFocusRecognizer];
}

- (IBAction)tapToFocus:(UITapGestureRecognizer *)tapGestureRecognizer {
    if (!_captureDevice) {
        return;
    }
    if (![_captureDevice isFocusPointOfInterestSupported]) {
        return;
    }
    if (![_captureDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
        return;
    }
    [self.previewView tapToFocus:tapGestureRecognizer];
    NSError *error;
    [_captureDevice lockForConfiguration:&error];
    if (error) {
        NSLog(@"Error trying to lock configuration of camera. %@", [error localizedDescription]);
        return;
    }
    CGPoint touchPoint = [tapGestureRecognizer locationOfTouch:0 inView:self.cameraView];
    // range of touch point is from (0,0) to (1,1)
    CGFloat touchX = touchPoint.x / self.previewView.frame.size.width;
    CGFloat touchY = touchPoint.y / self.previewView.frame.size.height;

    _captureDevice.focusMode = AVCaptureFocusModeAutoFocus;
    if ([_captureDevice isExposureModeSupported:AVCaptureExposureModeAutoExpose]) {
        _captureDevice.exposureMode = AVCaptureExposureModeAutoExpose;
    }
    _captureDevice.focusPointOfInterest = CGPointMake(touchX, touchY);
    if ([_captureDevice isExposurePointOfInterestSupported]) {
        _captureDevice.exposurePointOfInterest = CGPointMake(touchX, touchY);
    }
    [_captureDevice unlockForConfiguration];
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助人们,以便他们可以转移到更重要的代码!