2013-03-16 24 views
15

私はカメラでビデオをキャプチャするためにAVFoundationを直接使用する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 
} 

これまでのところ、写真のアプリのようなフィードバック矩形がありません。このフィードバック矩形を表示するようにAVFoundation Frameworkに指示する方法はありますか、この機能を自分で実装する必要はありますか?

+1

しかし、あなたは(場合 '使用する必要がありますCaptureDeviceClass!= Nil) ' –

+0

あなたのヒントをありがとう。私は本当に気にしていないし、現在の違いについて知っているので、私はそれを見上げた。私がクラスを参照しているという事実のために、あなたは絶対に正しいです。 – Alexander

+0

@アレクサンダー、私はあなたと同じ問題に直面しています。あなたはこの問題を解決しましたか? – ttotto

答えて

34

私がしたことは次のとおりです。 これは、ユーザーがカメラのオーバーレイをタップしたときに表示される四角形を作成するクラスです。

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 

そして、あなたはあなたのタップを受け取るビューで、次の操作を行います

- (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]; 
      } 
     } 
    } 
} 
+0

コード内の 'camFocus'は何ですか? – iqueqiorio

+0

@iqueqiorio camFocusは、カスタムクラス(コードの最初のスニペット)であるCameraFocusSquare型の変数です。 – Anil

+0

それでは、私は 'CameraFocusSquare * camFocus = [[CameraFocusSquare alloc] init];'しようとしていますが、どうすればエラーになるのですか? – iqueqiorio

11

は、アニルの華麗な答えに追加するには、次の代わりに計算を自分でやって、あなたはAVCaptureVideoPreviewLayerを見ている必要がありますのcaptureDevicePointOfInterestForPoint:。これにより、より一貫したフォーカスポイントが得られます(iOS 6以降で利用可能)。 https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVCaptureVideoPreviewLayer_Class/index.html#//apple_ref/occ/instm/AVCaptureVideoPreviewLayer/captureDevicePointOfInterestForPoint:アニルの答え@

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]; 
      } 
     } 
    } 
} 

ドキュメントはこちらです。私は、ユーザーが一度ではなくフォーカスポイントを選択できるようにしたいと思っていました(これは彼の解決策です)。私を正しい方向に向けるための@Anilに感謝します。

私の解決策にはいくつかの違いがあります。

  1. 私はフォーカスの広場とアニメーションを一度だけではなく再利用できるようにしたいと考えました。
  2. それは私が行うにはアニルのソリューション@得ることができませんでした(何かを完了した後、私は消えるためにアニメーションを望んでいた。
  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 

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 

Iは、ビューの上にこのすべてを開始します。これにより、柔軟性が増し、UIコードとコントローラコード(MVCと考える)が分離されます。

PreviewView.h

@import UIKit; 

@interface PreviewView : UIView 

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

@end 

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 

最後に、私のUIViewControllerサブクラスで、私は私のUITapGestureRecognizerが作成したビューに取り付けられています。ここでは、タップ・ツー・フォーカス・コードを実装しています。

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]; 
} 

は、彼らがより重要なコードの上に移動することができますので、これは人々を役に立てば幸い!

6

スウィフト実装:

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 
    } 
} 

}

ジェスチャーアクション:あなたの問題とは無関係の

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 { 

      } 
     } 
    } 
} 
関連する問題