Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oscardelama/df41163f84cebe1f562c to your computer and use it in GitHub Desktop.
Save oscardelama/df41163f84cebe1f562c to your computer and use it in GitHub Desktop.
rgb-noise: Build a spline approximation to the Lightroom camera tone curve
# 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