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 os.path
     16 
     17 import its.caps
     18 import its.device
     19 import its.image
     20 import its.objects
     21 import matplotlib
     22 from matplotlib import pylab
     23 import numpy as np
     24 
     25 NAME = os.path.basename(__file__).split('.')[0]
     26 LOCKED = 3
     27 LUMA_LOCKED_TOL = 0.05
     28 THRESH_CONVERGE_FOR_EV = 8  # AE must converge within this num
     29 YUV_FULL_SCALE = 255.0
     30 YUV_SATURATION_MIN = 253.0
     31 YUV_SATURATION_TOL = 1.0
     32 
     33 
     34 def main():
     35     """Tests that EV compensation is applied."""
     36 
     37     with its.device.ItsSession() as cam:
     38         props = cam.get_camera_properties()
     39         its.caps.skip_unless(its.caps.ev_compensation(props) and
     40                              its.caps.ae_lock(props))
     41 
     42         debug = its.caps.debug_mode()
     43         largest_yuv = its.objects.get_largest_yuv_format(props)
     44         if debug:
     45             fmt = largest_yuv
     46         else:
     47             match_ar = (largest_yuv['width'], largest_yuv['height'])
     48             fmt = its.objects.get_smallest_yuv_format(props, match_ar=match_ar)
     49 
     50         ev_per_step = its.objects.rational_to_float(
     51             props['android.control.aeCompensationStep'])
     52         steps_per_ev = int(1.0 / ev_per_step)
     53         evs = range(-2 * steps_per_ev, 2 * steps_per_ev + 1, steps_per_ev)
     54         lumas = []
     55         reds = []
     56         greens = []
     57         blues = []
     58 
     59         # Converge 3A, and lock AE once converged. skip AF trigger as
     60         # dark/bright scene could make AF convergence fail and this test
     61         # doesn't care the image sharpness.
     62         cam.do_3a(ev_comp=0, lock_ae=True, do_af=False)
     63 
     64         for ev in evs:
     65             # Capture a single shot with the same EV comp and locked AE.
     66             req = its.objects.auto_capture_request()
     67             req['android.control.aeExposureCompensation'] = ev
     68             req['android.control.aeLock'] = True
     69             caps = cam.do_capture([req]*THRESH_CONVERGE_FOR_EV, fmt)
     70             luma_locked = []
     71             for i, cap in enumerate(caps):
     72                 if cap['metadata']['android.control.aeState'] == LOCKED:
     73                     y = its.image.convert_capture_to_planes(cap)[0]
     74                     tile = its.image.get_image_patch(y, 0.45, 0.45, 0.1, 0.1)
     75                     luma = its.image.compute_image_means(tile)[0]
     76                     luma_locked.append(luma)
     77                     if i == THRESH_CONVERGE_FOR_EV-1:
     78                         lumas.append(luma)
     79                         rgb = its.image.convert_capture_to_rgb_image(cap)
     80                         rgb_tile = its.image.get_image_patch(rgb,
     81                                                              0.45, 0.45,
     82                                                              0.1, 0.1)
     83                         rgb_means = its.image.compute_image_means(rgb_tile)
     84                         reds.append(rgb_means[0])
     85                         greens.append(rgb_means[1])
     86                         blues.append(rgb_means[2])
     87                         print 'lumas in AE locked captures: ', luma_locked
     88                         assert np.isclose(min(luma_locked), max(luma_locked),
     89                                           rtol=LUMA_LOCKED_TOL)
     90             assert caps[THRESH_CONVERGE_FOR_EV-1]['metadata']['android.control.aeState'] == LOCKED
     91 
     92         pylab.plot(evs, lumas, '-ro')
     93         pylab.xlabel('EV Compensation')
     94         pylab.ylabel('Mean Luma (Normalized)')
     95         matplotlib.pyplot.savefig('%s_plot_means.png' % (NAME))
     96 
     97         # Trim extra saturated images
     98         while lumas and lumas[-1] >= YUV_SATURATION_MIN/YUV_FULL_SCALE:
     99             if (np.isclose(reds[-1], greens[-1],
    100                            YUV_SATURATION_TOL/YUV_FULL_SCALE) and
    101                     np.isclose(blues[-1], greens[-1],
    102                                YUV_SATURATION_TOL/YUV_FULL_SCALE)):
    103                 lumas.pop(-1)
    104                 reds.pop(-1)
    105                 greens.pop(-1)
    106                 blues.pop(-1)
    107                 print 'Removed saturated image.'
    108             else:
    109                 break
    110         # Only allow positive EVs to give saturated image
    111         assert len(lumas) > 2
    112         luma_diffs = np.diff(lumas)
    113         min_luma_diffs = min(luma_diffs)
    114         print 'Min of the luma value difference between adjacent ev comp: ',
    115         print min_luma_diffs
    116         # All luma brightness should be increasing with increasing ev comp.
    117         assert min_luma_diffs > 0
    118 
    119 if __name__ == '__main__':
    120     main()
    121