Last active
August 29, 2015 14:14
-
-
Save oscardelama/df41163f84cebe1f562c to your computer and use it in GitHub Desktop.
rgb-noise: Build a spline approximation to the Lightroom camera tone curve
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Plot log-log of LR and our camera tone curves | |
ggplot(lin.rgb.and.tif) + | |
geom_point(aes(x = (mean)/255, y = tif.mean.cam/255, | |
group = channel, colour = channel), | |
size = 1.5) + | |
ggtitle('LR Camera tone curve\nFor Nikon D7000') + | |
xlab('linear sRGB gray (log10)') + ylab('LR camera TC sRGB gray (log10)') + | |
scale_x_log10() + | |
scale_y_log10() + | |
geom_line(aes(x=x, y=y), data=my.cam.tc, color='darkblue', linetype='dashed') | |
# The curve is the same regardless the channel | |
green.df <- subset(lin.rgb.and.tif, channel == 'green') | |
# sort the points | |
green.df <- green.df[with(green.df, order(mean)), ] | |
# Get a composite of LR at the left and our camera TC at the right | |
combo.df <- data.frame('x' = green.df$mean/255, 'y' = green.df$tif.mean.cam/255) | |
# Add my camera TC to the data frame | |
combo.df$my.cam <- my.cam.tc.fun(combo.df$x) | |
# From 37.5 and ahead interpolate from LR cam to my cam TC | |
rows.for.interpol <- which(combo.df$x >= 0.375) | |
combo.df$lr.cam <- combo.df$y | |
my.cam.w <- (combo.df[rows.for.interpol, 'x'] - 0.375)/(0.914635-0.375) | |
combo.df[rows.for.interpol,'lr.cam'] <- | |
with(combo.df[rows.for.interpol,], my.cam.w*my.cam + (1-my.cam.w)*y) | |
# switch to the log10 scale | |
combo.df <- with(combo.df, data.frame('x'=log10(x), 'y'=log10(lr.cam))) | |
# Pass a smooth spline over the LR tone curve points | |
log10.lr.tc.sp <- smooth.spline(x = combo.df$x, | |
y = combo.df$y, | |
all.knots = TRUE) | |
# plot the spline approximation with the source data | |
dom.range <- range(combo.df$x) | |
dom <- seq(dom.range[1],dom.range[2],length.out=512) | |
log10.lr.tc.df <- data.frame(x=dom, y=predict(log10.lr.tc.sp, dom)$y) | |
# Log-log plot of the approximation and the source data | |
ggplot(green.df) + | |
geom_point(aes(x=log10(mean/255), y=log10(tif.mean.cam/255)), | |
color='red', alpha=0.4, size=2.2) + | |
geom_line(aes(x, y), data=log10.lr.tc.df) + | |
ggtitle('LR Camera Tone Curve\nFor Nikon D7000') + | |
xlab('linear sRGB Gray') + ylab('Lightroom camera sRGB gray') + | |
scale_x_continuous(breaks = seq(-3, 0, 1), | |
labels=c('0.1%', '1%', '10%', '100%')) + | |
scale_y_continuous(breaks = seq(-3, 0, 1), | |
labels=c('0.1%', '1%', '10%', '100%')) + | |
# Also plot our camera tone curve | |
geom_line(aes(x=log10(x), y=log10(y)), | |
data=my.cam.tc, linetype='dashed', color='blue') | |
# Make a composite with the LR approximation at the left and our camera TC at the right | |
lr.tc.df <- as.data.frame(10^log10.lr.tc.df) | |
# Add 'my camera TC' to the data frame | |
lr.tc.df$my.cam <- my.cam.tc.fun(lr.tc.df$x) | |
#-- Interpolate from 37.5% to 100% from LR camera to 'my camera' | |
rows.for.interpol <- which(lr.tc.df$x >= 0.375) | |
lr.tc.df$lr.cam <- lr.tc.df$y | |
# Interpolation weights | |
my.cam.w <- (lr.tc.df[rows.for.interpol, 'x'] - 0.375)/(0.91463- 0.375) | |
lr.tc.df[rows.for.interpol,'lr.cam'] <- | |
with(lr.tc.df[rows.for.interpol,], my.cam.w*my.cam + (1-my.cam.w)*y) | |
lr.tc.df <- rbind(lr.tc.df, data.frame(x=1, y=1, my.cam=1, lr.cam=1)) | |
# Pass a natural spline over the composite curve | |
lr.tc.spfun <- splinefun(lr.tc.df$x, y=lr.tc.df$lr.cam, method='natural') | |
# Get a curve with evenly spaced points | |
get.sp.tc <- function(spfun, step, x.range=c(0,1)) { | |
first.deriv <- function(x) { | |
spfun(deriv=1, x=x) | |
} | |
func <- function(x) { | |
spfun(x=x) | |
} | |
x.min <- x.range[1] | |
x.max <- x.range[2] | |
current.value <- x.min | |
tone.curve <- data.frame('x' = x.min, 'y'= func(x.min)) | |
while (current.value < x.max) { | |
deriv <- first.deriv(current.value) | |
dx <- step / sqrt(1+deriv*deriv) | |
current.value <- current.value + dx | |
x <- min(current.value, x.max) | |
tone.curve <- rbind(tone.curve, data.frame('x' = x, 'y'= func(x))) | |
} | |
# result; | |
tone.curve | |
} | |
# Compute evenly spaced LR cam TC points | |
lr.cam.tc <- get.sp.tc(lr.tc.spfun, 1/512) | |
write.csv(lr.cam.tc, 'lr-cam-tc.csv', row.names = FALSE) | |
# Plot the approximation, the LR camera TC data and our original camera TC | |
ggplot(lr.cam.tc) + | |
geom_point(aes(x=(mean)/255, y = tif.mean.cam/255), | |
color='red', alpha=0.25, data=green.df) + | |
geom_line(aes(x=x, y=y)) + | |
ggtitle('LR Camera tone curve') + | |
xlab('linear sRGB gray') + ylab('Lightroom camera sRGB gray') + | |
geom_line(aes(x=x, y=y), data=my.cam.tc, color='darkblue', linetype='dashed') + | |
scale_x_continuous(breaks = seq(0, 1, 0.25), | |
labels=c('0%', '25%', '50%', '75%', '100%')) + | |
scale_y_continuous(breaks = seq(0, 1, 0.25), | |
labels=c('0%', '25%', '50%', '75%', '100%')) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment