diff options
Diffstat (limited to 'apps/CameraITS/tools')
-rw-r--r-- | apps/CameraITS/tools/compute_dng_noise_model.py | 175 | ||||
-rw-r--r-- | apps/CameraITS/tools/config.py | 66 | ||||
-rw-r--r-- | apps/CameraITS/tools/run_all_tests.py | 66 |
3 files changed, 0 insertions, 307 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 e089ffc..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(get_results=True) - 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() - diff --git a/apps/CameraITS/tools/config.py b/apps/CameraITS/tools/config.py deleted file mode 100644 index 6e83412..0000000 --- a/apps/CameraITS/tools/config.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2013 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.target -import sys - -def main(): - """Set the target exposure. - - This program is just a wrapper around the its.target module, to allow the - functions in it to be invoked from the command line. - - Usage: - python config.py - Measure the target exposure, and cache it. - python config.py EXP - Hard-code (and cache) the target exposure. - - The "reboot" or "reboot=<N>" and "camera=<N>" arguments may also be - provided, just as with all the test scripts. The "target" argument is - may also be provided but it has no effect on this script since the cached - exposure value is cleared regardless. - - If no exposure value is provided, the camera will be used to measure - the scene and set a level that will result in the luma (with linear - tonemap) being at the 0.5 level. This requires camera 3A and capture - to be functioning. - - For bring-up purposes, the exposure value may be manually set to a hard- - coded value, without the camera having to be able to perform 3A (or even - capture a shot reliably). - """ - - # Command line args, ignoring any args that will be passed down to the - # ItsSession constructor. - args = [s for s in sys.argv if s[:6] not in \ - ["reboot", "camera", "target", "noinit"]] - - if len(args) == 1: - with its.device.ItsSession() as cam: - # Automatically measure target exposure. - its.target.clear_cached_target_exposure() - exposure = its.target.get_target_exposure(cam) - elif len(args) == 2: - # Hard-code the target exposure. - exposure = int(args[1]) - its.target.set_hardcoded_exposure(exposure) - else: - print "Usage: python %s [EXPOSURE]" - sys.exit(0) - print "New target exposure set to", exposure - print "This corresponds to %dms at ISO 100" % int(exposure/100/1000000.0) - -if __name__ == '__main__': - main() - diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py deleted file mode 100644 index 4677331..0000000 --- a/apps/CameraITS/tools/run_all_tests.py +++ /dev/null @@ -1,66 +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 os -import os.path -import tempfile -import subprocess -import time -import sys - -def main(): - """Run all the automated tests, saving intermediate files, and producing - a summary/report of the results. - - Script should be run from the top-level CameraITS directory. - """ - - # Get all the scene0 and scene1 tests, which can be run using the same - # physical setup. - scenes = ["scene0", "scene1"] - tests = [] - for d in scenes: - tests += [(d,s[:-3],os.path.join("tests", d, s)) - for s in os.listdir(os.path.join("tests",d)) - if s[-3:] == ".py"] - tests.sort() - - # Make output directories to hold the generated files. - topdir = tempfile.mkdtemp() - for d in scenes: - os.mkdir(os.path.join(topdir, d)) - print "Saving output files to:", topdir, "\n" - - # Run each test, capturing stdout and stderr. - numpass = 0 - for (scene,testname,testpath) in tests: - cmd = ['python', os.path.join(os.getcwd(),testpath)] + sys.argv[1:] - outdir = os.path.join(topdir,scene) - outpath = os.path.join(outdir,testname+"_stdout.txt") - errpath = os.path.join(outdir,testname+"_stderr.txt") - t0 = time.time() - with open(outpath,"w") as fout, open(errpath,"w") as ferr: - retcode = subprocess.call(cmd,stderr=ferr,stdout=fout,cwd=outdir) - t1 = time.time() - print "%s %s/%s [%.1fs]" % ( - "PASS" if retcode==0 else "FAIL", scene, testname, t1-t0) - if retcode == 0: - numpass += 1 - - print "\n%d / %d tests passed (%.1f%%)" % ( - numpass, len(tests), 100.0*float(numpass)/len(tests)) - -if __name__ == '__main__': - main() - |