Home | History | Annotate | Download | only in scene1
      1 # Copyright 2014 The Android Open Source Project
      2 #
      3 # Licensed under the Apache License, Version 2.0 (the "License");
      4 # you may not use this file except in compliance with the License.
      5 # You may obtain a copy of the License at
      6 #
      7 #      http://www.apache.org/licenses/LICENSE-2.0
      8 #
      9 # Unless required by applicable law or agreed to in writing, software
     10 # distributed under the License is distributed on an "AS IS" BASIS,
     11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 # See the License for the specific language governing permissions and
     13 # limitations under the License.
     14 
     15 import its.device
     16 import its.caps
     17 import its.objects
     18 import its.image
     19 import os.path
     20 import pylab
     21 import matplotlib
     22 import matplotlib.pyplot
     23 
     24 def main():
     25     """Verify that the DNG raw model parameters are correct.
     26     """
     27     NAME = os.path.basename(__file__).split(".")[0]
     28 
     29     NUM_STEPS = 4
     30 
     31     # Pass if the difference between expected and computed variances is small,
     32     # defined as being within an absolute variance delta of 0.0005, or within
     33     # 20% of the expected variance, whichever is larger; this is to allow the
     34     # test to pass in the presence of some randomness (since this test is
     35     # measuring noise of a small patch) and some imperfect scene conditions
     36     # (since ITS doesn't require a perfectly uniformly lit scene).
     37     DIFF_THRESH = 0.0005
     38     FRAC_THRESH = 0.2
     39 
     40     with its.device.ItsSession() as cam:
     41 
     42         props = cam.get_camera_properties()
     43         its.caps.skip_unless(its.caps.raw(props) and
     44                              its.caps.raw16(props) and
     45                              its.caps.manual_sensor(props) and
     46                              its.caps.read_3a(props) and
     47                              its.caps.per_frame_control(props))
     48 
     49         white_level = float(props['android.sensor.info.whiteLevel'])
     50         black_levels = props['android.sensor.blackLevelPattern']
     51         cfa_idxs = its.image.get_canonical_cfa_order(props)
     52         black_levels = [black_levels[i] for i in cfa_idxs]
     53 
     54         # Expose for the scene with min sensitivity
     55         sens_min, sens_max = props['android.sensor.info.sensitivityRange']
     56         sens_step = (sens_max - sens_min) / NUM_STEPS
     57         s_ae,e_ae,_,_,_  = cam.do_3a(get_results=True)
     58         s_e_prod = s_ae * e_ae
     59         sensitivities = range(sens_min, sens_max, sens_step)
     60 
     61         var_expected = [[],[],[],[]]
     62         var_measured = [[],[],[],[]]
     63         for sens in sensitivities:
     64 
     65             # Capture a raw frame with the desired sensitivity.
     66             exp = int(s_e_prod / float(sens))
     67             req = its.objects.manual_capture_request(sens, exp)
     68             cap = cam.do_capture(req, cam.CAP_RAW)
     69 
     70             # Test each raw color channel (R, GR, GB, B):
     71             noise_profile = cap["metadata"]["android.sensor.noiseProfile"]
     72             assert((len(noise_profile)) == 4)
     73             for ch in range(4):
     74                 # Get the noise model parameters for this channel of this shot.
     75                 s,o = noise_profile[cfa_idxs[ch]]
     76 
     77                 # Get a center tile of the raw channel, and compute the mean.
     78                 # Use a very small patch to ensure gross uniformity (i.e. so
     79                 # non-uniform lighting or vignetting doesn't affect the variance
     80                 # calculation).
     81                 plane = its.image.convert_capture_to_planes(cap, props)[ch]
     82                 plane = (plane * white_level - black_levels[ch]) / (
     83                         white_level - black_levels[ch])
     84                 tile = its.image.get_image_patch(plane, 0.49,0.49,0.02,0.02)
     85                 mean = tile.mean()
     86 
     87                 # Calculate the expected variance based on the model, and the
     88                 # measured variance from the tile.
     89                 var_measured[ch].append(
     90                         its.image.compute_image_variances(tile)[0])
     91                 var_expected[ch].append(s * mean + o)
     92 
     93     for ch in range(4):
     94         pylab.plot(sensitivities, var_expected[ch], "rgkb"[ch],
     95                 label=["R","GR","GB","B"][ch]+" expected")
     96         pylab.plot(sensitivities, var_measured[ch], "rgkb"[ch]+"--",
     97                 label=["R", "GR", "GB", "B"][ch]+" measured")
     98     pylab.xlabel("Sensitivity")
     99     pylab.ylabel("Center patch variance")
    100     pylab.legend(loc=2)
    101     matplotlib.pyplot.savefig("%s_plot.png" % (NAME))
    102 
    103     # Pass/fail check.
    104     for ch in range(4):
    105         diffs = [var_measured[ch][i] - var_expected[ch][i]
    106                  for i in range(NUM_STEPS)]
    107         print "Diffs (%s):"%(["R","GR","GB","B"][ch]), diffs
    108         for i,diff in enumerate(diffs):
    109             thresh = max(DIFF_THRESH, FRAC_THRESH * var_expected[ch][i])
    110             assert(diff <= thresh)
    111 
    112 if __name__ == '__main__':
    113     main()
    114 
    115