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 и выбросить два.