Skip to content

Instantly share code, notes, and snippets.

@oscardelama
Last active August 29, 2015 14:14
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/d85a5fe11db274aa1103 to your computer and use it in GitHub Desktop.
Save oscardelama/d85a5fe11db274aa1103 to your computer and use it in GitHub Desktop.
rgb-noise: Condense the three raw noise models in one
library(imgnoiser)
library(ggplot2)
# Y coordinate of sRGB primaries. From http://en.wikipedia.org/wiki/SRGB
weights.sRGB <- c(0.2126, 0.7152, 0.0722)
# D65 white point in XYZ. From ASTM E308-01 in http://www.brucelindbloom.com/
D65.XYZ <- c(0.95047, 1.00000, 1.08883)
# With "D65 color matrix" in the camera color data, we can convert
# the D65 XYZ white point to the camera raw color space:
D65.raw <- nikon.d7000.ISO100.colmap$cam.matrices.2$color.matrix %*% D65.XYZ
#> [,1]
#> [1,] 0.4764640
#> [2,] 1.0805807
#> [3,] 0.8877548
# Now we have a raw white reference to calibrate a colmap object
cm <- colmap$new(nikon.d7000.ISO100.colmap)
raw.to.sRGB.mtx <- cm$get.conv.matrix.from.raw(D65.raw, 'sRGB')
#> White Balance CCT:6498.99259620231
#> White Balance xy (1931):c(0.312727601432607, 0.329033074979199)
# We invert this matrix to convert the weights from sRGB to camera raw
weights.sRGB <- solve(raw.to.sRGB.mtx) %*% weights.sRGB
# Normalize the weigths to sum = 1
weights.sRGB <- weights.sRGB / sum(weights.sRGB)
#> [,1]
#> [1,] 0.1697277
#> [2,] 0.6206335
#> [3,] 0.2096388
# 'Condensed' `snr.optim` regressions of the camera noise variance
D7k.ISO100.var <- function(signal.raw) {
1.669 + 0.41622*signal.raw + 7.972E-06*signal.raw^2
}
# Camera SNR in dB from the `snr.optim` regressions
D7k.ISO100.SNR <- function(signal.raw) {
20*log10(signal.raw/sqrt(D7k.ISO100.var(signal.raw)))
}
# Camera SNR in dB from the 'condensed' `vvm` regressions
D7k.ISO100.SNR.vvm <- function(signal.raw) {
var <- 1.687 + (0.41656 + 7.9017E-06*signal.raw)*signal.raw
20*log10(signal.raw/sqrt(var))
}
# ISO100 raw scale for Nikon D7000
raw.scale <- 15779
# Compute the SNR at 18% gray to compare to DxOMark: the match is perfect!
D7k.ISO100.SNR(0.18*raw.scale)
#> [1] 38.10443
# Gray scale in [0,1] to show in the plot
gray.scale <- 10^seq(-4,0, length=40)
# Raw signal scale in [0, 15779]
signal.raw <- gray.scale*raw.scale
# Data for the plot
SNR.df <- data.frame(
'gray.scale' = gray.scale,
'signal' = signal.raw,
'SNR' = D7k.ISO100.SNR(signal.raw),
'SNR.vvm' = D7k.ISO100.SNR.vvm(signal.raw)
)
# DxOMark data
dxo.d7k <- data.frame(
signal=c(0.019, 0.036, 0.072, 0.13, 0.307, 0.582, 1.317, 2.133, 2.53, 2.926,
3.322, 4.114, 4.511, 4.907, 5.699, 6.492, 6.888, 7.284, 8.473, 12.435,
23.529, 28.284, 40.567, 50.869, 66.717, 81.774, 93.264, 98.811),
snr=c(4.8, 9, 13.1, 16.2, 20.4, 23.3, 26.9, 29.0, 29.8, 30.4, 31, 31.9, 32.3,
32.6, 33.3, 33.8, 34.1, 34.3, 34.9, 36.5, 39.1, 39.9, 41.2, 42, 43, 43.7,
44.1, 44.3))
# Plot the Nikon D7000 SNR graph together with DxOMark data points
x11()
ggplot(SNR.df, aes(gray.scale, SNR)) +
ggtitle('SNR Nikon D7000 - ISO 100\ncompared against DxOMark data') +
geom_line() +
geom_line(aes(gray.scale, SNR.vvm), linetype='dashed', color='blue', size=1, alpha=0.6) +
xlab('Gray linear scale') + ylab('dB') +
scale_x_log10(breaks=10^seq(-4, 0, 1), labels=c('0.01%', '0.1%', '1%', '10%', '100%')) +
geom_point(aes((signal/100), snr), data=dxo.d7k, color='red', alpha=0.40)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment