【问题标题】:OpenCv iOS camera preview single orientation only without stretchingOpenCv iOS 相机仅预览单一方向而无需拉伸
【发布时间】:2016-06-27 00:33:00
【问题描述】:

我正在为 iOS 编写一个 OpenCv Cordova 插件。我需要相机预览为全屏并保持所有 iOS 设备(iPhone、iPad)的纵横比。

我能够实现人像模式(参见代码),它在 iPhone 6/plus 上完美运行,但相机预览在 iPad 上略有拉伸,可能是因为 AVCaptureSessionPresetHigh 的支持的分辨率为 1280x720 .有人对如何实现单一方向(仅限横向或纵向)并保持纵横比有任何想法吗?

我目前启动相机的代码是

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    // Initialize imageView to fullscreen
    imageView = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    [self.view addSubview:imageView];
    [imageView setContentMode:UIViewContentModeScaleAspectFill];
    [imageView setClipsToBounds:YES];

    self.videoCamera = [[FixedCvVideoCamera alloc] initWithParentView:imageView];
    self.videoCamera.delegate = self;
    self.videoCamera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack;
    self.videoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPresetHigh;
    self.videoCamera.defaultAVCaptureVideoOrientation =  AVCaptureVideoOrientationPortrait;
    self.videoCamera.defaultFPS = 30;
    [self.videoCamera start];
}

请注意,我使用的是 FixedCvVideoCamera 而不是 OpenCv CvVideoCamera 类。原因是我继承并覆盖了 CvVideoCamera 的 layoutPreviewLayer 函数以保持纵向模式。

 - (void)layoutPreviewLayer;
{
    if (self.parentView != nil)
    {
        CALayer* layer = self->customPreviewLayer;
        CGRect bounds = self->customPreviewLayer.bounds;
        int rotation_angle = 0;

        switch (defaultAVCaptureVideoOrientation) {
            case AVCaptureVideoOrientationLandscapeRight:
                rotation_angle = 270;
                break;
            case AVCaptureVideoOrientationPortraitUpsideDown:
                rotation_angle = 180;
                break;
            case AVCaptureVideoOrientationLandscapeLeft:
                rotation_angle = 90;
                break;
            case AVCaptureVideoOrientationPortrait:
            default:
                break;
        }

        layer.position = CGPointMake(self.parentView.frame.size.width/2., self.parentView.frame.size.height/2.);
        layer.affineTransform = CGAffineTransformMakeRotation( DEGREES_RADIANS(rotation_angle) );
        layer.bounds = bounds;
    }
}

提前致谢。

【问题讨论】:

    标签: ios xcode opencv avcapturesession


    【解决方案1】:

    我自己解决了。下面的代码将帮助那些只想要固定人像模式并支持前后摄像头的人。

    视图控制器

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
    
        // Initialize imageView to fullscreen
        imageView = [[UIImageView alloc] initWithFrame:[UIScreen mainScreen].bounds];
        [self.view addSubview:imageView];
        [imageView setContentMode:UIViewContentModeScaleAspectFill];
        [imageView setClipsToBounds:YES];
    
        self.videoCamera = [[FixedCvVideoCamera alloc] initWithParentView:imageView];
        self.videoCamera.delegate = self;
        self.videoCamera.defaultAVCaptureDevicePosition = AVCaptureDevicePositionBack;
        self.videoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPresetHigh;
        self.videoCamera.defaultAVCaptureVideoOrientation =  AVCaptureVideoOrientationPortrait;
        self.videoCamera.defaultFPS = 30;
        self.videoCamera.grayscaleMode = NO;
    
        [self.videoCamera start];
    }
    

    固定CvVideoCamera:CvVideoCamera

    - (void)layoutPreviewLayer;
    {
        if (self.parentView != nil)
        {
            CALayer* layer = self->customPreviewLayer;
            CGRect bounds = self->customPreviewLayer.bounds;
            NSLog(@"[FixedCvVideoCamera]Custom Preview Layer bounds %fx%f", bounds.size.width, bounds.size.height);
    
            float previewAspectRatio = bounds.size.height / bounds.size.width;
            NSLog(@"[FixedCvVideoCamera]Preview aspect ratio %f", previewAspectRatio);
    
            //int rotation_angle = 0;
    
            layer.position = CGPointMake(self.parentView.frame.size.width/2., self.parentView.frame.size.height/2.);
            //layer.affineTransform = CGAffineTransformMakeRotation( DEGREES_RADIANS(rotation_angle) );
    
            // Get video feed's resolutions
            NSArray* devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
            AVCaptureDevice* device = nil;
            for (AVCaptureDevice *d in devices) {
                // Get the default camera device - should be either front of back camera device
                if ([d position] == self.defaultAVCaptureDevicePosition) {
                    device = d;
                }
            }
    
            // Set the default device if not found
            if (!device) {
                device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
            }
    
            CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(device.activeFormat.formatDescription);
            CGSize resolution = CGSizeMake(dimensions.width, dimensions.height);
            if (self.defaultAVCaptureVideoOrientation == AVCaptureVideoOrientationPortrait || self.defaultAVCaptureVideoOrientation == AVCaptureVideoOrientationPortraitUpsideDown) {
                resolution = CGSizeMake(resolution.height, resolution.width);
            }
            NSLog(@"[FixedCvVideoCamera]Video feed resolution is %fx%f", resolution.width, resolution.height);
    
            float videoFeedAspectRatio = resolution.height / resolution.width;
            NSLog(@"[FixedCvVideoCamera]Video feed's aspect ratio is %f", videoFeedAspectRatio);
    
            // Set layer bounds to ASPECT FILL by expanding either the width or the height
            if (previewAspectRatio > videoFeedAspectRatio) {
                NSLog(@"[FixedCvVideoCamera] Preview is more rectangular than the video feed aspect ratio. Expanding width to maintain aspect ratio.");
                float newWidth = bounds.size.height / videoFeedAspectRatio;
                layer.bounds = CGRectMake(0, 0, newWidth, bounds.size.height);
            } else {
                NSLog(@"[FixedCvVideoCamera] Preview is equally or less rectangular (wider) than the video feed's aspect ratio. Expanding height bound to maintain aspect ratio.");
                float newHeight = bounds.size.width * videoFeedAspectRatio;
                layer.bounds = CGRectMake(0, 0, bounds.size.width, newHeight);
            }
        }
    }
    

    【讨论】:

    • 谢谢哥们。让我头疼。
    • @Han - 是否可以询问或查看您实现此功能的更广泛的代码库或文件结构?我遇到了和你一样的问题,但我在 Android 的 OpenCV 方面有更多的专业知识,所以我试图更好地掌握如何在 iOS 中实现这一变化。
    • @mheavers 抱歉回复晚了。我没有收到电子邮件通知。很久以前,但基本上你有 2 个文件 .mm 文件(及其相应的 .h 文件)。首先是您的 FixedCvVideoCamera ,它扩展了 CvVideoCamera 并且您使用上面的代码覆盖 layoutPreviewLayer 函数。第二个是您的自定义视图控制器(如 Android 上的 Activity),它初始化 FixedCvVideoCamera 而不是 CvVideoCamera 以获取非拉伸视频源。这是在 viewDidLoad 函数中完成的。我希望这是有道理的。
    猜你喜欢
    • 2016-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多