裁剪AVCaptureVideoPreviewLayer输出到一个正方形

抓取可视屏幕的裁剪UIImage时,遇到AVCaptureVideoPreviewLayer方法问题。 目前它正在工作,但没有输出我需要的正确作物。

我正在尝试输出一个正方形,但它(按其外观)似乎正在给出完整的高度并压缩图像。

之前的图像显示实时屏幕和后图像显示图像一旦捕获button已被按下。 你可以看到它已经垂直改变,以适应广场,但高度没有被垂直裁剪。

在这里输入图像说明

捕获图像代码

[stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) { if (imageSampleBuffer != NULL) { NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; [self processImage:[UIImage imageWithData:imageData]]; } }]; 

裁剪代码

 - (void) processImage:(UIImage *)image { //process captured image, crop, resize and rotate haveImage = YES; CGRect deviceScreen = _previewLayer.bounds; CGFloat width = deviceScreen.size.width; CGFloat height = deviceScreen.size.height; NSLog(@"WIDTH %f", width); // Outputing 320 NSLog(@"HEIGHT %f", height); // Outputting 320 UIGraphicsBeginImageContext(CGSizeMake(width, width)); [image drawInRect: CGRectMake(0, 0, width, width)]; UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); CGRect cropRect = CGRectMake(0, 0, width, width); CGImageRef imageRef = CGImageCreateWithImageInRect([smallImage CGImage], cropRect); CGImageRelease(imageRef); [captureImageGrab setImage:[UIImage imageWithCGImage:imageRef]]; } 

即使预览图层是正方形,请记住生成的静态图像保持其原始大小。

从我所看到的问题来看:

 UIGraphicsBeginImageContext(CGSizeMake(width, width)); [image drawInRect: CGRectMake(0, 0, width, width)]; 

你已经把你的上下文与第一行一致。 您仍然需要以原始格式绘制您的图像,它将被该上下文剪切。 在第二行,你迫使原始图像在一个正方形的绘制,从而使它看起来“挤压”。

你应该find正确的图像高度,保持原来的比例,同时适合你的“宽度”。 接下来,您将需要在正方形上下文中以正确尺寸(保持原始比例)绘制该图像。 如果要剪切中心,请更改绘图的Y位置。

类似的东西:

 - (void) processImage:(UIImage *)image { UIGraphicsBeginImageContext(CGSizeMake(width, width)); CGFloat imageHeight = floorf(width / image.width * image.height); CGFloat offsetY = floorf((imageHeight - width) / 2.0f); [image drawInRect: CGRectMake(0, -offsetY, width, imageHeight)]; UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); [captureImageGrab setImage:smallImage]; } 

这应该做到这一点。

你有没有尝试设置video重力?

 previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill 

看看代码,在我看来,你正在将图像绘制成方形。 这是不考虑纵横比缩小图像的部分。

相反,做这样的事情:

 - (void) processImage:(UIImage *)image { //process captured image, crop, resize and rotate haveImage = YES; CGRect deviceScreen = _previewLayer.bounds; CGFloat width = deviceScreen.size.width; CGFloat height = deviceScreen.size.height; NSLog(@"WIDTH %f", width); // Outputing 320 NSLog(@"HEIGHT %f", height); // Outputting 320 CGRect cropRect = CGRectZero; if (image.size.width > image.size.height) { cropRect.origin.x = (image.size.width-image.size.height)/2; cropRect.size = CGSizeMake(image.size.height, image.size.height); } else { cropRect.origin.y = (image.size.height-image.size.width)/2; cropRect.size = CGSizeMake(image.size.width, image.size.width); } CGImageRef croppedImage = CGImageCreateWithImageInRect(image.CGImage, cropRect); UIGraphicsBeginImageContext(CGSizeMake(width, width)); [[UIImage imageWithCGImage:croppedImage] drawInRect:CGRectMake(0, 0, width, width)]; UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); CGImageRelease(croppedImage); [captureImageGrab setImage:[UIImage imageWithCGImage:smallImage.CGImage scale:image.scale orientation:image.imageOrientation]]; } 

由于相机拍摄的图像不是正方形,所以宽高比失真。 当绘制成一个正方形时,它将被画出一个畸变的高宽比。 一个可能的解决scheme是将图像绘制到保持宽高比的方形,如下所示:

 - (void) processImage:(UIImage *)image { //process captured image, crop, resize and rotate haveImage = YES; CGRect deviceScreen = _previewLayer.bounds; CGFloat width = deviceScreen.size.width; CGFloat height = deviceScreen.size.height; NSLog(@"WIDTH %f", width); // Outputing 320 NSLog(@"HEIGHT %f", height); // Outputting 320 UIGraphicsBeginImageContext(CGSizeMake(width, width)); CGFloat aspect_h = image.size.height * width / image.size.width; [image drawInRect: CGRectMake(0, -(aspect_h - width)/2.0, width, aspect_h)]; UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); CGRect cropRect = CGRectMake(0, 0, width, width); CGImageRef imageRef = CGImageCreateWithImageInRect([smallImage CGImage], cropRect); CGImageRelease(imageRef); } 

新的图像将是宽度宽度 。 对于这个宽度来说,保持长宽比的高度是aspect_h 。 然后,图像沿着y轴移动以垂直居中。

请注意,如果您的应用程序要在不是纵向的方向上工作,则需要做更多的工作。

另一种观察:如果使用image.size.width作为新图像上下文的宽度,则可以获得更好的分辨率图像。

希望这可以帮助!