Domanda

I am cloning Apple's camera app using AVCaptureSession based on Apple's AppCam app sample. The problem is I cannot see focus rectangle in the video preview screen. I used following code for setting focus, but still focus rectangle is not shown.

  AVCaptureDevice *device = [[self videoInput] device];
if ([device isFocusModeSupported:focusMode] && [device focusMode] != focusMode) {
    NSError *error;

      printf(" setFocusMode    \n");
    if ([device lockForConfiguration:&error]) {
        [device setFocusMode:focusMode];
        [device unlockForConfiguration];
    } else {
        id delegate = [self delegate];
        if ([delegate respondsToSelector:@selector(acquiringDeviceLockFailedWithError:)]) {
            [delegate acquiringDeviceLockFailedWithError:error];
        }
    }    
}

When I use UIImagePickerController, auto focus, tap focus are supported by default, and can see focus rectangle. Is there no way to show focus rectangle in the video preview layer using AVCaptureSession?

È stato utile?

Soluzione

The focus animation is a complete custom animation which you have to create by your own. I am currently having exact the same problem like you: I want to show a rectangle as a feedback for the user after he tapped the preview layer.

The first thing you want to do is implementing the tap-to-focus, probably where you initiate the preview layer:

UITapGestureRecognizer *tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapToFocus:)];
[tapGR setNumberOfTapsRequired:1];
[tapGR setNumberOfTouchesRequired:1];
[self.captureVideoPreviewView addGestureRecognizer:tapGR];

Now implement the tap-to-focus method itself:

-(void)tapToFocus:(UITapGestureRecognizer *)singleTap{
    CGPoint touchPoint = [singleTap locationInView:self.captureVideoPreviewView];
    CGPoint convertedPoint = [self.captureVideoPreviewLayer captureDevicePointOfInterestForPoint:touchPoint];
    AVCaptureDevice *currentDevice = currentInput.device;

    if([currentDevice isFocusPointOfInterestSupported] && [currentDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]){
        NSError *error = nil;
        [currentDevice lockForConfiguration:&error];
        if(!error){
            [currentDevice setFocusPointOfInterest:convertedPoint];
            [currentDevice setFocusMode:AVCaptureFocusModeAutoFocus];
            [currentDevice unlockForConfiguration];
        }    
    }
}

The last thing, which i haven't implemented by myself yet, is to add the focusing animation to the preview layer or rather the view controller which is holding the preview layer. I believe that could be done in tapToFocus:. There you already have the touch point. Simply add a animated image view or some other view which has the touch position as its center. After the animation has finished, remove the image view.

Altri suggerimenti

Swift implementation

Gesture:

 private func focusGesture() -> UITapGestureRecognizer {

    let tapRec: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(kTapToFocus))
    tapRec.cancelsTouchesInView = false
    tapRec.numberOfTapsRequired = 1
    tapRec.numberOfTouchesRequired = 1

    return tapRec
}

Action:

  private func tapToFocus(gesture : UITapGestureRecognizer) {

    let touchPoint:CGPoint = gesture.locationInView(self.previewView)
    let convertedPoint:CGPoint = previewLayer!.captureDevicePointOfInterestForPoint(touchPoint)

    let currentDevice:AVCaptureDevice = videoDeviceInput!.device

    if currentDevice.focusPointOfInterestSupported && currentDevice.isFocusModeSupported(AVCaptureFocusMode.AutoFocus){
        do {
            try currentDevice.lockForConfiguration()
            currentDevice.focusPointOfInterest = convertedPoint
            currentDevice.focusMode = AVCaptureFocusMode.AutoFocus
            currentDevice.unlockForConfiguration()
        } catch {

        }
    }

}

swift3 implementation

lazy var focusGesture: UITapGestureRecognizer = {
    let instance = UITapGestureRecognizer(target: self, action: #selector(tapToFocus(_:)))
    instance.cancelsTouchesInView = false
    instance.numberOfTapsRequired = 1
    instance.numberOfTouchesRequired = 1
    return instance
}()

func tapToFocus(_ gesture: UITapGestureRecognizer) {
    guard let previewLayer = previewLayer else {
        print("Expected a previewLayer")
        return
    }
    guard let device = device else {
        print("Expected a device")
        return
    }
    
    let touchPoint: CGPoint = gesture.location(in: cameraView)
    let convertedPoint: CGPoint = previewLayer.captureDevicePointOfInterest(for: touchPoint)
    if device.isFocusPointOfInterestSupported && device.isFocusModeSupported(AVCaptureFocusMode.autoFocus) {
        do {
            try device.lockForConfiguration()
            device.focusPointOfInterest = convertedPoint
            device.focusMode = AVCaptureFocusMode.autoFocus
            device.unlockForConfiguration()
        } catch {
            print("unable to focus")
        }
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top