Print more fit statistics, as well as a more standard equation form.
Also print the code in pseudo code rather than Rust. Also a few tweaks to other areas of the code.
This commit is contained in:
parent
a1dfebf748
commit
e894568cf8
|
@ -25,7 +25,9 @@ Next, run the processed OpenEXR image through lut_extractor like this:
|
|||
lut_extractor -i filename.exr
|
||||
```
|
||||
|
||||
This will produce two LUT files, one in `.cube` format and one in `.spi1d` format. It will also print Rust code for an attempted analytic fit of the LUT. The printed error percentages only apply to the Rust code, not to the LUT. The LUT is always accurate as long as you followed the steps correctly.
|
||||
This will produce two LUT files, one in `.cube` format and one in `.spi1d` format.
|
||||
|
||||
It also attempts an analytic fit to the LUT, but this only works well for specific kinds of transfer functions. Error statistics and pseudo code of the fit are printed. (Note: Max Relative Error is the most relevant statistic, and should be below 0.01 for an okay fit and below 0.001 for a good fit.)
|
||||
|
||||
And that's it!
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ pub fn find_log_offset_for_end(end: f64, line_offset: f64, slope: f64, base: f64
|
|||
let mut offset_up = 10.0;
|
||||
let mut offset_down = -10.0;
|
||||
|
||||
for _ in 0..54 {
|
||||
for _ in 0..100 {
|
||||
let log_offset = (offset_up + offset_down) * 0.5;
|
||||
if linear_to_log(end, line_offset, slope, log_offset, base) > 1.0 {
|
||||
offset_up = log_offset;
|
||||
|
@ -57,46 +57,38 @@ pub fn find_log_offset_for_end(end: f64, line_offset: f64, slope: f64, base: f64
|
|||
|
||||
//-------------------------------------------------------------
|
||||
|
||||
/// Generates Rust code for a both linear-to-log and log-to-linear
|
||||
/// Generates psuedo code for both linear-to-log and log-to-linear
|
||||
/// functions with the given parameters.
|
||||
pub fn generate_code(line_offset: f64, slope: f64, log_offset: f64, base: f64) -> String {
|
||||
let transition = 1.0 / (slope * base.ln());
|
||||
let k1 = transition + log_offset;
|
||||
let k2 = (transition - line_offset + log_offset) * slope;
|
||||
let k2 = (k1 - line_offset) * slope;
|
||||
let l = (transition - line_offset + log_offset) * slope - transition.log(base);
|
||||
|
||||
format!(
|
||||
r#"
|
||||
const A: f32 = {};
|
||||
const B: f32 = {};
|
||||
const C: f32 = {};
|
||||
const D: f32 = {};
|
||||
const E: f32 = {};
|
||||
A = {} (line slope)
|
||||
B = {} (line y offset)
|
||||
C = {} (log y scale)
|
||||
D = {} (log x offset)
|
||||
E = {} (log y offset)
|
||||
|
||||
pub fn linear_to_log(x: f32) -> f32 {{
|
||||
const P: f32 = {};
|
||||
linear_to_log(x) =
|
||||
if x <= {}:
|
||||
A * x + B
|
||||
else:
|
||||
C * ln(x + D) + E
|
||||
|
||||
if x <= P {{
|
||||
(x - A) * B
|
||||
}} else {{
|
||||
((x - C).log2() / D) + E
|
||||
}}
|
||||
}}
|
||||
|
||||
pub fn log_to_linear(x: f32) -> f32 {{
|
||||
const P: f32 = {};
|
||||
|
||||
if x <= P {{
|
||||
(x / B) + A
|
||||
}} else {{
|
||||
((x - E) * D).exp2() + C
|
||||
}}
|
||||
}}
|
||||
log_to_linear(x) =
|
||||
if x <= {}:
|
||||
(x - B) / A
|
||||
else:
|
||||
e^((x - E) / C) - D
|
||||
"#,
|
||||
line_offset,
|
||||
slope,
|
||||
log_offset,
|
||||
base.log2(),
|
||||
-line_offset * slope,
|
||||
1.0 / base.ln(),
|
||||
-log_offset,
|
||||
l,
|
||||
k1,
|
||||
k2,
|
||||
|
|
|
@ -34,12 +34,12 @@ pub fn find_parameters(lut: &[f32]) {
|
|||
let base = optimize(
|
||||
|v: f64| {
|
||||
let log_offset = crate::linear_log::find_log_offset_for_end(end, offset, slope, v);
|
||||
let mut sqr_err = 0.0f64;
|
||||
let mut rel_err = 0.0f64;
|
||||
for (x, y) in coords.iter().copied() {
|
||||
let e = (log_to_lin(x, offset, slope, log_offset, v) - y).abs() / y.abs();
|
||||
sqr_err += e * e;
|
||||
rel_err += e;
|
||||
}
|
||||
sqr_err
|
||||
rel_err
|
||||
},
|
||||
[1.5, 10000000.0],
|
||||
100,
|
||||
|
@ -49,25 +49,29 @@ pub fn find_parameters(lut: &[f32]) {
|
|||
// Calculate the error of our model.
|
||||
let mut max_err = 0.0f64;
|
||||
let mut avg_err = 0.0f64;
|
||||
let mut max_rel_err = 0.0f64;
|
||||
let mut avg_rel_err = 0.0f64;
|
||||
let mut avg_samples = 0usize;
|
||||
for (x, y) in coords.iter().copied() {
|
||||
let e = (log_to_lin(x, offset, slope, log_offset, base) - y).abs() / y.abs();
|
||||
let e = (log_to_lin(x, offset, slope, log_offset, base) - y).abs();
|
||||
max_err = max_err.max(e);
|
||||
avg_err += e;
|
||||
let rel_e = e / y.abs();
|
||||
max_rel_err = max_rel_err.max(rel_e);
|
||||
avg_rel_err += rel_e;
|
||||
avg_samples += 1;
|
||||
}
|
||||
avg_err /= avg_samples as f64;
|
||||
avg_rel_err /= avg_samples as f64;
|
||||
|
||||
println!("Fitted function statistics:");
|
||||
println!(" Max Relative Error: {}", max_rel_err);
|
||||
println!(" Max Absolute Error: {}", max_err);
|
||||
println!(" Avg Relative Error: {}", avg_rel_err);
|
||||
println!(" Avg Absolute Error: {}", avg_err);
|
||||
|
||||
println!(
|
||||
"Max Relative Error: {:.4}%\nAvg Relative Error: {:.4}%",
|
||||
max_err * 100.0,
|
||||
avg_err * 100.0
|
||||
);
|
||||
|
||||
// dbg!(offset, log_offset, slope, base, end);
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
"\nFitted function pseudo code:\n{}",
|
||||
crate::linear_log::generate_code(offset, slope, log_offset, base),
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user