Как я могу повернуть и вставить изображение с альфа-каналом, используя vImage в ios?

У меня есть большое изображение A и другое изображение B с альфа-каналом, который я хотел бы вставить в A. Я хочу применить аффинное преобразование к B, прежде чем прикреплять его к A. Каковы шаги для этого в С++ используя vImage в iOS?


person twerdster    schedule 25.01.2015    source источник
comment
Я сожалею, что здесь много недостающих деталей. Являются ли изображения CGImageRefs? vImage_Buffers? JPEG? UIImages? Сколько каналов в B. Собираетесь ли вы перезаписать альфу уже в A или смешать ее? Является ли А предварительно умноженным? Возможно, самый простой ответ, если вы не знакомы с низкоуровневыми графическими деталями, — это подготовить CGImageMask и прикрепить его к CGImageRef.   -  person Ian Ollmann    schedule 25.01.2015
comment
vInage_buffers альфа присутствует в обоих изображениях, предварительно умноженных.   -  person twerdster    schedule 25.01.2015


Ответы (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 );

}

person James Bush    schedule 13.05.2015

Предполагая, что 8 бит на компонент, 4-канальные данные:

  1. Unpremultiply A -- vImageUnpremultiplyData_ARGB8888
  2. извлечь альфа-канал из B -- vImageExtractChannel_ARGB8888
  3. преобразование B -- vImageAffineWarp_Planar8
  4. извлечь альфа-канал из A -- vImageExtractChannel_ARGB8888
  5. умножьте два альфа-канала вместе -- vImagePremultiplyData_Planar8
  6. записать результат в A -- vImageOverwriteChannels_ARGB8888
  7. предварительное умножение A -- vImagePremultiplyData_ARGB8888

Если вы действительно хотите заменить альфу A на B, а не скомпоновать их вместе, пропустите шаги 4 и 5.

Все это будет работать немного быстрее, если вы сделаете все 7 шагов на одной строке сканирования, прежде чем переходить к следующей строке сканирования. kvImageDoNotTile и dispatch_apply() можно довольно просто использовать для многопоточности.

При предварительном умножении: у вас может быть выбор, будут ли изображения предварительно умножаться или нет. Выгоды от компоновки предварительно умноженных изображений обычно преувеличивают. Компоновка изображения без предварительного умножения в поверхность с предварительным умножением требует незначительно больше усилий, чем компоновка изображения с предварительным умножением. Предварительное умножение вызывает проблемы для большинства фильтров изображений, что приводит к куче работы по предварительному умножению и повторному умножению. Это также приводит к некоторой потере точности. Как вы можете видеть выше, если изображения не предварительно умножены, то операции, которые вы хотите выполнить, становятся намного проще. Это может быть просто шаг 2 и 6 или один проход с vImageSelectChannels_ARGB8888 / vImagePermuteChannelsWithMaskedInsert_ARGB8888().

person Ian Ollmann    schedule 27.01.2015