Как я могу повернуть и вставить изображение с альфа-каналом, используя vImage в ios?
У меня есть большое изображение A и другое изображение B, в котором есть альфа-канал, который я хотел бы вставить в A. Я хочу применить аффинное преобразование к B, прежде чем прикрепить его к A. Каковы шаги для этого в C++ используя vImage в iOS?
2 ответа
Я сомневаюсь, что вы смогли получить любой из ответов, опубликованных здесь, для работы; в них просто не хватает специфики, чтобы помочь кому-то, у кого был такой вопрос, для начала.
Вот ваш рабочий ответ:
- (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 );
}
Предполагая 8 бит на компонент, 4 канала данных:
- Unpremultiply A - vImageUnpremultiplyData_ARGB8888
- извлечь альфа-канал из B - vImageExtractChannel_ARGB8888
- преобразование B - vImageAffineWarp_Planar8
- извлечь альфа-канал из A - vImageExtractChannel_ARGB8888
- умножить два альфа-канала вместе - vImagePremultiplyData_Planar8
- записать результат в A - vImageOverwriteChannels_ARGB8888
- предварительно умножить A - vImagePremultiplyData_ARGB8888
Если вы действительно хотите заменить альфа A на B, а не объединять их вместе, пропустите шаги 4 и 5.
Все это будет работать немного быстрее, если вы выполните все 7 шагов на одной линии сканирования, прежде чем перейти к следующей линии сканирования. kvImageDoNotTile и dispatch_apply() могут использоваться для многопоточности довольно просто.
При предварительном умножении: у вас может быть выбор относительно того, будут ли изображения предварительно умножены или нет. Преимущества производительности для наложения предварительно умноженных изображений обычно завышены. Объединить предварительно не умноженное изображение в предварительно умноженную поверхность лишь немного сложнее, чем сложить предварительно умноженное. Предварительное умножение вызывает проблемы для большинства фильтров изображений, в результате чего куча работы не умножается и снова умножается. Это также вызывает некоторую потерю точности. Как вы можете видеть выше, если изображения предварительно не умножены, то операции, которые вы хотите сделать, становятся намного проще. Это может быть простой шаг 2 и 6 или один проход с vImageSelectChannels_ARGB8888 / vImagePermuteChannelsWithMaskedInsert_ARGB8888().