【问题标题】:How to use CvPhotoCamera with iOS openCV?如何在 iOS openCV 中使用 CvPhotoCamera?
【发布时间】:2023-03-12 18:17:02
【问题描述】:

我已经关注了tutorial,了解如何使用CvVideoCamera 对象播放视频并进行一些处理。

我现在有兴趣使用CvPhotoCamera 对象通过takePicture 方法捕获高清图片。但是,本教程使用CvVideoCamera 并且没有对CvPhotoCamera 进行任何引用。

CvPhotoCameraCvVideoCamera 都继承自 CvAbstractCamera。它们是姐妹类,所以我不知道如何使用 takePicture 函数。

【问题讨论】:

    标签: ios opencv avfoundation avcapturesession ios-camera


    【解决方案1】:

    和@poiuytrez一样:给cvPhotoCamera添加修改

    CvPhotoCameraMod.h:

    #import <UIKit/UIKit.h>
    #import <opencv2/highgui/cap_ios.h>
    #import <opencv2/highgui/ios.h>
    
    #define DEGREES_RADIANS(angle) ((angle) / 180.0 * M_PI)
    
    @class CvPhotoCameraMod;
    
    @protocol CvPhotoCameraDelegateMod <CvPhotoCameraDelegate>
    - (void)processImage:(cv::Mat&)image;
    @end
    
    @interface CvPhotoCameraMod : CvPhotoCamera <AVCaptureVideoDataOutputSampleBufferDelegate>
    
    @property (nonatomic, retain) CALayer *customPreviewLayer;
    @property (nonatomic, retain) AVCaptureVideoDataOutput *videoDataOutput;
    @property (nonatomic, weak) id <CvPhotoCameraDelegateMod> delegate;
    
    - (void)createCustomVideoPreview;
    
    @end
    

    CvPhotoCameraMod.mm:

    #import "CvPhotoCameraMod.h"
    #import <CoreGraphics/CoreGraphics.h>
    #define DEGREES_RADIANS(angle) ((angle) / 180.0 * M_PI)
    
    @implementation CvPhotoCameraMod
    
    
    -(void)createCaptureOutput;
    {
        [super createCaptureOutput];
        [self createVideoDataOutput];
    }
    - (void)createCustomVideoPreview;
    {
        [self.parentView.layer addSublayer:self.customPreviewLayer];
    }
    
    
    //Method mostly taken from this source: https://github.com/Itseez/opencv/blob/b46719b0931b256ab68d5f833b8fadd83737ddd1/modules/videoio/src/cap_ios_video_camera.mm
    
    -(void)createVideoDataOutput{
        // Make a video data output
        self.videoDataOutput = [AVCaptureVideoDataOutput new];
    
        //Drop grayscale support here
        self.videoDataOutput.videoSettings  = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey];
    
    
        // discard if the data output queue is blocked (as we process the still image)
        [self.videoDataOutput setAlwaysDiscardsLateVideoFrames:YES];
        if ( [self.captureSession canAddOutput:self.videoDataOutput] ) {
            [self.captureSession addOutput:self.videoDataOutput];
        }
        [[self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo] setEnabled:YES];
    
        // set video mirroring for front camera (more intuitive)
        if ([self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].supportsVideoMirroring) {
            if (self.defaultAVCaptureDevicePosition == AVCaptureDevicePositionFront) {
                [self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].videoMirrored = YES;
            } else {
                [self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].videoMirrored = NO;
            }
        }
    
        // set default video orientation
        if ([self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].supportsVideoOrientation) {
            [self.videoDataOutput connectionWithMediaType:AVMediaTypeVideo].videoOrientation = self.defaultAVCaptureVideoOrientation;
        }
    
        // create a custom preview layer
        self.customPreviewLayer = [CALayer layer];
    
        self.customPreviewLayer.bounds = CGRectMake(0, 0, self.parentView.frame.size.width, self.parentView.frame.size.height);
    
        self.customPreviewLayer.position = CGPointMake(self.parentView.frame.size.width/2., self.parentView.frame.size.height/2.);
    
        // create a serial dispatch queue used for the sample buffer delegate as well as when a still image is captured
        // a serial dispatch queue must be used to guarantee that video frames will be delivered in order
        // see the header doc for setSampleBufferDelegate:queue: for more information
        dispatch_queue_t videoDataOutputQueue = dispatch_queue_create("VideoDataOutputQueue", DISPATCH_QUEUE_SERIAL);
        [self.videoDataOutput setSampleBufferDelegate:self queue:videoDataOutputQueue];
    }
    
    - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
    {
        (void)captureOutput;
        (void)connection;
        if (self.delegate) {
    
            // convert from Core Media to Core Video
            CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
            CVPixelBufferLockBaseAddress(imageBuffer, 0);
    
            void* bufferAddress;
            size_t width;
            size_t height;
            size_t bytesPerRow;
    
            CGColorSpaceRef colorSpace;
            CGContextRef context;
    
            int format_opencv;
    
            OSType format = CVPixelBufferGetPixelFormatType(imageBuffer);
            if (format == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) {
    
                format_opencv = CV_8UC1;
    
                bufferAddress = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);
                width = CVPixelBufferGetWidthOfPlane(imageBuffer, 0);
                height = CVPixelBufferGetHeightOfPlane(imageBuffer, 0);
                bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0);
    
            } else { // expect kCVPixelFormatType_32BGRA
    
                format_opencv = CV_8UC4;
    
                bufferAddress = CVPixelBufferGetBaseAddress(imageBuffer);
                width = CVPixelBufferGetWidth(imageBuffer);
                height = CVPixelBufferGetHeight(imageBuffer);
                bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
    
            }
    
            // delegate image processing to the delegate
            cv::Mat image((int)height, (int)width, format_opencv, bufferAddress, bytesPerRow);
    
            CGImage* dstImage;
    
            if ([self.delegate respondsToSelector:@selector(processImage:)]) {
                [self.delegate processImage:image];
            }
    
            // check if matrix data pointer or dimensions were changed by the delegate
            bool iOSimage = false;
            if (height == (size_t)image.rows && width == (size_t)image.cols && format_opencv == image.type() && bufferAddress == image.data && bytesPerRow == image.step) {
                iOSimage = true;
            }
    
    
            // (create color space, create graphics context, render buffer)
            CGBitmapInfo bitmapInfo;
    
            // basically we decide if it's a grayscale, rgb or rgba image
            if (image.channels() == 1) {
                colorSpace = CGColorSpaceCreateDeviceGray();
                bitmapInfo = kCGImageAlphaNone;
            } else if (image.channels() == 3) {
                colorSpace = CGColorSpaceCreateDeviceRGB();
                bitmapInfo = kCGImageAlphaNone;
                if (iOSimage) {
                    bitmapInfo |= kCGBitmapByteOrder32Little;
                } else {
                    bitmapInfo |= kCGBitmapByteOrder32Big;
                }
            } else {
                colorSpace = CGColorSpaceCreateDeviceRGB();
                bitmapInfo = kCGImageAlphaPremultipliedFirst;
                if (iOSimage) {
                    bitmapInfo |= kCGBitmapByteOrder32Little;
                } else {
                    bitmapInfo |= kCGBitmapByteOrder32Big;
                }
            }
    
            if (iOSimage) {
                context = CGBitmapContextCreate(bufferAddress, width, height, 8, bytesPerRow, colorSpace, bitmapInfo);
                dstImage = CGBitmapContextCreateImage(context);
                CGContextRelease(context);
            } else {
    
                NSData *data = [NSData dataWithBytes:image.data length:image.elemSize()*image.total()];
                CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
    
                // Creating CGImage from cv::Mat
                dstImage = CGImageCreate(image.cols,                                 // width
                                         image.rows,                                 // height
                                         8,                                          // bits per component
                                         8 * image.elemSize(),                       // bits per pixel
                                         image.step,                                 // bytesPerRow
                                         colorSpace,                                 // colorspace
                                         bitmapInfo,                                 // bitmap info
                                         provider,                                   // CGDataProviderRef
                                         NULL,                                       // decode
                                         false,                                      // should interpolate
                                         kCGRenderingIntentDefault                   // intent
                                         );
    
                CGDataProviderRelease(provider);
            }
    
    
            // render buffer
            dispatch_sync(dispatch_get_main_queue(), ^{
                self.customPreviewLayer.contents = (__bridge id)dstImage;
            });
    
    
            // cleanup
            CGImageRelease(dstImage);
    
            CGColorSpaceRelease(colorSpace);
    
            CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
        }
    }
    
    
    @end
    

    【讨论】:

    • XCode 在 CvPhotoCameraMod.h 文件中出现错误。它似乎无法识别 cv 命名空间。知道为什么吗?
    • 如果 using namespace cv; in CvPhotoCameraMod.h 对您没有帮助 - 可能问题不在命名空间中。
    【解决方案2】:

    我的解决方案是创建一个名为 CvVideoPhotoCamera 的新类,它继承自 CvAbstractCamera。 CvVideoPhotoCamera 的内容是由 CvVideoCamera 和 CvPhotoCamera 合并而成的。

    【讨论】:

      猜你喜欢
      • 2017-10-06
      • 1970-01-01
      • 2017-11-12
      • 2018-02-02
      • 2015-09-03
      • 2019-09-01
      • 2018-07-20
      • 1970-01-01
      • 2015-09-24
      相关资源
      最近更新 更多