CIPhotoEffect CIFilters 在色彩管理方面是不变的。是什么赋予了 CIPhotoEffect 滤镜这个属性?

2023-11-30

给这个问题一些背景(ho ho):

我在 iOS 下对 CIFilter 进行子类化,以便创建一些自定义照片效果滤镜。根据文档,这意味着创建一个“复合”过滤器,将一个或多个预先存在的 CIFilter 封装在我的自定义 CIFilter 子类的范围内。

一切都很好。那里没有问题。举例来说,假设我封装了一个 CIColorMatrix 过滤器,该过滤器已预设了某些 rgba 输入向量。

当应用我的自定义过滤器(或者实际上是单独的 CIColorMatrix)时,在使用颜色管理打开和关闭的 CIContext 时,我看到完全不同的结果。我正在创建我的上下文,如下所示:

色彩管理:

CIContext * context = [CIContext contextWithOptions:nil];

色彩管理关闭:

NSDictionary *options = @{kCIContextWorkingColorSpace:[NSNull null], kCIContextOutputColorSpace:[NSNull null]};
CIContext * context = [CIContext contextWithOptions:options];

现在,这并不奇怪。然而,我注意到所有预先构建的 CIPhotoEffect CIFilters,例如CIPhotoEffectInstant 在这两种相同的颜色管理条件下本质上是不变的。

任何人都可以提供任何见解来了解是什么赋予了他们这种财产吗?例如,它们本身是否封装了可以以类似不变性应用的特定 CIFilter?

我的目标是创建一些具有相同属性的自定义滤镜,而不仅限于仅链接 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。所谓的 Haled 颜色查找表,或保留 CLUT 图像可用于定义从输入颜色到输出颜色的映射。

在来自的帮助下this答案,我也组装了代码来执行此操作,为了方便起见,将其重新发布到此处。

Hald CLUT图像基于CIColorCubeWithColorSpace CIFilter,在不同颜色管理方案/工作色彩空间下不变:

Usage:

    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, &divider, &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。


CIPhotoEffect内部使用CIColorCubeWithColorSpace filter.

所有颜色立方体数据都存储在CoreImage.framework.

你可以找到模拟器的CoreImage.framework here (/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:];

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CIPhotoEffect CIFilters 在色彩管理方面是不变的。是什么赋予了 CIPhotoEffect 滤镜这个属性? 的相关文章

  • RemoteIO 音频单元播放回调中的 AudioBufferList 内容

    我想 拦截 音频数据传送到 iOS 设备扬声器的过程 我相信这可以使用 RemoteIO 音频单元和回调来完成 在下面的playbackCallback中 ioData实际上包含任何音频数据吗 static OSStatus playbac
  • IPV6 快速可达性

    我是 swift 和 xcode 的新手 并且我的应用程序因 IPV6 而被拒绝 性能 2 1 当我们执行以下操作时 您的应用程序会在运行 iOS 9 3 5 并连接到 IPv6 网络的 iPad 和 iPhone 上崩溃 具体来说 当我们
  • 如何在 C++ BOOST 中像图形一样加载 TIFF 图像

    我想要加载一个 tiff 图像 带有带有浮点值的像素的 GEOTIFF 例如 boost C 中的图形 我是 C 的新手 我的目标是使用从源 A 到目标 B 的双向 Dijkstra 来获得更高的性能 Boost GIL load tiif
  • 无法在 Windows 上使用 Gnustep 编译 Objective C

    嗨 我是初学者 学习目标c 我发现错误 hello m 1 34 Foundation Foundation h 没有这样的文件或目录 我开始知道我需要制作一个 make 文件 我可以知道如何制作 make 文件吗 无需创建 makefil
  • 我如何获取用户的电子邮件? iPhone SDK

    我需要获取 Mail app 中使用的用户的电子邮件地址 如何使用 iPhone SDK 做到这一点 谢谢你 简短的回答 你不能 如果需要 您应该提示用户输入电子邮件地址
  • 仅将 UIImage 移动到另一个 UIImage 内部

    I have an UIImage which is shown in an UIImageView I also have another image in an UIImageView which lays above the firs
  • IOS7 状态栏在选定控制器上隐藏/显示

    我想在某些控制器上显示和隐藏状态栏 这可以完成吗 或者它更像是一个整体应用程序设置 我看过很多关于 plist 更新的帖子 问题 View controller based status bar appearance NO 如果这完成了 那
  • 我可以更改键盘方向吗?

    例如我用这段代码关闭自动旋转 BOOL shouldAutorotateToInterfaceOrientation UIInterfaceOrientation interfaceOrientation return NO BOOL sh
  • Xcode 无法找到 strip-frameworks.sh 目录

    我最近将 Xcode 更新到版本 7 1 其中包括 Swift 2 1 我安装了 Swift 2 1 没有遇到任何问题 在尝试运行我的项目后 我意识到我需要获取最新版本的 Realm 因为之前的版本不支持 Swift 2 1 我删除了旧框架
  • Firebase Analytics 禁用受众国家/地区跟踪

    我正在开发一个严格不允许位置跟踪的应用程序 我想使用 Firebase Analytic 的其他功能 例如 PageTransitions 和 Crashalitics 但如果我无法禁用受众位置跟踪 我就无法使用其中任何功能 这是我在 An
  • 将子视图控制器的视图添加到父视图控制器的子视图

    我想添加一个表视图控制器作为容器视图控制器的子视图控制器 如下所示 根据苹果公司的查看控制器编程指南 http developer apple com library ios featuredarticles ViewControllerP
  • 两者都实现了类。将使用两者之一

    我有一个项目 它具有使用 SocketRocket 的依赖项 通过 CocoaPods 安装 并从 HeapAnalytics 导入了静态库 显然 HeapAnalytics 库已经使用了 SocketRocket 编译时没有出现错误 但在
  • 如何在 UICollectionView 的节标题中动态添加标签和按钮?

    请帮助我如何水平添加标签和水平添加类似的按钮 但每个按钮应像另一个部分一样在每个标签的下方对齐 这应该在 UICollectionView 的标题中动态发生 因为标签和按钮的数量根据我的数据 我想制作一种 Excel 类型的布局 并在标题中
  • 为什么使用[ClassName alloc]而不是[[self class] alloc]?

    我正在读马克 达尔林普尔 Mark Dalrymple 的著作在 Mac 上学习 Objective C 仅在协议章节 所以仍然相对较新 并试图弄清楚一些事情 为什么要通过类自己的名称来引用它 如果我有一个叫做Foo 为什么我会想写 比如说
  • 如何防止 RealmSwift 列表中出现重复项?

    如何防止向列表中添加重复项RealmSwift 我有我的User作为领域对象 但真正的数据源是服务器 只是使用领域在本地缓存用户 当我从服务器获取当前用户数据时 我想确保存储在领域中的用户拥有来自服务器的所有播放列表 以及它们的曲目列表等
  • 带有 Core Data 对象的动态 UITableView 高度

    过去几天我一直在试图解决一个谜团 即为什么我的批处理大小为 20 的 NSFetchedResultsController 总是在获取完成后立即错误 即加载到内存中 我的所有对象 从而导致请求需要约 20 秒 事实证明 这是因为在我的 he
  • 是什么导致了这个 iPhone 崩溃日志?

    我有点卡住了 需要解决这个问题 因为我的一个应用程序出现了随机崩溃 而这些崩溃并不总是能够重现 这是崩溃日志之一 Incident Identifier 59865612 9F00 44EA 9474 2BF607AD662E CrashR
  • iOS 10 的错误? NSDate 日本地区时间描述和 24 小时休息

    这似乎是 iOS 10 的一个错误 在 iOS 8 和 9 中都可以 NSDate date description 的小时描述是错误的 它附加了 24 小时描述和 12 小时描述 我没有使用 NSDateFormatter 只是默认设置
  • 用 UIView 像翻书一样翻页?

    我正在尝试在之间切换UIViews让它看起来就像你正在翻书的一页 The UIViewAnimationTransitionCurlUp如果我能让它向左或向右卷曲 那就非常接近了 这可能吗 我尝试过使用CATRansition但没有一种动画
  • UISplitViewController - 推送模态视图

    使用 UISplitViewController 时推送模态视图的最佳实践是什么 您会从 RootViewController DetailViewController 还是直接从应用程序委托推送 理想情况下 我想要实现的功能是在基于某些条

随机推荐

  • 如何使用 POP3 检索 Gmail 子文件夹/标签?

    下面的代码使用javamail API来访问gmail String host pop gmail com int port 995 Properties properties new Properties properties put m
  • 从 Xcode 启动 iOS 模拟器并出现黑屏,然后 Xcode 挂起且无法停止任务

    我在 iOS 模拟器中运行基本 iPhone 应用程序时遇到问题 在阅读斯坦福 iTunes CS193p 讲座时 我已经搜索了一段时间 Google 和 SO 但到目前为止找不到解决方案 类似的错误还有很多 但解决方案似乎并不能解决这个问
  • cor.test() 的矩阵版本

    Cor test 需要向量x and y作为参数 但我有一个完整的数据矩阵 我想成对地测试 Cor 将此矩阵作为参数就好了 我希望找到一种方法来为cor test 其他人的常见建议似乎是使用cor prob https stat ethz
  • Jquery 旋转 div [重复]

    这个问题在这里已经有答案了 我无法旋转 div 控制台中没有警告或错误 您可以查看JSFiddle 版本在这里 我使用的代码是 div2 click someFunction2 function someFunction2 div2 ani
  • 禁用 HTML5 范围输入的跟踪

    我正在尝试找到一种方法来阻止用户单击 HTML5 范围输入的 轨道 部分 本质上 我只希望用户能够使用 句柄 来更改范围值 这可能吗 至少在 chrome 上可以通过指针事件实现 input type range pointer event
  • 客户端与服务器对话时如何克服“Access-Control-Allow-Origin”错误

    因此 我正在使用 swiip 的一个 yeoman 项目 名为 Generator gulp Angular 只需执行 npm search gulp Angular 您就会看到它 开箱即用的客户端从 127 0 0 1 3000 运行 我
  • 从 java webstart 应用程序中的 jar 获取资源

    我正在尝试在 Java Webstart 应用程序中加载大量资源 我最初尝试使用以下方式加载这些 ClassLoader loader MyClass class getClassLoader URL url loader getResou
  • mongodb keep_mutation阶段解释

    我使用mongo的explain 来检查一些查询的性能 有时会出现keep mutation阶段 如下所示 executionStats executionStages stage KEEP MUTATIONS nReturned 1 ex
  • Rails 3 设计 401 未经授权的 ajax 调用

    我遇到了与这个问题类似的问题 Rails 3 中的 jQuery Ajax 调用收到 401 未经授权的请求 我已将 token authenticatable 添加到我的设计模型中 在我的 ajax 调用操作中 def rate para
  • 如何将列表应用于 pandas 组[重复]

    这个问题在这里已经有答案了 我看到这个问题 在 pandas groupby 中对列表中的行进行分组 但我想要应用两列以上list input df pd DataFrame index c1 c2 c3 1 A 6 1 2 A 5 2 3
  • 如何通过按键切换元素的内容?

    我目前正在尝试创建一个网站 如果我按 q p 标签将从 Q 更改为 A 目前 这适用于下面的代码 然而问题是 当按 q 时 它需要返回到 A 我尝试让它与removeEventListeners 一起使用 但它似乎不起作用 Like die
  • 如何递归地从表中删除项目?

    我有一个 MySQL 表 文件夹 CREATE TABLE IF NOT EXISTS folders id int 11 unsigned NOT NULL AUTO INCREMENT folder key varchar 40 NOT
  • sed:在块之后追加

    我对 sed 很陌生 我发现的所有内容都是这里一点 那里一点 我有一个文本文件 其中包含如下所示的块 start a b c whatever 显然 这是一个简化版本 我想在末尾添加一行 start阻止给我 start a b c d wh
  • 如何使用表中可能不可用的 ID 构建 SQL 语句?

    使用 Microsoft SQL Server 2008 假设有一个 table1 保存所选的省 区 公社和村庄的 ID 然后是表2 其中包含省 区 公社和村庄的ID和名称 省份和地区是必填字段 并且始终会被填满 公社和村庄可能会被填满 但
  • 使用 Apache Spark 将键值对简化为键列表对

    我正在编写一个 Spark 应用程序 想要组合一组键值对 K V1 K V2 K Vn 成一个键 多值对 K V1 V2 Vn 我觉得我应该能够使用reduceByKey带有某种味道的函数 My KMV My KV reduce lambd
  • NSString:isEqual 与 isEqualToString

    有什么区别isEqual and isEqualToString 为什么类要添加 isEqualTo 方法 对于 NSArray 来说是 isEqualToArray 对于 NSData 来说是 isEqualToData 而不是仅仅重写i
  • AFNetworking 表单请求(一个请求中上传多个文件)

    我们正在开发一个 iOS 应用程序 该应用程序在一个请求中提供单个以及多个文件上传选项 我使用 AFNetworking 进行单个文件上传 效果很好 现在 我们需要支持多个文件上传 我有 html 代码 它实际上可以从网络上传多个文件 我需
  • DISPID_VALUE 对于从脚本调用 IDispatch 是否可靠?

    继续从这个问题 我很困惑是否DISPID VALUE on IDispatch Invoke 脚本函数和属性 在我的例子中是 JavaScript 可以被认为是标准且可靠的 用于调用由IDispatch 如果是 MSDN 中是否提到过 请注
  • Java全屏独占模式

    我使应用程序在独占模式下全屏显示 但是当我显示输入对话框时 应用程序被最小化 我希望应用程序保持全屏 并在其上显示输入对话框 这就是我全屏渲染应用程序的方式 setUndecorated true GraphicsEnvironment g
  • CIPhotoEffect CIFilters 在色彩管理方面是不变的。是什么赋予了 CIPhotoEffect 滤镜这个属性?

    给这个问题一些背景 ho ho 我在 iOS 下对 CIFilter 进行子类化 以便创建一些自定义照片效果滤镜 根据文档 这意味着创建一个 复合 过滤器 将一个或多个预先存在的 CIFilter 封装在我的自定义 CIFilter 子类的