给这个问题一些背景(ho ho):
我在iOS下继承了CIFilter,目的是创建一些自定义的照片效果滤镜 . 根据documentation,这意味着创建一个"compound"过滤器,它将一个或多个预先存在的CIF过滤器封装在我的自定义CIFilter子类的保护伞中 .
一切都很好 . 没有问题 . 举例来说,假设我封装了一个CIColorMatrix过滤器,该过滤器已经预设了某些rgba输入向量 .
在应用我的自定义过滤器(或单独使用CIColorMatrix)时,当使用带有颜色管理的CIContext时,我会看到截然不同的结果 . 我正在创建我的上下文如下:
Colour management on:
CIContext * context = [CIContext contextWithOptions:nil];
Colour management off:
NSDictionary *options = @{kCIContextWorkingColorSpace:[NSNull null], kCIContextOutputColorSpace:[NSNull null]};
CIContext * context = [CIContext contextWithOptions:options];
现在,这并不奇怪 . 但是,我注意到所有预先构建的CIPhotoEffect CIFilters,例如CIPhotoEffectInstant在相同的两种颜色管理条件下基本上是不变的 .
任何人都可以提供有关什么给他们这个属性的任何见解?例如,它们是否自己封装了可能具有类似不变性的特定CIF过滤器?
我的目标是创建一些具有相同属性的自定义过滤器,而不仅限于仅链接CIPhotoEffect过滤器 .
编辑:感谢YuAo,我已经汇集了一些工作代码示例,我在这里发布以帮助其他人:
以编程方式生成的CIColorCubeWithColorSpace CIFilter,在不同的颜色管理方案/工作色彩空间下不变:
self.filter = [CIFilter filterWithName:@"CIColorCubeWithColorSpace"];
[self.filter setDefaults];
int cubeDimension = 2; // Must be power of 2, max 128
int cubeDataSize = 4 * cubeDimension * cubeDimension * cubeDimension; // bytes
float cubeDataBytes[8*4] = {
0.0, 0.0, 0.0, 1.0,
0.1, 0.0, 1.0, 1.0,
0.0, 0.5, 0.5, 1.0,
1.0, 1.0, 0.0, 1.0,
0.5, 0.0, 0.5, 1.0,
1.0, 0.0, 1.0, 1.0,
0.0, 1.0, 1.0, 1.0,
1.0, 1.0, 1.0, 1.0
};
NSData *cubeData = [NSData dataWithBytes:cubeDataBytes length:cubeDataSize * sizeof(float)];
[self.filter setValue:@(cubeDimension) forKey:@"inputCubeDimension"];
[self.filter setValue:cubeData forKey:@"inputCubeData"];
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
[self.filter setValue:(__bridge id)colorSpace forKey:@"inputColorSpace"];
[self.filter setValue:sourceImageCore forKey:@"inputImage"];
CIImage *filteredImageCore = [self.filter outputImage];
CGColorSpaceRelease(colorSpace);
文档说明:
要提供CGColorSpaceRef对象作为输入参数,请将其强制转换为id类型 . 使用默认颜色空间(null)(相当于kCGColorSpaceGenericRGBLinear),此滤镜的效果与CIColorCube的效果相同 .
我想更进一步,能够从文件中读取cubeData . 所谓的Hald颜色查找表或Hald CLUT images可用于定义从输入颜色到输出颜色的映射 .
在this回答的帮助下,我也组装了代码来执行此操作,为方便起见,这里重新发布 .
基于Hald CLUT图像的CIColorCubeWithColorSpace CIFilter,在不同的颜色管理方案/工作色彩空间下不变:
用法:
NSData *cubeData = [self colorCubeDataFromLUT:@"LUTImage.png"];
int cubeDimension = 64;
[self.filter setValue:@(cubeDimension) forKey:@"inputCubeDimension"];
[self.filter setValue:cubeData forKey:@"inputCubeData"];
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); // or whatever your image's colour space
[self.filter setValue:(__bridge id)colorSpace forKey:@"inputColorSpace"];
[self.filter setValue:sourceImageCore forKey:@"inputImage"];
帮助方法(使用Accelerate Framework):
- (nullable NSData *) colorCubeDataFromLUT:(nonnull NSString *)name
{
UIImage *image = [UIImage imageNamed:name inBundle:[NSBundle bundleForClass:self.class] compatibleWithTraitCollection:nil];
static const int kDimension = 64;
if (!image) return nil;
NSInteger width = CGImageGetWidth(image.CGImage);
NSInteger height = CGImageGetHeight(image.CGImage);
NSInteger rowNum = height / kDimension;
NSInteger columnNum = width / kDimension;
if ((width % kDimension != 0) || (height % kDimension != 0) || (rowNum * columnNum != kDimension)) {
NSLog(@"Invalid colorLUT %@",name);
return nil;
}
float *bitmap = [self createRGBABitmapFromImage:image.CGImage];
if (bitmap == NULL) return nil;
// Convert bitmap data written in row,column order to cube data written in x:r, y:g, z:b representation where z varies > y varies > x.
NSInteger size = kDimension * kDimension * kDimension * sizeof(float) * 4;
float *data = malloc(size);
int bitmapOffset = 0;
int z = 0;
for (int row = 0; row < rowNum; row++)
{
for (int y = 0; y < kDimension; y++)
{
int tmp = z;
for (int col = 0; col < columnNum; col++) {
NSInteger dataOffset = (z * kDimension * kDimension + y * kDimension) * 4;
const float divider = 255.0;
vDSP_vsdiv(&bitmap[bitmapOffset], 1, ÷r, &data[dataOffset], 1, kDimension * 4); // Vector scalar divide; single precision. Divides bitmap values by 255.0 and puts them in data, processes each column (kDimension * 4 values) at once.
bitmapOffset += kDimension * 4; // shift bitmap offset to the next set of values, each values vector has (kDimension * 4) values.
z++;
}
z = tmp;
}
z += columnNum;
}
free(bitmap);
return [NSData dataWithBytesNoCopy:data length:size freeWhenDone:YES];
}
- (float *)createRGBABitmapFromImage:(CGImageRef)image {
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
unsigned char *bitmap;
NSInteger bitmapSize;
NSInteger bytesPerRow;
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
bytesPerRow = (width * 4);
bitmapSize = (bytesPerRow * height);
bitmap = malloc( bitmapSize );
if (bitmap == NULL) return NULL;
colorSpace = CGColorSpaceCreateDeviceRGB();
if (colorSpace == NULL) {
free(bitmap);
return NULL;
}
context = CGBitmapContextCreate (bitmap,
width,
height,
8,
bytesPerRow,
colorSpace,
(CGBitmapInfo)kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease( colorSpace );
if (context == NULL) {
free (bitmap);
return NULL;
}
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
CGContextRelease(context);
float *convertedBitmap = malloc(bitmapSize * sizeof(float));
vDSP_vfltu8(bitmap, 1, convertedBitmap, 1, bitmapSize); // Converts an array of unsigned 8-bit integers to single-precision floating-point values.
free(bitmap);
return convertedBitmap;
}
可以通过获得身份图像(Google!)然后向其应用相同的图像处理链来创建Hald CLUT图像,该图像处理链应用于用于在任何图像编辑程序中可视化“外观”的图像 . 只需确保将示例代码中的cubeDimension设置为LUT图像的正确尺寸 . 如果尺寸d是沿3D LUT立方体一侧的元素数量,则Hald CLUT图像宽度和高度将是d * sqrt(d)像素,并且图像将具有d ^ 3个总像素 .
2 回答
以下是CIPhotoEffect / CIColorCubeWithColorSpace应该如何使用颜色管理而不是关闭 .
CI管理应该执行以下颜色管理:
从输入空间到立方体空间的颜色匹配 . 如果这两者相等,这就是一个noop .
应用颜色立方体 .
从立方体空间到输出空间的颜色匹配 . 如果这两者相等,这就是一个noop .
关于颜色管理关闭这是CI应该做的事情:
CIPhotoEffect
内部使用CIColorCubeWithColorSpace
过滤器 .所有颜色立方体数据都存储在
CoreImage.framework
中 .你可以在这里找到模拟器的
CoreImage.framework
(/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks/CoreImage.framework/
) .颜色立方体数据以
scube
路径扩展名命名 . 例如CIPhotoEffectChrome.scube
CIColorCubeWithColorSpace
内部隐藏颜色立方体颜色值,以使用私有方法匹配当前核心图像上下文的工作颜色空间:-[CIImage _imageByMatchingWorkingSpaceToColorSpace:]; -[CIImage _imageByMatchingColorSpaceToWorkingSpace:];