在 iOS OpenCV 相机中将相机预览旋转到人像

Posted

技术标签:

【中文标题】在 iOS OpenCV 相机中将相机预览旋转到人像【英文标题】:Rotate camera preview to Portrait in iOS OpenCV Camera 【发布时间】:2016-01-05 20:29:16 【问题描述】:

我刚打算在我的 ios 应用中使用 openCV。

我创建了相机预览,但它以横向模式显示,但方向不正确。我不知道如何以正确的方向旋转相机意味着如果手机是纵向的,那么相机应该以纵向模式打开..

有什么解决办法吗?

【问题讨论】:

【参考方案1】:

如果你使用的是CvVideoCameraDelegate,那么在viewDidLoad方法中初始化相机参数后添加如下代码。

self->videoCamera.rotateVideo = YES;

【讨论】:

【参考方案2】:

您没有具体说明相关窗口是视图还是图层,或者是实时视频还是保存到文件中。您也没有指定视频是通过 OpenCV 录制的,还是通过其他方式录制的。

因此,我为每个意外事件都包含了代码 sn-ps;如果您熟悉 OpenCV 和 iOS 视图编程的基础知识,那么应该很清楚您应该使用什么(在我的情况下,顺便说一下,我使用了所有这些):

- (void)viewDidLayoutSubviews 
    [super viewDidLayoutSubviews];

    switch ([UIDevice currentDevice].orientation) 
        case UIDeviceOrientationPortraitUpsideDown:
            self.videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
            break;
        case UIDeviceOrientationLandscapeLeft:
            self.videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationLandscapeLeft;
            break;
        case UIDeviceOrientationLandscapeRight:
            self.videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationLandscapeRight;
            break;
        default:
            self.videoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait;
            break;
    

    [self refresh];


- (void)processImage:(cv::Mat &)mat 

    if (self.videoCamera.running) 
        switch (self.videoCamera.defaultAVCaptureVideoOrientation) 
            case AVCaptureVideoOrientationLandscapeLeft:
            case AVCaptureVideoOrientationLandscapeRight:
                // The landscape video is captured upside-down.
                // Rotate it by 180 degrees.
                cv::flip(mat, mat, -1);
                break;
            default:
                break;
        
    


- (void)convertBlendSrcMatToWidth:(int)dstW height:(int)dstH 

    double dstAspectRatio = dstW / (double)dstH;

    int srcW = originalBlendSrcMat.cols;
    int srcH = originalBlendSrcMat.rows;
    double srcAspectRatio = srcW / (double)srcH;
    cv::Mat subMat;
    if (srcAspectRatio < dstAspectRatio) 
        int subMatH = (int)(srcW / dstAspectRatio);
        int startRow = (srcH - subMatH) / 2;
        int endRow = startRow + subMatH;
        subMat = originalBlendSrcMat.rowRange(startRow, endRow);
     else 
        int subMatW = (int)(srcH * dstAspectRatio);
        int startCol = (srcW - subMatW) / 2;
        int endCol = startCol + subMatW;
        subMat = originalBlendSrcMat.colRange(startCol, endCol);
    
    cv::resize(subMat, convertedBlendSrcMat, cv::Size(dstW, dstH), 0.0, 0.0, cv::INTER_LANCZOS4);



- (int)imageWidth 
    AVCaptureVideoDataOutput *output = [self.captureSession.outputs lastObject];
    NSDictionary *videoSettings = [output videoSettings];
    int videoWidth = [[videoSettings objectForKey:@"Width"] intValue];
    return videoWidth;


- (int)imageHeight 
    AVCaptureVideoDataOutput *output = [self.captureSession.outputs lastObject];
    NSDictionary *videoSettings = [output videoSettings];
    int videoHeight = [[videoSettings objectForKey:@"Height"] intValue];
    return videoHeight;


- (void)updateSize 
    // Do nothing.


- (void)layoutPreviewLayer 
    if (self.parentView != nil) 

        // Center the video preview.
        self.customPreviewLayer.position = CGPointMake(0.5 * self.parentView.frame.size.width, 0.5 * self.parentView.frame.size.height);

        // Find the video's aspect ratio.
        CGFloat videoAspectRatio = self.imageWidth / (CGFloat)self.imageHeight;

        // Scale the video preview while maintaining its aspect ratio.
        CGFloat boundsW;
        CGFloat boundsH;
        if (self.imageHeight > self.imageWidth) 
            if (self.letterboxPreview) 
                boundsH = self.parentView.frame.size.height;
                boundsW = boundsH * videoAspectRatio;
             else 
                boundsW = self.parentView.frame.size.width;
                boundsH = boundsW / videoAspectRatio;
            
         else 
            if (self.letterboxPreview) 
                boundsW = self.parentView.frame.size.width;
                boundsH = boundsW / videoAspectRatio;
             else 
                boundsH = self.parentView.frame.size.height;
                boundsW = boundsH * videoAspectRatio;
            
        
        self.customPreviewLayer.bounds = CGRectMake(0.0, 0.0, boundsW, boundsH);
    



- (void)processImage:(cv::Mat &)mat 

    if (self.videoCamera.running) 
        switch (self.videoCamera.defaultAVCaptureVideoOrientation) 
            case AVCaptureVideoOrientationLandscapeLeft:
            case AVCaptureVideoOrientationLandscapeRight:
                // The landscape video is captured upside-down.
                // Rotate it by 180 degrees.
                cv::flip(mat, mat, -1);
                break;
            default:
                break;
        
    


- (void)convertBlendSrcMatToWidth:(int)dstW height:(int)dstH 

    double dstAspectRatio = dstW / (double)dstH;

    int srcW = originalBlendSrcMat.cols;
    int srcH = originalBlendSrcMat.rows;
    double srcAspectRatio = srcW / (double)srcH;
    cv::Mat subMat;
    if (srcAspectRatio < dstAspectRatio) 
        int subMatH = (int)(srcW / dstAspectRatio);
        int startRow = (srcH - subMatH) / 2;
        int endRow = startRow + subMatH;
        subMat = originalBlendSrcMat.rowRange(startRow, endRow);
     else 
        int subMatW = (int)(srcH * dstAspectRatio);
        int startCol = (srcW - subMatW) / 2;
        int endCol = startCol + subMatW;
        subMat = originalBlendSrcMat.colRange(startCol, endCol);
    
    cv::resize(subMat, convertedBlendSrcMat, cv::Size(dstW, dstH), 0.0, 0.0, cv::INTER_LANCZOS4);



- (int)imageWidth 
    AVCaptureVideoDataOutput *output = [self.captureSession.outputs lastObject];
    NSDictionary *videoSettings = [output videoSettings];
    int videoWidth = [[videoSettings objectForKey:@"Width"] intValue];
    return videoWidth;


- (int)imageHeight 
    AVCaptureVideoDataOutput *output = [self.captureSession.outputs lastObject];
    NSDictionary *videoSettings = [output videoSettings];
    int videoHeight = [[videoSettings objectForKey:@"Height"] intValue];
    return videoHeight;


- (void)updateSize 
    // Do nothing.


- (void)layoutPreviewLayer 
    if (self.parentView != nil) 

        // Center the video preview.
        self.customPreviewLayer.position = CGPointMake(0.5 * self.parentView.frame.size.width, 0.5 * self.parentView.frame.size.height);

        // Find the video's aspect ratio.
        CGFloat videoAspectRatio = self.imageWidth / (CGFloat)self.imageHeight;

        // Scale the video preview while maintaining its aspect ratio.
        CGFloat boundsW;
        CGFloat boundsH;
        if (self.imageHeight > self.imageWidth) 
            if (self.letterboxPreview) 
                boundsH = self.parentView.frame.size.height;
                boundsW = boundsH * videoAspectRatio;
             else 
                boundsW = self.parentView.frame.size.width;
                boundsH = boundsW / videoAspectRatio;
            
         else 
            if (self.letterboxPreview) 
                boundsW = self.parentView.frame.size.width;
                boundsH = boundsW / videoAspectRatio;
             else 
                boundsH = self.parentView.frame.size.height;
                boundsW = boundsH * videoAspectRatio;
            
        
        self.customPreviewLayer.bounds = CGRectMake(0.0, 0.0, boundsW, boundsH);
    

这里有很多东西,你必须知道把它放在哪里。如果你不明白,请告诉我。

【讨论】:

以上是关于在 iOS OpenCV 相机中将相机预览旋转到人像的主要内容,如果未能解决你的问题,请参考以下文章

如何在surfaceview中将Android相机更改为人像?

在android中将相机预览拉伸到全屏

Android:在方向更改时保留相机预览,而其他视图可以旋转

使用 OpenGL 2.0 API 在 GLSurfaceView 上将 Android 相机预览旋转 90 度

相机预览处于纵向模式,但拍摄的图像已旋转

OpenCV - 如何在 Android 中设置全屏相机视图?