使用 ImageIO 将 HDR 图像正确色调映射到 SDK

问题描述 投票:0回答:1

在我的应用程序中,我尝试从存储在Apple照片库中的HDRBT.2100JPEG XL(即16bpc)导出SDR sRGB JPEG(即8bpc)(但这在这里并不重要) ).

我需要正确地将 HDR 输入色彩空间映射到 SDR(SRGB 或 P3 色彩空间,适合 JPG 的低位深度)。这应该是可能的,因为苹果的色彩管理已经支持它。例如,当尝试在 macOS 中的任何位置显示在 SDR 显示器上正确进行颜色管理的原始 JXL 图像时,将产生正确的输出。

由于我想支持非常大(61MP+)10bpc 或 16bpc 图像,因此我尝试使用 ImageIO(如果可能的话,直接使用

CGImageSource

CGImageDestination
),因为它是最高效的内存效率和性能方法。在此之前,我使用 Core Image,它也不会生成正确的色调映射图像,但会增加内存使用量(转换时内存使用量会增加 500-800 MB),并且需要相当长的时间才能完成。

欢迎任何建议。

请注意,这些文件是实际的高动态范围,而不是过去的“HDR 摄影”,后者会将多次曝光合并到传统的 SDR 图像中。

这是我到目前为止所拥有的:

guard let data = sourceImageData, let source = CGImageSourceCreateWithData(data as CFData, [kCGImageSourceShouldCache: false, kCGImageSourceTypeIdentifierHint: asset.uniformType.identifier as CFString] as CFDictionary), let cfOutputData = CFDataCreateMutable(nil, 0), let imageDestination = CGImageDestinationCreateWithData(cfOutputData, outputUTType.identifier as CFString, 1, nil) else { break } var outputOptions: [AnyHashable: Any] = [kCGImageDestinationMergeMetadata: true, kCGImageDestinationLossyCompressionQuality: options.outputLossyCompressionQuality, kCGImageSourceCreateThumbnailFromImageAlways: true, kCGImageSourceCreateThumbnailWithTransform: true] if case let .scaled(scale) = options.outputResize { outputOptions[kCGImageDestinationImageMaxPixelSize] = Double(max(asset.pixelWidth, asset.pixelHeight)) * scale } else if case let .aspectResized(maxPixelSize) = options.outputResize { outputOptions[kCGImageDestinationImageMaxPixelSize] = maxPixelSize } if [.jpeg /* and other 8bpc formats */].contains(options.outputDataFormat) { outputOptions[kCGImageSourceDecodeRequest] = kCGImageSourceDecodeToSDR outputOptions[kCGImageDestinationPreserveGainMap] = false outputOptions[kCGImagePropertyNamedColorSpace] = CGColorSpace.sRGB } else { outputOptions[kCGImageSourceDecodeRequest] = kCGImageSourceDecodeToHDR outputOptions[kCGImageSourceDecodeRequestOptions] = [ "kCGFallbackHDRGain": 10000, "kCGTargetColorSpace": CGColorSpace.itur_2100_PQ, "kCGTargetHeadroom": 1000000 ] } CGImageDestinationAddImageFromSource(imageDestination, source, 0, outputOptions as CFDictionary) if CGImageDestinationFinalize(imageDestination) { imageData = cfOutputData as Data }
我希望 

kCGImageSourceDecodeRequest = kCGImageSourceDecodeToSDR

 能够完成我需要的操作,将 HDR 图像色调映射到 SDR,但可惜,事实并非如此。

有趣的是,用 iPhone 拍摄的 HDR 图像并非采用 BT.2100(或其他 HDR)色彩空间,而是由 P3 基础图像与增益图元数据层组成,我可以使用

kCGImageDestinationPreserveGainMap = false

 正确处理。

以下是 HDR JXL 文件的示例:

https://www.dropbox.com/scl/fi/p9bpuuykjgtwaeax7cfyc/orig.jxl?rlkey=w48cx1av2p2uzbt8m39luq2bb&st=bnrcpkg3&dl=0

如果您在现代 MacBook Pro 上的 macOS 15.0+ 预览版中打开此文件,或者使用合适的 HDR 显示器(例如 Pro Display XDR),您应该能够看到整个动态范围。在 Sequoia 之前的 macOS 上,预览未配置为显示 HDR 图像;在这种情况下,您可以将图像导入到“照片”中,然后“照片”应该正确显示 HDR 范围。 JXL 在 macOS 14 及更高版本、iOS 17 及更高版本中受支持。

一些(不正确的)输出示例:

图像IO ImageIO output

由于它根本没有改变色彩空间,因此该 JPG 的色彩空间是 BT.2100,并且您可以看到源自低位深度的色调分离(色带)。

核心形象 Core Image output

此处,SRGB 色彩空间已正确分配给图像,但未执行色调映射,因此颜色不正确。

照片应用程序

毫不奇怪,如果使用“照片”应用程序复制 (CMD+C) JXL 图像,它会生成具有平滑渐变的正确色调映射的 P3 色彩空间 JPG。

Photos output

任何有关如何实现我需要的建议都将受到赞赏。谢谢

ios macos core-graphics core-image color-management
1个回答
0
投票
结果我把

kCGImageSourceDecodeRequest: kCGImageSourceDecodeToHDR

 选项放在了错误的地方,目的地,而不是源。

这是一个有效的示例代码:

guard var imageData, let source = CGImageSourceCreateWithData(imageData as CFData, [ kCGImageSourceShouldCache: false, kCGImageSourceTypeIdentifierHint: asset.uniformType.identifier, kCGImageSourceDecodeRequest: isRequestSDR ? kCGImageSourceDecodeToSDR : kCGImageSourceDecodeToHDR ] as CFDictionary), let imageDestination = CGImageDestinationCreateWithData(cfOutputData, outputUTType.identifier as CFString, 1, nil) else { return imageData as Any } CGImageDestinationAddImageFromSource(_imageDestination, source, CGImageSourceGetPrimaryImageIndex(source), outputOptions as CFDictionary) if CGImageDestinationFinalize(imageDestination) { imageData = cfOutputData as Data } return imageData
这解决了我原来的问题,但我确实觉得这是一种“魔法”,幕后发生了一些事情,但我不清楚到底发生了什么。如果我想从一种 HDR 格式转换为另一种格式,例如 PQ 转换为 HLG,或者将一种 HDR 色彩空间转换为另一种,我仍然不清楚如何实现。

© www.soinside.com 2019 - 2024. All rights reserved.