Last active
August 29, 2015 14:14
-
-
Save oscardelama/d85a5fe11db274aa1103 to your computer and use it in GitHub Desktop.
rgb-noise: Condense the three raw noise models in one
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
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