CameraITS: Cleaned up and documented script to generate DNG noise model

Bug: 18400529

Change-Id: I749c62c3ffff916d61a2b459959d1f5b5ccf005e
diff --git a/apps/CameraITS/pymodules/its/image.py b/apps/CameraITS/pymodules/its/image.py
index e2d521a..b3bdb65 100644
--- a/apps/CameraITS/pymodules/its/image.py
+++ b/apps/CameraITS/pymodules/its/image.py
@@ -540,9 +540,13 @@
     img = numpy.vstack(chs).T.reshape(h/f,w/f,chans)
     return img
 
-def __measure_color_checker_patch(img, xc,yc, patch_size):
+def __get_color_checker_patch(img, xc,yc, patch_size):
     r = patch_size/2
-    tile = img[yc-r:yc+r+1:, xc-r:xc+r+1:, ::]
+    tile = img[yc-r:yc+r:, xc-r:xc+r:, ::]
+    return tile
+
+def __measure_color_checker_patch(img, xc,yc, patch_size):
+    tile = __get_color_checker_patch(img, xc,yc, patch_size)
     means = tile.mean(1).mean(0)
     return means
 
@@ -570,10 +574,7 @@
         debug_fname_prefix: If not None, the (string) name of a file prefix to
             use to save a number of debug images for visualizing the output of
             this function; can be used to see if the patches are being found
-            successfully. If this argument is provided, then some of the sanity
-            check assertions will be disabled to allow the function to provide
-            useful debugging information, meaning that garbage data may be
-            returned.
+            successfully.
 
     Returns:
         6x4 list of lists of integer (x,y) coords of the center of each patch,
@@ -674,6 +675,7 @@
             patches[yi].append((xc,yc))
 
     # Sanity check: test that the R,G,B,black,white patches are correct.
+    sanity_failed = False
     patch_info = [(2,2,[0]), # Red
                   (2,1,[1]), # Green
                   (2,0,[2]), # Blue
@@ -686,16 +688,19 @@
         means = __measure_color_checker_patch(img, xc,yc, 64)
         if (min([means[i] for i in high_chans]+[1]) < \
                 max([means[i] for i in low_chans]+[0])):
-            print "Color patch sanity check failed: patch", i
-            # If the debug info is requested, then don't assert that the patches
-            # are matched, to allow the caller to see the output.
-            if debug_fname_prefix is None:
-                assert(0)
+            sanity_failed = True
 
     if debug_fname_prefix is not None:
-        for (xc,yc) in sum(patches,[]):
-            img[yc,xc] = 1.0
-        write_image(img, debug_fname_prefix+"_2.jpg")
+        gridimg = numpy.zeros([4*(32+2), 6*(32+2), 3])
+        for yi in range(4):
+            for xi in range(6):
+                xc,yc = patches[yi][xi]
+                tile = __get_color_checker_patch(img, xc,yc, 32)
+                gridimg[yi*(32+2)+1:yi*(32+2)+1+32,
+                        xi*(32+2)+1:xi*(32+2)+1+32, :] = tile
+        write_image(gridimg, debug_fname_prefix+"_2.png")
+
+    assert(not sanity_failed)
 
     return patches
 
diff --git a/apps/CameraITS/tests/dng_noise_model/DngNoiseModel.pdf b/apps/CameraITS/tests/dng_noise_model/DngNoiseModel.pdf
new file mode 100644
index 0000000..4aa4b7f
--- /dev/null
+++ b/apps/CameraITS/tests/dng_noise_model/DngNoiseModel.pdf
Binary files differ
diff --git a/apps/CameraITS/tools/compute_dng_noise_model.py b/apps/CameraITS/tests/dng_noise_model/dng_noise_model.py
similarity index 86%
rename from apps/CameraITS/tools/compute_dng_noise_model.py
rename to apps/CameraITS/tests/dng_noise_model/dng_noise_model.py
index 1b57754..19b6c92 100644
--- a/apps/CameraITS/tools/compute_dng_noise_model.py
+++ b/apps/CameraITS/tests/dng_noise_model/dng_noise_model.py
@@ -50,7 +50,7 @@
         s_e_prod *= 2
 
         # Capture raw frames across the full sensitivity range.
-        NUM_SENS_STEPS = 15
+        NUM_SENS_STEPS = 9
         sens_step = int((sens_max - sens_min - 1) / float(NUM_SENS_STEPS))
         reqs = []
         sens = []
@@ -75,7 +75,7 @@
         patches = [(2*x,2*y) for (x,y) in sum(patches,[])]
 
         lines = []
-        for (s,cap) in zip(sens,caps):
+        for iouter, (s,cap) in enumerate(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.
@@ -117,10 +117,17 @@
             #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))
+            if iouter == 0:
+                pylab.plot(xs, ys, 'r', label="Measured")
+                pylab.plot([0,xs[-1]],[b,m*xs[-1]+b],'b', label="Fit")
+            else:
+                pylab.plot(xs, ys, 'r')
+                pylab.plot([0,xs[-1]],[b,m*xs[-1]+b],'b')
+
+        pylab.xlabel("Mean")
+        pylab.ylabel("Variance")
+        pylab.legend()
+        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)
@@ -132,11 +139,16 @@
         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')
+        fig = matplotlib.pyplot.figure()
+        pylab.plot(gains, [10*o for o in Os], 'r', label="Measured")
         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')
+                [10*mO*gains[0]+10*bO, 10*mO*gains[-1]+10*bO],'r--',label="Fit")
+        pylab.plot(gains, Ss, 'b', label="Measured")
+        pylab.plot([gains[0],gains[-1]], [mS*gains[0]+bS,mS*gains[-1]+bS],'b--',
+                label="Fit")
+        pylab.xlabel("Sensitivity")
+        pylab.ylabel("Model parameter: S (blue), O x10 (red)")
+        pylab.legend()
         matplotlib.pyplot.savefig("%s_plot_S_O.png" % (NAME))
 
         print """