Обрезка вывода AVCaptureVideoPreviewLayer на квадрат
У меня возникают проблемы с моим методом AVCaptureVideoPreviewLayer при захвате обрезанного UIImage просматриваемого экрана. В настоящее время он работает, но не выводит нужный урожай, который мне нужен.
Я пытаюсь вывести квадрат, но он (по внешнему виду), кажется, дает полную высоту и сжимает изображение.
Перед изображением отображается экран LIVE, а изображение после изображения показывает изображение после нажатия кнопки захвата. Вы можете видеть, что он был изменен по вертикали, чтобы соответствовать квадрату, но высота не была обрезана по вертикали.
![enter image description here]()
Capture Image Code
[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]];
}
Ответы
Ответ 1
Даже если слой предварительного просмотра является квадратным, имейте в виду, что сгенерированное неподвижное изображение сохраняет свой первоначальный размер.
Из того, что я вижу, проблема здесь:
UIGraphicsBeginImageContext(CGSizeMake(width, width));
[image drawInRect: CGRectMake(0, 0, width, width)];
Вы уже сделали свой квадрат контекста первой строкой. Вам все равно нужно нарисовать свое изображение в исходном формате, оно будет обрезано в этом контексте. Во второй строке вы вынуждаете рисовать исходное изображение в квадрате, что делает его "сжатым".
Вы должны найти правильную высоту изображения, которая сохраняет исходное соотношение при установке вашей "ширины". Затем вы захотите нарисовать это изображение с правильным размером (сохраняя исходное соотношение) в квадратном контексте. Если вы хотите закрепить центр, измените положение 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];
}
Это должно сделать это.
Ответ 2
Вы пытались установить videoGravity?
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
Ответ 3
Глядя на код, мне кажется, что вы рисуете изображение в квадрат. Это та часть, которая сжимает изображение без учета соотношения сторон.
Вместо этого сделайте следующее:
- (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]];
}
Ответ 4
Соотношение сторон искажено, потому что изображение, снятое камерой, не является квадратным. При рисовании в квадрат он будет нарисован с искаженным соотношением сторон. Возможное решение состоит в том, чтобы нарисовать изображение в квадрат, сохраняя аспектный рацион, например:
- (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 в качестве ширины для нового контекста изображения.
надеюсь, что это поможет!