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

How can I rotate and paste image with alpha channel using vImage in ios?

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

中使用 vImage 在 c++ 中执行此操作

假设每个组件 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() 可以非常简单地用于多线程。

On premultiplication: You may have a choice as to whether the images are premultiplied or not. The performance benefits for compositing of premultiplied images is usually overstated. It is only marginally more work to composite a non-premultiplied image into a premultiplied surface than it is to composite a premultiplied one. Premultiplication causes problems for most image filters, resulting in a bunch of work unpremultiplying and premultiplying again. It also causes some precision loss. As you can see above, if the images are not premultiplied, then the operations you want to do become much simpler. It could be a simple as just steps 2 and 6, or a single pass with vImageSelectChannels_ARGB8888 / vImagePermuteChannelsWithMaskedInsert_ARGB8888().

我怀疑您是否能够使此处发布的任何答案发挥作用;他们只是没有足够的细节来帮助有这样问题的人。

这是您的有效答案:

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

}