Home | History | Annotate | Download | only in scene2
      1 # Copyright 2018 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 
     22 import matplotlib
     23 from matplotlib import pylab
     24 import numpy as np
     25 
     26 AE_STATE_CONVERGED = 2
     27 CONTROL_AE_STATE_FLASH_REQUIRED = 4
     28 NAME = os.path.basename(__file__).split('.')[0]
     29 NUM_CAPTURE = 30
     30 VALID_STABLE_LUMA_MIN = 0.1
     31 VALID_STABLE_LUMA_MAX = 0.9
     32 
     33 
     34 def is_awb_af_stable(prev_cap, cap):
     35     awb_gains_0 = prev_cap['metadata']['android.colorCorrection.gains']
     36     awb_gains_1 = cap['metadata']['android.colorCorrection.gains']
     37     ccm_0 = prev_cap['metadata']['android.colorCorrection.transform']
     38     ccm_1 = cap['metadata']['android.colorCorrection.transform']
     39     focus_distance_0 = prev_cap['metadata']['android.lens.focusDistance']
     40     focus_distance_1 = cap['metadata']['android.lens.focusDistance']
     41 
     42     return (np.allclose(awb_gains_0, awb_gains_1, rtol=0.01) and
     43             ccm_0 == ccm_1 and
     44             np.isclose(focus_distance_0, focus_distance_1, rtol=0.01))
     45 
     46 
     47 def main():
     48     """Tests PER_FRAME_CONTROL properties for auto capture requests.
     49 
     50     If debug is required, MANUAL_POSTPROCESSING capability is implied
     51     since its.caps.read_3a is valid for test. Debug can performed with
     52     a defined tonemap curve:
     53     req['android.tonemap.mode'] = 0
     54     gamma = sum([[i/63.0,math.pow(i/63.0,1/2.2)] for i in xrange(64)],[])
     55     req['android.tonemap.curve'] = {
     56             'red': gamma, 'green': gamma, 'blue': gamma}
     57     """
     58 
     59     with its.device.ItsSession() as cam:
     60         props = cam.get_camera_properties()
     61         its.caps.skip_unless(its.caps.per_frame_control(props) and
     62                              its.caps.read_3a(props))
     63 
     64         debug = its.caps.debug_mode()
     65         largest_yuv = its.objects.get_largest_yuv_format(props)
     66         if debug:
     67             fmt = largest_yuv
     68         else:
     69             match_ar = (largest_yuv['width'], largest_yuv['height'])
     70             fmt = its.objects.get_smallest_yuv_format(props, match_ar=match_ar)
     71 
     72         req = its.objects.auto_capture_request()
     73         caps = cam.do_capture([req]*NUM_CAPTURE, fmt)
     74 
     75         total_gains = []
     76         lumas = []
     77         ae_states = []
     78         for i, cap in enumerate(caps):
     79             print '=========== frame %d ==========' % i
     80             y = its.image.convert_capture_to_planes(cap)[0]
     81             tile = its.image.get_image_patch(y, 0.45, 0.45, 0.1, 0.1)
     82             luma = its.image.compute_image_means(tile)[0]
     83 
     84             ae_state = cap['metadata']['android.control.aeState']
     85             iso = cap['metadata']['android.sensor.sensitivity']
     86             isp_gain = cap['metadata']['android.control.postRawSensitivityBoost']
     87             exp_time = cap['metadata']['android.sensor.exposureTime']
     88             total_gain = iso*isp_gain/100.0*exp_time/1000000.0
     89             awb_state = cap['metadata']['android.control.awbState']
     90             awb_gains = cap['metadata']['android.colorCorrection.gains']
     91             ccm = cap['metadata']['android.colorCorrection.transform']
     92             focus_distance = cap['metadata']['android.lens.focusDistance']
     93 
     94             # Convert CCM from rational to float, as numpy arrays.
     95             awb_ccm = np.array(its.objects.rational_to_float(ccm)).reshape(3, 3)
     96 
     97             print 'AE: %d ISO: %d ISP_sen: %d exp(ms): %d tot_gain: %f' % (
     98                     ae_state, iso, isp_gain, exp_time, total_gain),
     99             print 'luma: %f' % luma
    100             print 'fd: %f' % focus_distance
    101             print 'AWB: %d, AWB gains: %s\n AWB matrix: %s' % (
    102                     awb_state, str(awb_gains), str(awb_ccm))
    103             print 'Tonemap curve:', cap['metadata']['android.tonemap.curve']
    104 
    105             lumas.append(luma)
    106             total_gains.append(total_gain)
    107             ae_states.append(ae_state)
    108             img = its.image.convert_capture_to_rgb_image(cap)
    109             its.image.write_image(img, '%s_frame_%d.jpg'% (NAME, i))
    110 
    111         norm_gains = [x / max(total_gains) * max(lumas) for x in total_gains]
    112         pylab.plot(range(len(lumas)), lumas, '-g.',
    113                    label='Center patch brightness')
    114         pylab.plot(range(len(norm_gains)), norm_gains, '-r.',
    115                    label='Metadata AE setting product')
    116         pylab.title(NAME)
    117         pylab.xlabel('frame index')
    118         pylab.legend()
    119         matplotlib.pyplot.savefig('%s_plot.png' % (NAME))
    120 
    121         for i in range(1, len(caps)):
    122             if is_awb_af_stable(caps[i-1], caps[i]):
    123                 prev_total_gain = total_gains[i-1]
    124                 total_gain = total_gains[i]
    125                 delta_gain = total_gain - prev_total_gain
    126                 prev_luma = lumas[i-1]
    127                 luma = lumas[i]
    128                 delta_luma = luma - prev_luma
    129                 # luma and total_gain should change in same direction
    130                 msg = 'Frame %d to frame %d:' % (i-1, i)
    131                 msg += ' metadata gain %f->%f (%s), luma %f->%f (%s)' % (
    132                         prev_total_gain, total_gain,
    133                         'increasing' if delta_gain > 0.0 else 'decreasing',
    134                         prev_luma, luma,
    135                         'increasing' if delta_luma > 0.0 else 'decreasing')
    136                 assert delta_gain * delta_luma >= 0.0, msg
    137             else:
    138                 print 'Frame %d->%d AWB/AF changed' % (i-1, i)
    139 
    140         for i in range(len(lumas)):
    141             luma = lumas[i]
    142             ae_state = ae_states[i]
    143             if (ae_state == AE_STATE_CONVERGED or
    144                         ae_state == CONTROL_AE_STATE_FLASH_REQUIRED):
    145                 msg = 'Frame %d AE converged luma %f. valid range: (%f, %f)' % (
    146                         i, luma, VALID_STABLE_LUMA_MIN, VALID_STABLE_LUMA_MAX)
    147                 assert VALID_STABLE_LUMA_MIN < luma < VALID_STABLE_LUMA_MAX, msg
    148 
    149 if __name__ == '__main__':
    150     main()
    151