0

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

4

2 回答 2

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 );

}

于 2015-05-13T16:08:18.973 回答
0

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

  1. 取消预乘 A -- vImageUnpremultiplyData_ARGB8888
  2. 从 B 中提取 alpha 通道 -- vImageExtractChannel_ARGB8888
  3. 变换 B -- vImageAffineWarp_Planar8
  4. 从 A 中提取 alpha 通道 -- vImageExtractChannel_ARGB8888
  5. 将两个 Alpha 通道相乘——vImagePremultiplyData_Planar8
  6. 将结果写入 A -- vImageOverwriteChannels_ARGB8888
  7. 预乘A——vImagePremultiplyData_ARGB8888

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

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

关于预乘:您可以选择是否对图像进行预乘。合成预乘图像的性能优势通常被夸大了。将非预乘图像合成到预乘表面仅比合成预乘图像多一点工作。预乘会导致大多数图像过滤器出现问题,导致一堆工作不预乘并再次预乘。它也会导致一些精度损失。正如你在上面看到的,如果图像没有被预乘,那么你想要做的操作就会变得简单得多。它可以是简单的步骤 2 和 6,也可以是使用 vImageSelectChannels_ARGB8888 / vImagePermuteChannelsWithMaskedInsert_ARGB8888() 的单通道。

于 2015-01-27T04:53:49.403 回答