Несмотря на то, что фильтр достаточно простой и эффективный, найти примеры кода с его использованием удалось чисто случайно уже после того, как все заработало :-)
Куб предназначен для замены множества цветов. R, G, B компоненты исходного цвета являются трехмерными координатами нового цвета, который задается в виде 4 float’ов (RGBA).
В приведенном примере происходит хитрая замена цвета со всеми оттенками. Для удобства используется работа с цветом в формате HSV, т.к. в этом случае гораздо легче выцеплять схожие цвета - они будут попадать в сектор.
Представление цвета в HSV:
![]()
Итак, на формочке есть 2 слайдера, с помощью которых меняется диапазон заменяемых оттенков. Для удобства считается, что основной цвет для замены находится посередине этого диапазона и именно он меняется на зеленый.
Для этого пробегаем по всем цветам, смотрим попадает ли HSV аналог этого цвета в нужный сектор и если да - запоминаем его смещение относительно центрального. После этого конструируем новый HSV цвет с таким же смещением относительно зеленого и конвертируем обратно в RGB. Подобный код можно было бы использовать, например, для вырезания фона определенного цвета (chroma key). В этом случае все цвета в нужном секторе меняют прозрачность (alpha) на 0.0
Пример заполнения куба:
const unsigned int size = 64;
size_t cubeDataSize = size * size * size * sizeof ( float ) * 4;
float *cubeData = (float *) malloc ( cubeDataSize );
float rgb[3], hsv[3], newRGB[3];
size_t offset = 0;
for (int z = 0; z < size; z++)
{
rgb[2] = ((double) z) / size; // blue value
for (int y = 0; y < size; y++)
{
rgb[1] = ((double) y) / size; // green value
for (int x = 0; x < size; x++)
{
rgb[0] = ((double) x) / size; // red value
rgbToHSV(rgb, hsv);
if (hsv[0] < minHueAngle || hsv[0] > maxHueAngle)
memcpy(newRGB, rgb, sizeof(newRGB));
else
{
hsv[0] = destCenterHueAngle + (centerHueAngle - hsv[0]);
hsvToRGB(hsv, newRGB);
}
cubeData[offset] = newRGB[0];
cubeData[offset+1] = newRGB[1];
cubeData[offset+2] = newRGB[2];
cubeData[offset+3] = 1.0;
offset += 4;
}
}
}
NSData *data = [NSData dataWithBytesNoCopy:cubeData length:cubeDataSize freeWhenDone:YES];
CIFilter *colorCube = [CIFilter filterWithName:@"CIColorCube"];
[colorCube setValue:[NSNumber numberWithInt:size] forKey:@"inputCubeDimension"];
[colorCube setValue:data forKey:@"inputCubeData"];
[colorCube setValue:_ciImage forKey:kCIInputImageKey];В действии
Исходное изображение:
Результат замены:
Разница возникает из-за того, что в разных диапазонах берется разный центральный цвет для замены.
Полный код проекта доступен на гитхабе


