2013-04-11 40 views
32

這使我發瘋,因爲我無法使其工作。我有以下情況:如何從AVCapture中將圖像裁剪到在顯示器上看到的矩形

我使用AVCaptureSessionAVCaptureVideoPreviewLayer來創建我自己的相機界面。界面顯示一個矩形。以下是填充整個屏幕的AVCaptureVideoPreviewLayer

我希望以某種方式裁剪捕獲的圖像,使得生成的圖像精確地顯示在顯示器上的矩形中顯示的內容。

我的設置是這樣的:

_session = [[AVCaptureSession alloc] init]; 
AVCaptureSession *session = _session; 
session.sessionPreset = AVCaptureSessionPresetPhoto; 

AVCaptureDevice *camera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 
if (camera == nil) { 
    [self showImagePicker]; 
    _isSetup = YES; 
    return; 
} 
AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session]; 
captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; 

captureVideoPreviewLayer.frame = self.liveCapturePlaceholderView.bounds; 
[self.liveCapturePlaceholderView.layer addSublayer:captureVideoPreviewLayer]; 

NSError *error; 
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:camera error:&error]; 
if (error) { 
    HGAlertViewWrapper *av = [[HGAlertViewWrapper alloc] initWithTitle:kFailedConnectingToCameraAlertViewTitle message:kFailedConnectingToCameraAlertViewMessage cancelButtonTitle:kFailedConnectingToCameraAlertViewCancelButtonTitle otherButtonTitles:@[kFailedConnectingToCameraAlertViewRetryButtonTitle]]; 
    [av showWithBlock:^(NSString *buttonTitle){ 
     if ([buttonTitle isEqualToString:kFailedConnectingToCameraAlertViewCancelButtonTitle]) { 
      [self.delegate gloameCameraViewControllerDidCancel:self]; 
     } 
     else { 
      [self setupAVSession]; 
     } 
    }]; 
} 
[session addInput:input]; 

NSDictionary *options = @{ AVVideoCodecKey : AVVideoCodecJPEG }; 
_stillImageOutput = [[AVCaptureStillImageOutput alloc] init]; 
[_stillImageOutput setOutputSettings:options]; 

[session addOutput:_stillImageOutput]; 

[session startRunning]; 
_isSetup = YES; 

我捕捉這樣的形象:

[_stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) 
{ 
    if (error) { 
     MWLogDebug(@"Error capturing image from camera. %@, %@", error, [error userInfo]); 
     _capturePreviewLayer.connection.enabled = YES; 
    } 
    else 
    { 
     NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; 
     UIImage *image = [[UIImage alloc] initWithData:imageData]; 

     CGRect cropRect = [self createCropRectForImage:image]; 
     UIImage *croppedImage;// = [self cropImage:image toRect:cropRect]; 
     UIGraphicsBeginImageContext(cropRect.size); 
     [image drawAtPoint:CGPointMake(-cropRect.origin.x, -cropRect.origin.y)]; 
     croppedImage = UIGraphicsGetImageFromCurrentImageContext(); 
     UIGraphicsEndImageContext(); 
     self.capturedImage = croppedImage; 
     [_session stopRunning];    
    } 
}]; 

createCropRectForImage:方法我試過各種方法來計算矩形切出的形象,但迄今爲止沒有成功。

- (CGRect)createCropRectForImage:(UIImage *)image 
{ 
    CGPoint maskTopLeftCorner = CGPointMake(self.maskRectView.frame.origin.x, self.maskRectView.frame.origin.y); 
    CGPoint maskBottomRightCorner = CGPointMake(self.maskRectView.frame.origin.x + self.maskRectView.frame.size.width, self.maskRectView.frame.origin.y + self.maskRectView.frame.size.height); 

    CGPoint maskTopLeftCornerInLayerCoords = [_capturePreviewLayer convertPoint:maskTopLeftCorner fromLayer:self.maskRectView.layer.superlayer]; 
    CGPoint maskBottomRightCornerInLayerCoords = [_capturePreviewLayer convertPoint:maskBottomRightCorner fromLayer:self.maskRectView.layer.superlayer]; 
    CGPoint maskTopLeftCornerInDeviceCoords = [_capturePreviewLayer captureDevicePointOfInterestForPoint:maskTopLeftCornerInLayerCoords]; 
    CGPoint maskBottomRightCornerInDeviceCoords = [_capturePreviewLayer captureDevicePointOfInterestForPoint:maskBottomRightCornerInLayerCoords]; 

    float x = maskTopLeftCornerInDeviceCoords.x * image.size.width; 
    float y = (1 - maskTopLeftCornerInDeviceCoords.y) * image.size.height; 
    float width = fabsf(maskTopLeftCornerInDeviceCoords.x - maskBottomRightCornerInDeviceCoords.x) * image.size.width; 
    float height = fabsf(maskTopLeftCornerInDeviceCoords.y - maskBottomRightCornerInDeviceCoords.y) * image.size.height; 

    return CGRectMake(x, y, width, height); 
} 

這是我目前的版本,但沒有得到正確的比例。有人可以幫助我!

- (UIImage*)cropImage:(UIImage*)originalImage toRect:(CGRect)rect{ 

    CGImageRef imageRef = CGImageCreateWithImageInRect([originalImage CGImage], rect); 

    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); 
    CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef); 
    CGContextRef bitmap = CGBitmapContextCreate(NULL, rect.size.width, rect.size.height, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo); 

    if (originalImage.imageOrientation == UIImageOrientationLeft) { 
     CGContextRotateCTM (bitmap, radians(90)); 
     CGContextTranslateCTM (bitmap, 0, -rect.size.height); 

    } else if (originalImage.imageOrientation == UIImageOrientationRight) { 
     CGContextRotateCTM (bitmap, radians(-90)); 
     CGContextTranslateCTM (bitmap, -rect.size.width, 0); 

    } else if (originalImage.imageOrientation == UIImageOrientationUp) { 
     // NOTHING 
    } else if (originalImage.imageOrientation == UIImageOrientationDown) { 
     CGContextTranslateCTM (bitmap, rect.size.width, rect.size.height); 
     CGContextRotateCTM (bitmap, radians(-180.)); 
    } 

    CGContextDrawImage(bitmap, CGRectMake(0, 0, rect.size.width, rect.size.height), imageRef); 
    CGImageRef ref = CGBitmapContextCreateImage(bitmap); 

    UIImage *resultImage=[UIImage imageWithCGImage:ref]; 
    CGImageRelease(imageRef); 
    CGContextRelease(bitmap); 
    CGImageRelease(ref); 

    return resultImage; 
} 

沒有任何人有方法的「最佳組合」,使這項工作:

我也用這個方法來裁剪我的形象試過嗎? :)

+1

你解決問題了嗎?我正在尋找答案。 – kkocabiyik 2013-04-23 00:29:30

回答

40

我已經使用metadataOutputRectOfInterestForRect函數解決了這個問題。

它適用於任何方向。

[_stillImageOutput captureStillImageAsynchronouslyFromConnection:stillImageConnection 
               completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) 
{ 
    if (error) 
    { 
     [_delegate cameraView:self error:@"Take picture failed"]; 
    } 
    else 
    { 

     NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; 
     UIImage *takenImage = [UIImage imageWithData:jpegData]; 

     CGRect outputRect = [_previewLayer metadataOutputRectOfInterestForRect:_previewLayer.bounds]; 
     CGImageRef takenCGImage = takenImage.CGImage; 
     size_t width = CGImageGetWidth(takenCGImage); 
     size_t height = CGImageGetHeight(takenCGImage); 
     CGRect cropRect = CGRectMake(outputRect.origin.x * width, outputRect.origin.y * height, outputRect.size.width * width, outputRect.size.height * height); 

     CGImageRef cropCGImage = CGImageCreateWithImageInRect(takenCGImage, cropRect); 
     takenImage = [UIImage imageWithCGImage:cropCGImage scale:1 orientation:takenImage.imageOrientation]; 
     CGImageRelease(cropCGImage); 

    } 
} 
]; 

The takenImage is still imageOrientation dependent image。您可以刪除進一步圖像處理的方向信息。

UIGraphicsBeginImageContext(takenImage.size); 
[takenImage drawAtPoint:CGPointZero]; 
takenImage = UIGraphicsGetImageFromCurrentImageContext(); 
UIGraphicsEndImageContext(); 
+0

很好,代碼不錯 – Shashi3456643 2016-03-17 21:59:53

+0

@unknownStack我有同樣的問題,但是你的代碼並沒有解決我的問題。我保存在專輯庫中的起源和圖像,但他們是一樣的:(但當它設置在一個uiimageView中,它顯示了一個非常放大的圖像:( – 2016-12-26 08:22:29

0

AVMakeRectWithAspectRatioInsideRect 這個API是AVFoundation,它將返回裁剪區域給定作物尺寸的圖像。

27

在斯威夫特3:

private func cropToPreviewLayer(originalImage: UIImage) -> UIImage { 
    let outputRect = previewLayer.metadataOutputRectOfInterest(for: previewLayer.bounds) 
    var cgImage = originalImage.cgImage! 
    let width = CGFloat(cgImage.width) 
    let height = CGFloat(cgImage.height) 
    let cropRect = CGRect(x: outputRect.origin.x * width, y: outputRect.origin.y * height, width: outputRect.size.width * width, height: outputRect.size.height * height) 

    cgImage = cgImage.cropping(to: cropRect)! 
    let croppedUIImage = UIImage(cgImage: cgImage, scale: 1.0, orientation: originalImage.imageOrientation) 

    return croppedUIImage 
} 
+3

誠實的善良。這將是前10名之一在這個網站上發佈的答案我當然希望你留在網站上我發送了一個巨大的賞金**謝謝你,Patrick Montalto ** – Fattie 2017-05-03 15:37:53

+2

真的很棒的回答:)幫助了很多,從幾個小時工作 – 2017-05-22 09:01:30

+2

什麼是previewLayer,獲取錯誤「未解決的標識符」 – Yatendra 2017-06-27 07:43:37