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.image
     16 import its.device
     17 import its.caps
     18 import its.objects
     19 import os.path
     20 from matplotlib import pylab
     21 import matplotlib
     22 import matplotlib.pyplot
     23 import numpy
     24 
     25 #AE must converge within this number of auto requests for EV
     26 THREASH_CONVERGE_FOR_EV = 8
     27 
     28 def main():
     29     """Tests that EV compensation is applied.
     30     """
     31     LOCKED = 3
     32 
     33     NAME = os.path.basename(__file__).split(".")[0]
     34 
     35     MAX_LUMA_DELTA_THRESH = 0.05
     36 
     37     with its.device.ItsSession() as cam:
     38         props = cam.get_camera_properties()
     39         its.caps.skip_unless(its.caps.manual_sensor(props) and
     40                              its.caps.manual_post_proc(props) and
     41                              its.caps.per_frame_control(props) and
     42                              its.caps.ev_compensation(props))
     43 
     44         mono_camera = its.caps.mono_camera(props)
     45         debug = its.caps.debug_mode()
     46         largest_yuv = its.objects.get_largest_yuv_format(props)
     47         if debug:
     48             fmt = largest_yuv
     49         else:
     50             match_ar = (largest_yuv['width'], largest_yuv['height'])
     51             fmt = its.objects.get_smallest_yuv_format(props, match_ar=match_ar)
     52 
     53         ev_compensation_range = props['android.control.aeCompensationRange']
     54         range_min = ev_compensation_range[0]
     55         range_max = ev_compensation_range[1]
     56         ev_per_step = its.objects.rational_to_float(
     57                 props['android.control.aeCompensationStep'])
     58         steps_per_ev = int(round(1.0 / ev_per_step))
     59         ev_steps = range(range_min, range_max + 1, steps_per_ev)
     60         imid = len(ev_steps) / 2
     61         ev_shifts = [pow(2, step * ev_per_step) for step in ev_steps]
     62         lumas = []
     63 
     64         # Converge 3A, and lock AE once converged. skip AF trigger as
     65         # dark/bright scene could make AF convergence fail and this test
     66         # doesn't care the image sharpness.
     67         cam.do_3a(ev_comp=0, lock_ae=True, do_af=False, mono_camera=mono_camera)
     68 
     69         for ev in ev_steps:
     70 
     71             # Capture a single shot with the same EV comp and locked AE.
     72             req = its.objects.auto_capture_request()
     73             req['android.control.aeExposureCompensation'] = ev
     74             req['android.control.aeLock'] = True
     75             # Use linear tone curve to avoid brightness being impacted
     76             # by tone curves.
     77             req['android.tonemap.mode'] = 0
     78             req['android.tonemap.curve'] = {
     79                 'red': [0.0,0.0, 1.0,1.0],
     80                 'green': [0.0,0.0, 1.0,1.0],
     81                 'blue': [0.0,0.0, 1.0,1.0]}
     82             caps = cam.do_capture([req]*THREASH_CONVERGE_FOR_EV, fmt)
     83 
     84             for cap in caps:
     85                 if (cap['metadata']['android.control.aeState'] == LOCKED):
     86                     y = its.image.convert_capture_to_planes(cap)[0]
     87                     tile = its.image.get_image_patch(y, 0.45,0.45,0.1,0.1)
     88                     lumas.append(its.image.compute_image_means(tile)[0])
     89                     break
     90             assert(cap['metadata']['android.control.aeState'] == LOCKED)
     91 
     92         print "ev_step_size_in_stops", ev_per_step
     93         shift_mid = ev_shifts[imid]
     94         luma_normal = lumas[imid] / shift_mid
     95         expected_lumas = [min(1.0, luma_normal * ev_shift) for ev_shift in ev_shifts]
     96 
     97         pylab.plot(ev_steps, lumas, 'r')
     98         pylab.plot(ev_steps, expected_lumas, 'b')
     99         matplotlib.pyplot.savefig("%s_plot_means.png" % (NAME))
    100 
    101         luma_diffs = [expected_lumas[i] - lumas[i] for i in range(len(ev_steps))]
    102         max_diff = max(abs(i) for i in luma_diffs)
    103         avg_diff = abs(numpy.array(luma_diffs)).mean()
    104         print "Max delta between modeled and measured lumas:", max_diff
    105         print "Avg delta between modeled and measured lumas:", avg_diff
    106         assert(max_diff < MAX_LUMA_DELTA_THRESH)
    107 
    108 if __name__ == '__main__':
    109     main()
    110