vImageConvert для извлечения одного канала

Как я могу "извлечь" только один канал из изображения, используя vImage? Мой подход сейчас таков:

vImage_Buffer redBuffer;
redBuffer.data = (void*)redImageData.bytes;
redBuffer.width = size.width;
redBuffer.height = size.height;
redBuffer.rowBytes = [redImageData length]/size.height;
vImage_Buffer redBuffer2;
redBuffer2.width = size.width;
redBuffer2.height = size.height;
redBuffer2.rowBytes = size.width;
vImageConvert_RGB888toPlanar8(&redBuffer, &redBuffer2, nil, nil, kvImageNoFlags);

redBuffer - это рабочее изображение, без ошибок, но vImageConvert дает мне EXC_BAD_ACCESS, я перепробовал много опций, и некоторые приводили к EXC_BAD_ACCESS, а некоторые - к поврежденному выходному изображению. Что я делаю неправильно?

Так что благодаря Робу Кенигеру мне удалось извлечь каналы, но если я попытаюсь соединить их вместе с другими каналами, изображения растягиваются по горизонтали и имеют полосы RGB. Почему они не собраны правильно? Вот пример с извлечением каналов и последующим их объединением:

    vImage_Buffer blueBuffer;
    blueBuffer.data = (void*)blueImageData.bytes;
    blueBuffer.width = size.width;
    blueBuffer.height = size.height;
    blueBuffer.rowBytes = [blueImageData length]/size.height;

    vImage_Buffer rBuffer;
    rBuffer.width = size.width;
    rBuffer.height = size.height;
    rBuffer.rowBytes = size.width;
    void *rPixelBuffer = malloc(size.width * size.height);
    if(rPixelBuffer == NULL)
    {
        NSLog(@"No pixelbuffer");
    }
    rBuffer.data = rPixelBuffer;

    vImage_Buffer gBuffer;
    gBuffer.width = size.width;
    gBuffer.height = size.height;
    gBuffer.rowBytes = size.width;
    void *gPixelBuffer = malloc(size.width * size.height);
    if(gPixelBuffer == NULL)
    {
        NSLog(@"No pixelbuffer");
    }
    gBuffer.data = gPixelBuffer;

    vImage_Buffer bBuffer;
    bBuffer.width = size.width;
    bBuffer.height = size.height;
    bBuffer.rowBytes = size.width;
    void *bPixelBuffer = malloc(size.width * size.height);
    if(bPixelBuffer == NULL)
    {
        NSLog(@"No pixelbuffer");
    }
    bBuffer.data = bPixelBuffer;

    vImageConvert_RGB888toPlanar8(&blueBuffer, &rBuffer, &gBuffer, &bBuffer, kvImageNoFlags);

    size_t destinationImageBytesLength = size.width*size.height*3;
    const void* destinationImageBytes = valloc(destinationImageBytesLength);
    NSData* destinationImageData = [[NSData alloc] initWithBytes:destinationImageBytes length:destinationImageBytesLength];
    vImage_Buffer destinationBuffer;
    destinationBuffer.data = (void*)destinationImageData.bytes;
    destinationBuffer.width = size.width;
    destinationBuffer.height = size.height;
    destinationBuffer.rowBytes = [destinationImageData length]/size.height;

    vImage_Error result = vImageConvert_Planar8toRGB888(&rBuffer, &gBuffer, &bBuffer, &destinationBuffer, 0);
    NSImage* image = nil;
    if(result == kvImageNoError)
    {
        //TODO: If you need color matching, use an appropriate colorspace here
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)(destinationImageData));
        CGImageRef finalImageRef = CGImageCreate(size.width, size.height, 8, 24, destinationBuffer.rowBytes, colorSpace, kCGBitmapByteOrder32Big|kCGImageAlphaNone, dataProvider, NULL, NO, kCGRenderingIntentDefault);
        CGColorSpaceRelease(colorSpace);
        CGDataProviderRelease(dataProvider);
        image = [[NSImage alloc] initWithCGImage:finalImageRef size:NSMakeSize(size.width, size.height)];
        CGImageRelease(finalImageRef);
    }
    free((void*)destinationImageBytes);
    return image;

3 ответа

Решение

Вы не инициализируете redBuffer2 выходной буфер, так что вам некуда хранить выходные данные функции.

//allocate a buffer for the output image and check it exists
void *pixelBuffer = malloc(size.width * size.height);
if(pixelBuffer == NULL)
{
    NSLog(@"No pixelbuffer"); 
    //handle this somehow
}

//assign the allocated buffer to the vImage buffer struct
redBuffer2.data = pixelBuffer;

Решение (или, по крайней мере, начало одного):

err = vImageExtractChannel_ARGB8888(&_src, &_blu, 2, kvImageNoError);
...
uint8_t copyMask = 1;
vImageOverwriteChannels_ARGB8888(&_blu, &_src, &_dst, copyMask, kvImageNoFlags);

Это сработало для меня, за исключением версии OpenCV для моего приложения для камеры iOS; окно предварительного просмотра отображает белую полосу с одной стороны, что происходит каждый раз, когда OpenCV не нравится, как я что-то делаю. Я не думаю, что это будет вашей проблемой, и, учитывая, что это всего лишь три строки кода для вашей множественности строк, стоит попробовать.

vImageConvert_RGB888toPlanar8 не принимает NULL-указатели для структур vImage_Buffer. Функция помечена VIMAGE_NON_NULL(1,2,3,4), что должно вызывать жалобу вашего компилятора на это использование.

На OS X.10 или iOS 8 был добавлен vImageExtractChannel_ARGB8888, но нет эквивалента RGB888. Если вам это нужно, вы должны подать запрос на функцию. http://bugreporter.apple.com/ Тем временем вы можете создать три выходных буфера planar8 и выбросить два.

Другие вопросы по тегам