首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >iOS加速框架vImage -性能改进?

iOS加速框架vImage -性能改进?
EN

Stack Overflow用户
提问于 2015-02-26 10:03:17
回答 3查看 2.8K关注 0票数 6

我一直在与OpenCV和苹果的加速框架合作,发现been的性能很慢,而且苹果的文档有限。让我们举个例子:

代码语言:javascript
复制
void equalizeHistogram(const cv::Mat &planar8Image, cv::Mat &equalizedImage)
{
    cv::Size size = planar8Image.size();
    vImage_Buffer planarImageBuffer = {
        .width = static_cast<vImagePixelCount>(size.width),
        .height = static_cast<vImagePixelCount>(size.height),
        .rowBytes = planar8Image.step,
        .data = planar8Image.data
    };

    vImage_Buffer equalizedImageBuffer = {
        .width = static_cast<vImagePixelCount>(size.width),
        .height = static_cast<vImagePixelCount>(size.height),
        .rowBytes = equalizedImage.step,
        .data = equalizedImage.data
    };

    TIME_START(VIMAGE_EQUALIZE_HISTOGRAM);
    vImage_Error error = vImageEqualization_Planar8(&planarImageBuffer, &equalizedImageBuffer, kvImageNoFlags);
    TIME_END(VIMAGE_EQUALIZE_HISTOGRAM);
    if (error != kvImageNoError) {
        NSLog(@"%s, vImage error %zd", __PRETTY_FUNCTION__, error);
    }
}

这个电话大约需要20毫秒。它在我的应用程序中具有不可用的实际意义。也许直方图的均衡化本身就是缓慢的,但我也测试了BGRA->Grayscale,发现OpenCV可以在5ms内完成,而vImage则需要20 5ms。

在其他函数的测试中,我找到了一个带有模糊函数(要点)模糊函数(要点),并对其进行了测试。大约20毫秒。

让这些功能变得更快有什么窍门吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-05-25 22:57:21

若要使用equalizeHistogram函数每秒获得30帧,您必须将图像(从ARGBxxxx转换为PlanarX)去交错,并且只等于R(ed)G(reen)B(lue);如果您等于A(lpha),帧速率将下降到至少24。

下面的代码完全按照您的需要执行,速度随您的意愿而定:

代码语言:javascript
复制
- (CVPixelBufferRef)copyRenderedPixelBuffer:(CVPixelBufferRef)pixelBuffer {

CVPixelBufferLockBaseAddress( pixelBuffer, 0 );

unsigned char *base = (unsigned char *)CVPixelBufferGetBaseAddress( pixelBuffer );
size_t width = CVPixelBufferGetWidth( pixelBuffer );
size_t height = CVPixelBufferGetHeight( pixelBuffer );
size_t stride = CVPixelBufferGetBytesPerRow( pixelBuffer );

vImage_Buffer _img = {
    .data = base,
    .height = height,
    .width = width,
    .rowBytes = stride
};

vImage_Error err;
vImage_Buffer _dstA, _dstR, _dstG, _dstB;

err = vImageBuffer_Init( &_dstA, height, width, 8 * sizeof( uint8_t ), kvImageNoFlags);
if (err != kvImageNoError)
    NSLog(@"vImageBuffer_Init (alpha) error: %ld", err);

err = vImageBuffer_Init( &_dstR, height, width, 8 * sizeof( uint8_t ), kvImageNoFlags);
if (err != kvImageNoError)
    NSLog(@"vImageBuffer_Init (red) error: %ld", err);

err = vImageBuffer_Init( &_dstG, height, width, 8 * sizeof( uint8_t ), kvImageNoFlags);
if (err != kvImageNoError)
    NSLog(@"vImageBuffer_Init (green) error: %ld", err);

err = vImageBuffer_Init( &_dstB, height, width, 8 * sizeof( uint8_t ), kvImageNoFlags);
if (err != kvImageNoError)
    NSLog(@"vImageBuffer_Init (blue) error: %ld", err);

err = vImageConvert_ARGB8888toPlanar8(&_img, &_dstA, &_dstR, &_dstG, &_dstB, kvImageNoFlags);
if (err != kvImageNoError)
    NSLog(@"vImageConvert_ARGB8888toPlanar8 error: %ld", err);

err = vImageEqualization_Planar8(&_dstR, &_dstR, kvImageNoFlags);
if (err != kvImageNoError)
    NSLog(@"vImageEqualization_Planar8 (red) error: %ld", err);

err = vImageEqualization_Planar8(&_dstG, &_dstG, kvImageNoFlags);
if (err != kvImageNoError)
    NSLog(@"vImageEqualization_Planar8 (green) error: %ld", err);

err = vImageEqualization_Planar8(&_dstB, &_dstB, kvImageNoFlags);
if (err != kvImageNoError)
    NSLog(@"vImageEqualization_Planar8 (blue) error: %ld", err);

err = vImageConvert_Planar8toARGB8888(&_dstA, &_dstR, &_dstG, &_dstB, &_img, kvImageNoFlags);
if (err != kvImageNoError)
    NSLog(@"vImageConvert_Planar8toARGB8888 error: %ld", err);

err = vImageContrastStretch_ARGB8888( &_img, &_img, kvImageNoError );
if (err != kvImageNoError)
    NSLog(@"vImageContrastStretch_ARGB8888 error: %ld", err);

free(_dstA.data);
free(_dstR.data);
free(_dstG.data);
free(_dstB.data);

CVPixelBufferUnlockBaseAddress( pixelBuffer, 0 );

return (CVPixelBufferRef)CFRetain( pixelBuffer );

}

注意,我分配了alpha通道,尽管我没有在它上执行任何操作;这只是因为在ARGB8888和Planar8之间来回转换需要α通道缓冲区分配和引用。无论怎样,性能和质量的提高都是一样的。

还请注意,我在将Planar8缓冲区转换为单个ARGB8888缓冲器后执行对比度拉伸;这是因为它比按信道应用函数快,就像我对直方图均衡函数所做的那样,并且得到了与单独执行相同的结果(对比度拉伸函数不会造成与直方图均衡相同的α信道失真)。

票数 7
EN

Stack Overflow用户

发布于 2015-02-26 12:01:29

如果你能避免的话,不要继续重新分配vImage_Buffer。

vImage加速性能的关键之一是vImage_Buffers的重用。我不能说我在苹果有限的文档中读了多少次这方面的暗示,但我绝对没有听。

在前面提到的模糊代码示例中,我重新编写了测试应用程序,为每个映像设置vImage_Buffer输入和输出缓冲区一次,而不是每次调用boxBlur时设置一次。我每次通话都减少了10毫秒,这在响应时间上产生了明显的差异。

这表明,在你开始看到性能改善之前,加速需要时间来热身。对该方法的第一次调用花费了34 to。

代码语言:javascript
复制
- (UIImage *)boxBlurWithSize:(int)boxSize
{
    vImage_Error error;
    error = vImageBoxConvolve_ARGB8888(&_inputImageBuffer,
                                       &_outputImageBuffer,
                                       NULL,
                                       0,
                                       0,
                                       boxSize,
                                       boxSize,
                                       NULL,
                                       kvImageEdgeExtend);
    if (error) {
        NSLog(@"vImage error %zd", error);
    }

    CGImageRef modifiedImageRef = vImageCreateCGImageFromBuffer(&_outputImageBuffer,
                                                                &_inputImageFormat,
                                                                NULL,
                                                                NULL,
                                                                kvImageNoFlags,
                                                                &error);

    UIImage *returnImage = [UIImage imageWithCGImage:modifiedImageRef];
    CGImageRelease(modifiedImageRef);

    return returnImage;
}
票数 6
EN

Stack Overflow用户

发布于 2015-05-25 23:38:31

若要将vImage与OpenCV一起使用,请将对OpenCV矩阵的引用传递给如下方法:

代码语言:javascript
复制
long contrastStretch_Accelerate(const Mat& src, Mat& dst) {
    vImagePixelCount rows = static_cast<vImagePixelCount>(src.rows);
    vImagePixelCount cols = static_cast<vImagePixelCount>(src.cols);

    vImage_Buffer _src = { src.data, rows, cols, src.step };
    vImage_Buffer _dst = { dst.data, rows, cols, dst.step };

    vImage_Error err;

    err = vImageContrastStretch_ARGB8888( &_src, &_dst, 0 );
    return err;
}

从OpenCV代码块调用此方法,如下所示:

代码语言:javascript
复制
- (void)processImage:(Mat&)image;
{
    contrastStretch_Accelerate(image, image);
}

就这么简单,因为这些都是指针引用,所以没有任何类型的“深度复制”。它是尽可能快和有效的,所有的问题的背景和其他相关的性能-考虑(我也可以帮助你)。

你知道当OpenCV和vImage混在一起时,你必须改变频道排列吗?如果不是,在调用vImage矩阵上的任何OpenCV函数之前,调用:

代码语言:javascript
复制
const uint8_t map[4] = { 3, 2, 1, 0 };
err = vImagePermuteChannels_ARGB8888(&_img, &_img, map, kvImageNoFlags);
if (err != kvImageNoError)
    NSLog(@"vImagePermuteChannels_ARGB8888 error: %ld", err);

执行相同的调用,map和all,将图像返回到适合于OpenCV矩阵的信道顺序。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28739404

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档