79 lines
2.4 KiB
Swift
79 lines
2.4 KiB
Swift
|
|
import Foundation
|
||
|
|
|
||
|
|
/// Camera log transfer functions. Constants from vendor whitepapers:
|
||
|
|
/// - ARRI LogC4 (ALEXA 35), ARRI LogC4 spec 2022
|
||
|
|
/// - RED Log3G10 v3, RED IPP2 whitepaper
|
||
|
|
/// - Sony S-Log3, Sony technical summary
|
||
|
|
public enum TransferFunction: String, Sendable, CaseIterable, Codable {
|
||
|
|
case logC4
|
||
|
|
case log3G10
|
||
|
|
case sLog3
|
||
|
|
case linear
|
||
|
|
|
||
|
|
/// Linear scene value -> encoded log signal (0..1 nominal).
|
||
|
|
public func encode(_ x: Float) -> Float {
|
||
|
|
switch self {
|
||
|
|
case .linear:
|
||
|
|
return x
|
||
|
|
case .logC4:
|
||
|
|
let c = LogC4.self
|
||
|
|
if x < c.t { return (x - c.t) / c.s }
|
||
|
|
return (log2(c.a * x + 64) - 6) / 14 * c.b + c.c
|
||
|
|
case .log3G10:
|
||
|
|
let c = Log3G10.self
|
||
|
|
let y = x + c.c
|
||
|
|
if y < 0 { return y * c.g }
|
||
|
|
return c.a * log10(y * c.b + 1)
|
||
|
|
case .sLog3:
|
||
|
|
let c = SLog3.self
|
||
|
|
if x >= c.linBreak {
|
||
|
|
return (420 + log10((x + 0.01) / 0.19) * 261.5) / 1023
|
||
|
|
}
|
||
|
|
return (x * (171.2102946929 - 95) / c.linBreak + 95) / 1023
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Encoded log signal -> linear scene value.
|
||
|
|
public func decode(_ y: Float) -> Float {
|
||
|
|
switch self {
|
||
|
|
case .linear:
|
||
|
|
return y
|
||
|
|
case .logC4:
|
||
|
|
let c = LogC4.self
|
||
|
|
if y < 0 { return y * c.s + c.t }
|
||
|
|
return (exp2(14 * (y - c.c) / c.b + 6) - 64) / c.a
|
||
|
|
case .log3G10:
|
||
|
|
let c = Log3G10.self
|
||
|
|
if y < 0 { return y / c.g - c.c }
|
||
|
|
return (pow(10, y / c.a) - 1) / c.b - c.c
|
||
|
|
case .sLog3:
|
||
|
|
let c = SLog3.self
|
||
|
|
if y >= 171.2102946929 / 1023 {
|
||
|
|
return pow(10, (y * 1023 - 420) / 261.5) * 0.19 - 0.01
|
||
|
|
}
|
||
|
|
return (y * 1023 - 95) * c.linBreak / (171.2102946929 - 95)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// MARK: Constants
|
||
|
|
|
||
|
|
private enum LogC4 {
|
||
|
|
static let a: Float = (exp2(18) - 16) / 117.45
|
||
|
|
static let b: Float = (1023 - 95) / 1023
|
||
|
|
static let c: Float = 95.0 / 1023.0
|
||
|
|
static let s: Float = (7 * log(2.0 as Float) * exp2(7 - 14 * c / b)) / (a * b)
|
||
|
|
static let t: Float = (exp2(14 * (-c / b) + 6) - 64) / a
|
||
|
|
}
|
||
|
|
|
||
|
|
private enum Log3G10 {
|
||
|
|
static let a: Float = 0.224282
|
||
|
|
static let b: Float = 155.975327
|
||
|
|
static let c: Float = 0.01
|
||
|
|
static let g: Float = 15.1927
|
||
|
|
}
|
||
|
|
|
||
|
|
private enum SLog3 {
|
||
|
|
static let linBreak: Float = 0.01125000
|
||
|
|
}
|
||
|
|
}
|