Подтвердить что ты не робот

Обрезка вывода 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]];

}
4b9b3361

Ответ 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 в качестве ширины для нового контекста изображения.

надеюсь, что это поможет!