如何在 ios 中使用 vImage 旋转和粘贴带有 alpha 通道的图像?

Posted

技术标签:

【中文标题】如何在 ios 中使用 vImage 旋转和粘贴带有 alpha 通道的图像?【英文标题】:How can I rotate and paste image with alpha channel using vImage in ios? 【发布时间】:2015-01-25 00:56:23 【问题描述】:

我有一个大图像 A 和另一个图像 B,它有一个 alpha 通道,我想粘贴到 A 中。我想在 B 粘贴到 A 之前对其应用仿射变换。步骤是什么这在 c++ 中使用 ios 中的 vImage?

【问题讨论】:

很遗憾这里遗漏了很多细节。图像是 CGImageRefs 吗? vImage_Buffers? JPEG?用户界面图像? B 中有多少通道。您打算覆盖 A 中已有的 alpha 还是将其混合? A 是预乘的吗?如果您不熟悉底层图形细节,最简单的答案可能是准备一个 CGImageMask 并将其附加到 CGImageRef。 vInage_buffers,alpha 存在于两个图像中,预乘。 【参考方案1】:

我怀疑您是否能够获得此处发布的任何答案;他们只是没有足够的细节来帮助那些一开始就有这样的问题的人。

这是您的有效答案:

- (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 );
//size_t extendedWidth = stride / sizeof( uint32_t ); // each pixel is 4 bytes/32 bits
vImage_Buffer _img = 
    .data = base,
    .height = height,
    .width = width,
    .rowBytes = stride
;

size_t pixelBufferSize = (stride  * height) / sizeof(uint8_t);
void* gBuffer = malloc(pixelBufferSize);
vImage_Buffer _dstG = 
    .data = gBuffer,
    .height = height / sizeof(uint8_t),
    .width = width / sizeof(uint8_t),
    .rowBytes = stride / sizeof(uint8_t)
;

vImage_Error err;

const uint8_t map[4] =  3, 2, 1, 0 ;
err = vImagePermuteChannels_ARGB8888(&_img, &_img, map, kvImageNoFlags);
if (err != kvImageNoError)
    NSLog(@"Error: %ld", err);

err = vImageExtractChannel_ARGB8888(&_img, &_dstG, 2, kvImageNoError);
if (err != kvImageNoError)
    NSLog(@"Error: %ld", err);

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

err = vImageContrastStretch_Planar8( &_dstG, &_dstG, kvImageNoError );
if (err != kvImageNoError)
    NSLog(@"Error: %ld", err);

err = vImageOverwriteChannels_ARGB8888(&_dstG, &_img, &_img, 0x2, kvImageNoError);
if (err != kvImageNoError)
    NSLog(@"Error: %ld", err);

err = vImagePermuteChannels_ARGB8888(&_img, &_img, map, kvImageNoFlags);
if (err != kvImageNoError)
    NSLog(@"Error: %ld", err);

CVPixelBufferUnlockBaseAddress( pixelBuffer, 0 );

free(gBuffer);

return (CVPixelBufferRef)CFRetain( pixelBuffer );

【讨论】:

【参考方案2】:

假设每个组件 8 位,4 通道数据:

    Unpremultiply A -- vImageUnpremultiplyData_ARGB8888 从 B 中提取 alpha 通道 -- vImageExtractChannel_ARGB8888 变换 B -- vImageAffineWarp_Planar8 从 A 中提取 alpha 通道 -- vImageExtractChannel_ARGB8888 将两个 Alpha 通道相乘——vImagePremultiplyData_Planar8 将结果写入A--vImageOverwriteChannels_ARGB8888 预乘 A -- vImagePremultiplyData_ARGB8888

如果您真的想用 B 替换 A 的 alpha 而不是将它们组合在一起,请跳过第 4 步和第 5 步。

如果你在一个扫描线上完成所有 7 个步骤,然后再继续下一个扫描线,整个事情会运行得更快。 kvImageDoNotTile 和 dispatch_apply() 可以非常简单地用于多线程。

关于预乘:您可以选择是否将图像 是否预乘。合成的性能优势 预乘图像通常被夸大了。只是稍微多一点 将非预乘图像合成为预乘图像 表面,而不是合成一个预乘的表面。预乘会导致大多数图像过滤器出现问题,导致 在一堆工作中取消预乘和再次预乘。它也是 造成一些精度损失。如上所示,如果图像是 没有预乘,那么你想做的操作就会变得很多 更简单。可以是简单的步骤 2 和 6,也可以是单程 使用 vImageSelectChannels_ARGB8888 / vImagePermuteChannelsWithMaskedInsert_ARGB8888()。

【讨论】:

以上是关于如何在 ios 中使用 vImage 旋转和粘贴带有 alpha 通道的图像?的主要内容,如果未能解决你的问题,请参考以下文章

对于IOS,如何使用vImage将ARGB图像转换为灰度图像

iOS 使用 vImage - 加速将 QCAR YUV 转换为 RGB

如何从 vImage_Buffer 到 CVPixelBufferRef

iOS Accelerate Framework vImage - 性能改进?

iOS - 将 UIImage 转换为 vImage 内存处理

如何使用加速框架(vImage)缩放灰度图像