aboutsummaryrefslogtreecommitdiff
path: root/apps/CameraITS/tools/compute_dng_noise_model.py
diff options
context:
space:
mode:
Diffstat (limited to 'apps/CameraITS/tools/compute_dng_noise_model.py')
-rw-r--r--apps/CameraITS/tools/compute_dng_noise_model.py175
1 files changed, 0 insertions, 175 deletions
diff --git a/apps/CameraITS/tools/compute_dng_noise_model.py b/apps/CameraITS/tools/compute_dng_noise_model.py
deleted file mode 100644
index 60186c5..0000000
--- a/apps/CameraITS/tools/compute_dng_noise_model.py
+++ /dev/null
@@ -1,175 +0,0 @@
-# Copyright 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-import its.device
-import its.objects
-import its.image
-import pprint
-import pylab
-import os.path
-import matplotlib
-import matplotlib.pyplot
-import numpy
-import math
-
-def main():
- """Compute the DNG noise model from a color checker chart.
-
- TODO: Make this more robust; some manual futzing may be needed.
- """
- NAME = os.path.basename(__file__).split(".")[0]
-
- with its.device.ItsSession() as cam:
-
- props = cam.get_camera_properties()
-
- white_level = float(props['android.sensor.info.whiteLevel'])
- black_levels = props['android.sensor.blackLevelPattern']
- idxs = its.image.get_canonical_cfa_order(props)
- black_levels = [black_levels[i] for i in idxs]
-
- # Expose for the scene with min sensitivity
- sens_min, sens_max = props['android.sensor.info.sensitivityRange']
- s_ae,e_ae,awb_gains,awb_ccm,_ = cam.do_3a()
- s_e_prod = s_ae * e_ae
-
- # Make the image brighter since the script looks at linear Bayer
- # raw patches rather than gamma-encoded YUV patches (and the AE
- # probably under-exposes a little for this use-case).
- s_e_prod *= 2
-
- # Capture raw frames across the full sensitivity range.
- NUM_SENS_STEPS = 15
- sens_step = int((sens_max - sens_min - 1) / float(NUM_SENS_STEPS))
- reqs = []
- sens = []
- for s in range(sens_min, sens_max, sens_step):
- e = int(s_e_prod / float(s))
- req = its.objects.manual_capture_request(s, e)
- req["android.colorCorrection.transform"] = \
- its.objects.float_to_rational(awb_ccm)
- req["android.colorCorrection.gains"] = awb_gains
- reqs.append(req)
- sens.append(s)
-
- caps = cam.do_capture(reqs, cam.CAP_RAW)
-
- # A list of the (x,y) coords of the center pixel of a collection of
- # patches of a color checker chart. Each patch should be uniform,
- # however the actual color doesn't matter. Note that the coords are
- # relative to the *converted* RGB image, which is 1/2 x 1/2 of the
- # full size; convert back to full.
- img = its.image.convert_capture_to_rgb_image(caps[0], props=props)
- patches = its.image.get_color_checker_chart_patches(img, NAME+"_debug")
- patches = [(2*x,2*y) for (x,y) in sum(patches,[])]
-
- lines = []
- for (s,cap) in zip(sens,caps):
- # For each capture, compute the mean value in each patch, for each
- # Bayer plane; discard patches where pixels are close to clamped.
- # Also compute the variance.
- CLAMP_THRESH = 0.2
- planes = its.image.convert_capture_to_planes(cap, props)
- points = []
- for i,plane in enumerate(planes):
- plane = (plane * white_level - black_levels[i]) / (
- white_level - black_levels[i])
- for j,(x,y) in enumerate(patches):
- tile = plane[y/2-16:y/2+16:,x/2-16:x/2+16:,::]
- mean = its.image.compute_image_means(tile)[0]
- var = its.image.compute_image_variances(tile)[0]
- if (mean > CLAMP_THRESH and mean < 1.0-CLAMP_THRESH):
- # Each point is a (mean,variance) tuple for a patch;
- # for a given ISO, there should be a linear
- # relationship between these values.
- points.append((mean,var))
-
- # Fit a line to the points, with a line equation: y = mx + b.
- # This line is the relationship between mean and variance (i.e.)
- # between signal level and noise, for this particular sensor.
- # In the DNG noise model, the gradient (m) is "S", and the offset
- # (b) is "O".
- points.sort()
- xs = [x for (x,y) in points]
- ys = [y for (x,y) in points]
- m,b = numpy.polyfit(xs, ys, 1)
- lines.append((s,m,b))
- print s, "->", m, b
-
- # TODO: Clean up these checks (which currently fail in some cases).
- # Some sanity checks:
- # * Noise levels should increase with brightness.
- # * Extrapolating to a black image, the noise should be positive.
- # Basically, the "b" value should correspnd to the read noise,
- # which is the noise level if the sensor was operating in zero
- # light.
- #assert(m > 0)
- #assert(b >= 0)
-
- # Draw a plot.
- pylab.plot(xs, ys, 'r')
- pylab.plot([0,xs[-1]],[b,m*xs[-1]+b],'b')
- matplotlib.pyplot.savefig("%s_plot_mean_vs_variance.png" % (NAME))
-
- # Now fit a line across the (m,b) line parameters for each sensitivity.
- # The gradient (m) params are fit to the "S" line, and the offset (b)
- # params are fit to the "O" line, both as a function of sensitivity.
- gains = [d[0] for d in lines]
- Ss = [d[1] for d in lines]
- Os = [d[2] for d in lines]
- mS,bS = numpy.polyfit(gains, Ss, 1)
- mO,bO = numpy.polyfit(gains, Os, 1)
-
- # Plot curve "O" as 10x, so it fits in the same scale as curve "S".
- pylab.plot(gains, [10*o for o in Os], 'r')
- pylab.plot([gains[0],gains[-1]],
- [10*mO*gains[0]+10*bO, 10*mO*gains[-1]+10*bO], 'b')
- pylab.plot(gains, Ss, 'r')
- pylab.plot([gains[0],gains[-1]], [mS*gains[0]+bS, mS*gains[-1]+bS], 'b')
- matplotlib.pyplot.savefig("%s_plot_S_O.png" % (NAME))
-
- print """
- /* Generated test code to dump a table of data for external validation
- * of the noise model parameters.
- */
- #include <stdio.h>
- #include <assert.h>
- double compute_noise_model_entry_S(int sens);
- double compute_noise_model_entry_O(int sens);
- int main(void) {
- int sens;
- for (sens = %d; sens <= %d; sens += 100) {
- double o = compute_noise_model_entry_O(sens);
- double s = compute_noise_model_entry_S(sens);
- printf("%%d,%%lf,%%lf\\n", sens, o, s);
- }
- return 0;
- }
-
- /* Generated functions to map a given sensitivity to the O and S noise
- * model parameters in the DNG noise model.
- */
- double compute_noise_model_entry_S(int sens) {
- double s = %e * sens + %e;
- return s < 0.0 ? 0.0 : s;
- }
- double compute_noise_model_entry_O(int sens) {
- double o = %e * sens + %e;
- return o < 0.0 ? 0.0 : o;
- }
- """%(sens_min,sens_max,mS,bS,mO,bO)
-
-if __name__ == '__main__':
- main()
-