web-dev-qa-db-ja.com

フォーカスするiOS AVFoundationタップ

私は多かれ少なかれデフォルトのカメラアプリのように振る舞うカメラアプリを作成しようとしています。現時点ではうまくいかないのは、タップしてフォーカスすることです。カメラに焦点を合わせて、実際のカメラアプリと同じように、タッチした場所で何でもできるようにしたいと思います。

これが私のviewDidLoadです

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Session
    _session = [[AVCaptureSession alloc] init];
    _session.sessionPreset = AVCaptureSessionPresetPhoto;

    // Input
    _videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    _videoInput = [AVCaptureDeviceInput deviceInputWithDevice:_videoDevice error:nil];

    // Output
    _frameOutput = [[AVCaptureVideoDataOutput alloc] init];
    _frameOutput.videoSettings = [NSDictionary dictionaryWithObject:AVVideoCodecJPEG forKey:AVVideoCodecKey];

    [_frameOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()];
    [_session addInput:_videoInput];
    [_session addOutput:_frameOutput];
    [_session startRunning];
};

そして、これが私のカメラフォーカスをワンクリックにする方法です。

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    [touches enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
        UITouch *touch = obj;
        CGPoint touchPoint = [touch locationInView:touch.view];
        focusLayer.frame = CGRectMake((touchPoint.x-25), (touchPoint.y-25), 50, 50);

        if ([_videoDevice isFocusPointOfInterestSupported]) {
            NSError *error;
            if ([_videoDevice lockForConfiguration:&error]) {
                [_videoDevice setFocusPointOfInterest:touchPoint];
                [_videoDevice setExposurePointOfInterest:touchPoint];

                [_videoDevice setFocusMode:AVCaptureFocusModeAutoFocus];
                if ([_videoDevice isExposureModeSupported:AVCaptureExposureModeAutoExpose]){
                    [_videoDevice setExposureMode:AVCaptureExposureModeAutoExpose];
                }
                [_videoDevice unlockForConfiguration];
            }
        }


        // NSLog(@"x = %f, y = %f", touchPoint.x, touchPoint.y);
    }];
}

画面をクリックしても何も起こりません。

25
spacecash21

次のコードのようなものを使用して、touchPointを[0,1]の範囲に調整する必要があります。

    CGRect screenRect = [[UIScreen mainScreen] bounds];
    screenWidth = screenRect.size.width;
    screenHeight = screenRect.size.height;  
    double focus_x = thisFocusPoint.center.x/screenWidth;
    double focus_y = thisFocusPoint.center.y/screenHeight;

    [[self captureManager].videoDevice lockForConfiguration:&error];
    [[self captureManager].videoDevice setFocusPointOfInterest:CGPointMake(focus_x,focus_y)];
    [[self captureManager].videoDevice unlockForConfiguration];

これに関するドキュメントは Apple-AV Foundationプログラミングガイドライン-セクションMedia Captureを参照してください。 フォーカスモードに関する情報を見つける

サポートされている場合は、focusPointOfInterestを使用してフォーカルポイントを設定します。 CGPointを渡します。{0,0}は画像領域の左上を表し、{1,1}は右がホームボタンの横長モードの右下を表します。これは、デバイスが縦長モードであっても適用されます。

33
Konrad Lang
UITapGestureRecognizer *shortTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapToFocus:)];
shortTap.numberOfTapsRequired=1;
shortTap.numberOfTouchesRequired=1;
[viewCanvasRecording addGestureRecognizer:shortTap];

そしてこれ:

- (void)handleTapToFocus:(UITapGestureRecognizer *)tapGesture
{
    AVCaptureDevice *acd=!currentFrontCamera ? captureBackInput.device : captureFrontInput.device;

    if (tapGesture.state == UIGestureRecognizerStateEnded)
    {
        CGPoint thisFocusPoint = [tapGesture locationInView:viewCanvasRecording];

        double focus_x = thisFocusPoint.x/viewCanvasRecording.frame.size.width;
        double focus_y = thisFocusPoint.y/viewCanvasRecording.frame.size.height;

        if ([acd isFocusModeSupported:AVCaptureFocusModeAutoFocus] && [acd isFocusPointOfInterestSupported])
        {
            if ([acd lockForConfiguration:nil])
            {
                [acd setFocusMode:AVCaptureFocusModeAutoFocus];
                [acd setFocusPointOfInterest:CGPointMake(focus_x, focus_y)];

                /*
                if ([acd isExposureModeSupported:AVCaptureExposureModeAutoExpose] && [acd isExposurePointOfInterestSupported])
                {
                    [acd setExposureMode:AVCaptureExposureModeAutoExpose];
                    [acd setExposurePointOfInterest:CGPointMake(focus_x, focus_y)];
                }*/

                [acd unlockForConfiguration];
            }
        }
    }
}

A Swiftバージョン:

@IBAction func tapToFocus(_ sender: UITapGestureRecognizer) {
    if (sender.state == .ended) {
        let thisFocusPoint = sender.location(in: previewView)

        print("touch to focus ", thisFocusPoint)

        let focus_x = thisFocusPoint.x / previewView.frame.size.width
        let focus_y = thisFocusPoint.y / previewView.frame.size.height

        if (captureDevice!.isFocusModeSupported(.autoFocus) && captureDevice!.isFocusPointOfInterestSupported) {
            do {
                try captureDevice?.lockForConfiguration()
                captureDevice?.focusMode = .autoFocus
                captureDevice?.focusPointOfInterest = CGPoint(x: focus_x, y: focus_y)

                if (captureDevice!.isExposureModeSupported(.autoExpose) && captureDevice!.isExposurePointOfInterestSupported) {
                    captureDevice?.exposureMode = .autoExpose;
                    captureDevice?.exposurePointOfInterest = CGPoint(x: focus_x, y: focus_y);
                 }

                captureDevice?.unlockForConfiguration()
            } catch {
                print(error)
            }
        }
    }
}
6
Catalin

これが、AVカメラプレビューのジェスチャーの処理方法です。最初にUITapGestureRecognizerをセットアップしてから、captureDevicePointOfInterestForPointを使用してポイントを取得します。

- (void)setupGestures
{
  UITapGestureRecognizer *tapToFocusRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
                                          action:@selector(handleTapToFocusAndExposureRecognizer:)];
  [self addGestureRecognizer:tapToFocusRecognizer];
}

- (void)handleTapToFocusAndExposureRecognizer:(UITapGestureRecognizer*)tabRecognizer {
  CGPoint touchPoint = [tabRecognizer locationInView:self];
  CGPoint point = [self.previewLayer captureDevicePointOfInterestForPoint:touchPoint];
  AVCaptureDevice *device = [self.videoCaptureDeviceInput device];
  NSError *error = nil;

  if (tabRecognizer.state == UIGestureRecognizerStateEnded) {
    if (![device lockForConfiguration:&error]) {
      if (error) {
        RCTLogError(@"%s: %@", __func__, error);
      }
      return;
    }

    [device setFocusPointOfInterest:CGPointMake(point.x, point.y)];
    [device setFocusMode:AVCaptureFocusModeContinuousAutoFocus];

    [device setExposurePointOfInterest:CGPointMake(point.x, point.y)];
    [device setExposureMode:AVCaptureExposureModeContinuousAutoExposure];

    [device unlockForConfiguration];
  }
}

AVCaptureVideoPreviewLayerを使用してタッチポイントを取得しています。ただし、AVCaptureVideoPreviewLayerの代わりにGLKViewを使用してプレビューをレンダリングする場合、ポイントを直接取得することはできませんが、前の回答のようにポイントを取得する必要があります。

IOS開発用の新しいコーダー。これがお役に立てば幸いです。

1
Feng Liu