【问题标题】:How do you scale an image using vImage in the Accelerate framework in iOS 8?如何在 iOS 8 的 Accelerate 框架中使用 vImage 缩放图像?
【发布时间】:2015-05-24 04:05:43
【问题描述】:

我正在尝试在 iOS 8 设备上尽快调整 CMSampleBufferRef 的大小以用于图像处理。从我在网上找到的内容来看,执行此操作的方法似乎是在 Accelerate 框架中使用 vImage API。但是,我对 Accelerate 框架所做的工作并不多,而且我不太清楚如何做到这一点。到目前为止,这是我将图像缩放到 200x200 的内容:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
    CVImageBufferRef cvimgRef = CMSampleBufferGetImageBuffer(sampleBuffer);
    CVPixelBufferLockBaseAddress(cvimgRef,0);
    void *imageData = CVPixelBufferGetBaseAddress(cvimgRef);
    NSInteger width = CVPixelBufferGetWidth(cvimgRef);
    NSInteger height = CVPixelBufferGetHeight(cvimgRef);

    unsigned char *newData= // NOT SURE WHAT THIS SHOULD BE...
    vImage_Buffer  inBuff = { imageData, height, width, 4*width };
    vImage_Buffer  outBuff = { newData, 200, 200, 4*200 };

    // NOT SURE IF THIS IS THE CORRECT METHOD... video output settings for kCVPixelBufferPixelFormatTypeKey is set to kCVPixelFormatType_32BGRA
    // This seems wrong since the image scale is ARGB, not BGRA.
    vImageScale_ARGB8888(inBuffer, outBuffer, NULL, kvImageNoFlags);
    CVPixelBufferUnlockBaseAddress(cvimgRef,0);
}

其中 outBuffer 是结果。之后,我也不确定如何将 outBuffer 转换回 CVImageBufferRef 以进行进一步的图像处理。任何建议将不胜感激!

【问题讨论】:

    标签: ios accelerate-framework vimage


    【解决方案1】:
    - (CVPixelBufferRef)copyRenderedPixelBuffer:(CVPixelBufferRef)pixelBuffer {
    
    CVPixelBufferLockBaseAddress( pixelBuffer, 0 );
    
    // vImage processing
    vImage_Error err;
    vImage_Buffer buffer;
    buffer.data = (unsigned char *)CVPixelBufferGetBaseAddress( pixelBuffer );
    buffer.rowBytes = CVPixelBufferGetBytesPerRow( pixelBuffer );
    buffer.width = CVPixelBufferGetWidth( pixelBuffer );
    buffer.height = CVPixelBufferGetHeight( pixelBuffer );
    vImageCVImageFormatRef vformat = vImageCVImageFormat_CreateWithCVPixelBuffer( pixelBuffer );
    vImage_CGImageFormat cgformat = {
        .bitsPerComponent = 8,
        .bitsPerPixel = 32,
        .bitmapInfo = kCGBitmapByteOrderDefault,
        .colorSpace = NULL,    //sRGB
    };
    const CGFloat bgColor[3] = {0.0, 0.0, 0.0};
    vImageBuffer_InitWithCVPixelBuffer(&buffer, &cgformat, pixelBuffer, vformat, bgColor, kvImageNoAllocate);
    
    vImage_Buffer outbuffer;
    void *tempBuffer;
    tempBuffer = malloc(CVPixelBufferGetBytesPerRow( pixelBuffer ) * CVPixelBufferGetHeight( pixelBuffer ));
    outbuffer.data = tempBuffer;
    outbuffer.rowBytes = CVPixelBufferGetBytesPerRow( pixelBuffer );
    outbuffer.width = CVPixelBufferGetWidth( pixelBuffer );
    outbuffer.height = CVPixelBufferGetHeight( pixelBuffer );
    

    // 在此处处理图像

        err = vImageBuffer_CopyToCVPixelBuffer(&outbuffer, &cgformat, pixelBuffer, vformat, bgColor, kvImageNoFlags);
    
    if(err != -1)
        free(tempBuffer);
    
    CVPixelBufferUnlockBaseAddress( pixelBuffer, 0 );
    
    return (CVPixelBufferRef)CFRetain( pixelBuffer );
    

    }

    【讨论】:

      【解决方案2】:

      您必须将重采样过滤器与任何改变图像几何形状的 vImage 操作结合使用:第 32 页,vImage 编程指南。

      【讨论】:

        【解决方案3】:

        vImageScale 只返回一个缓冲区数据,注意缓冲区需要被释放。
        我不知道是否有更快的方法只使用该输出缓冲区,但我会将缓冲区转换为CGImage。类似的东西取自here,所以把它作为参考

        vImage_CGImageFormat format = {
                .bitsPerComponent = 8,
                .bitsPerPixel = 32,
                .colorSpace = NULL,
                .bitmapInfo = (CGBitmapInfo)kCGImageAlphaFirst,
                .version = 0,
                .decode = NULL,
                .renderingIntent = kCGRenderingIntentDefault,
            };
        ret = kvImageNoError;
            CGImageRef destRef = vImageCreateCGImageFromBuffer(&dstBuffer, &format, NULL, NULL, kvImageNoFlags, &ret)
        


        稍后我会将其转换为CVPixelBuffer

        - (CVPixelBufferRef) pixelBufferFromCGImage: (CGImageRef) image
        {
            NSDictionary *options = @{
                                      (NSString*)kCVPixelBufferCGImageCompatibilityKey : @YES,
                                      (NSString*)kCVPixelBufferCGBitmapContextCompatibilityKey : @YES,
                                      };
        
        CVPixelBufferRef pxbuffer = NULL;
        CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, CGImageGetWidth(image),
                            CGImageGetHeight(image), kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options,
                            &pxbuffer);
        if (status!=kCVReturnSuccess) {
            DLog(@"Operation failed");
        }
        NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
        
        CVPixelBufferLockBaseAddress(pxbuffer, 0);
        void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
        
        CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
        CGContextRef context = CGBitmapContextCreate(pxdata, CGImageGetWidth(image),
                                                     CGImageGetHeight(image), 8, 4*CGImageGetWidth(image), rgbColorSpace,
                                                     kCGImageAlphaNoneSkipFirst);
        NSParameterAssert(context);
        
        CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));
        
        CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image),
                                               CGImageGetHeight(image)), image);
        CGColorSpaceRelease(rgbColorSpace);
        CGContextRelease(context);
        
        CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
        return pxbuffer;
        }
        


        我很确定可以避免转换为 CGImage 并开始使用缓冲区,但我从未尝试过。

        【讨论】:

        • 另见 vImageBuffer_InitWithCVPixelBuffer() / vImageBuffer_InitForCopyToCVPixelBuffer()
        • @IanOllmann 这些功能太棒了!! vImage 在性能上很重要,你能提供一个关于如何做到这一点的例子吗,在标题中他们说这应该用于准备缓冲区到另一个转换。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-27
        • 1970-01-01
        • 1970-01-01
        • 2015-03-18
        相关资源
        最近更新 更多