General info about pattern noise: http://theory.uchicago.edu/~ejm/pix/20d/tests/noise/#patternnoise
The CMV12000 sensor suffers from dynamic row noise.
That means, a scalar offset gets added to each row. The offset is not correlated between different frames, so we can't remove it using a calibration frame (dark frame or whatever).
One can observe this noise by looking at the difference between two images taken at identical settings. There are two main components that appear obvious in such a difference frame: random noise (per pixel, increases on brighter pixels) and row noise (per line).
There are two ways to deal with this noise, after performing Black Calibration:
The application note AN01 from CMOSIS says:
"The noise is also present in the black reference columns (8 left and 8 right), so when enabled (reg 89 = 1), these can be used for row noise correction by for example making a relative row profile of these black columns and subtract this from the image."
However, simply subtracting each row average of the black columns from our image is not going to work. Here's why:
Kalman filter theory: http://robocup.mi.fu-berlin.de/buch/kalman.pdf
From page 3, if we know how noisy our estimations are, the optimal weights are inversely proportional with the noise variances:
x_optimal = (x1 * var(x2) + x2 * var(x1)) / (var(x1) + var(x2))
Here, let's say R = x1 is row noise (stdev = 1.6 at gain=x1) and x2 is black column noise.
R = x1 B = mean(black_col') = R + x2 => x2 = B - R x2 can be estimated as mean(black_col') - mean(active_area') stdev(x2) = 1.3.
We want to find k that minimizes var(R - k*B).
var(R - k*B) = var(x1 * (1-k) - x2 * k), => k = var(x1)) / (var(x1) + var(x2).
In particular, for gain = x1, k = 1.6^2 / (1.6^2 + 1.3^2) = 0.6.
So, we don't have to simply subtract the black columns. Rather, we'll subtract the static offset (median value) first, and then, we'll subtract the remaining variations multiplied by 0.6 at gain=x1.
Things get a little more complex because the static offset is different on odd and even rows, and it also appears to change from the left side to right side of the frame. More details on the Raw preprocessing page.
A closer look at the frequency spectrum of the black columns, compared to the spectrum of the row noise from a dark frame, revealed a strong fixed-frequency component present only in the black columns. Attempting to fix row noise with the above procedure would introduce some of this fixed frequency component in the main image as well.
In the example image from below, this component has a frequency of 1/41.27 pixels-1, with an amplitude of 1.14 DN. The value is different in other test images, and appears to be consistent in the images taken during the same experiment. It doesn't change with exposure time. Cause is unknown.
TODO: detailed analysis, FFT graphs...
We'll attempt to filter out this perturbation from the black columns before using them for reducing row noise.
The methods discussed here are implemented in raw2dng.
Troubleshooting or checking the effectiveness of each step:
Tip: the algorithm for filtering row noise is also available in MLVFS, so you can use it on MLV videos (recorded with Magic Lantern) as well.
Showing half-res image crops pushed by 4 stops (ufraw-batch --wb=auto --exposure=4 --shrink=2).
Corrected with dark frame and dark current only:
Also corrected with black columns:
Also corrected with --fixrn:
Larger images (half-res):
All files used for this test, including scripts, calibration frames and uncompressed images, can be found here: http://files.apertus.org/AXIOM-Beta/snapshots/pattern-noise/
In particular, you might be interested in: