• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2017 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"""Verifies AE and AF can run independently."""
15
16
17import logging
18import math
19import os.path
20from mobly import test_runner
21import numpy as np
22
23import its_base_test
24import camera_properties_utils
25import error_util
26import its_session_utils
27
28_AWB_GAINS_LENGTH = 4
29_AWB_XFORM_LENGTH = 9
30_G_CHANNEL = 2
31_G_GAIN = 1.0
32_G_GAIN_TOL = 0.05
33_NAME = os.path.splitext(os.path.basename(__file__))[0]
34_THREE_A_STATES = {'AE': (True, False, True),
35                   'AF': (False, True, True),
36                   'FULL_3A': (True, True, True)}  # note no AWB solo
37
38
39class SingleATest(its_base_test.ItsBaseTest):
40  """Test basic camera 3A behavior with AE and AF run individually.
41
42  To pass, 3A must converge. Check that returned 3A values are valid.
43  """
44
45  def test_ae_af(self):
46    logging.debug('Starting %s', _NAME)
47    with its_session_utils.ItsSession(
48        device_id=self.dut.serial,
49        camera_id=self.camera_id,
50        hidden_physical_id=self.hidden_physical_id) as cam:
51      props = cam.get_camera_properties()
52      props = cam.override_with_hidden_physical_camera_props(props)
53      camera_properties_utils.skip_unless(
54          camera_properties_utils.read_3a(props))
55      mono_camera = camera_properties_utils.mono_camera(props)
56
57      # Load chart for scene
58      its_session_utils.load_scene(
59          cam, props, self.scene, self.tablet, self.chart_distance)
60
61      # Do AE/AF/3A and evaluate outputs
62      for k, three_a_req in sorted(_THREE_A_STATES.items()):
63        logging.debug('Trying %s', k)
64        try:
65          s, e, awb_gains, awb_xform, fd = cam.do_3a(get_results=True,
66                                                     do_ae=three_a_req[0],
67                                                     do_af=three_a_req[1],
68                                                     do_awb=three_a_req[2],
69                                                     mono_camera=mono_camera)
70
71        except error_util.CameraItsError as e_util:
72          raise AssertionError(f'{k} did not converge.') from e_util
73
74        logging.debug('AWB gains: %s, xform: %s', str(awb_gains),
75                      str(awb_xform))
76        if three_a_req[0]:  # can report None for AF only
77          if not e:
78            raise AssertionError('No valid exposure time returned for AE.')
79          if not s:
80            raise AssertionError('No valid sensitivity returned for AE.')
81          logging.debug('AE sensitivity: %d, exposure: %dns', s, e)
82        else:
83          logging.debug('AE sensitivity: None, exposure: None')
84        if three_a_req[1]:  # fd can report None for AE only
85          logging.debug('AF fd: %.3f', fd)
86        else:
87          logging.debug('AF fd: None')
88        # check AWB values
89        if len(awb_gains) != _AWB_GAINS_LENGTH:
90          raise AssertionError(f'Problem with AWB gains: {awb_gains}')
91        for g in awb_gains:
92          if np.isnan(g):
93            raise AssertionError('Gain in AWB is NaN.')
94        if len(awb_xform) != _AWB_XFORM_LENGTH:
95          raise AssertionError(f'Problem with AWB transform: {awb_xform}')
96        for x in awb_xform:
97          if np.isnan(x):
98            raise AssertionError('Value in AWB transform is NaN.')
99        if not math.isclose(
100            awb_gains[_G_CHANNEL], _G_GAIN, rel_tol=_G_GAIN_TOL):
101          raise AssertionError(
102              f'AWB G channel mismatch. AWB(G): {awb_gains[_G_CHANNEL]}, '
103              f'REF: {_G_GAIN}, TOL: {_G_GAIN_TOL}')
104
105        # check AE values
106        if k == 'full_3a' or k == 'ae':
107          if s < min(props['android.sensor.info.sensitivityRange']):
108            raise AssertionError(f'ISO is < minimum! ISO: {s}')
109          if e < min(props['android.sensor.info.exposureTimeRange']):
110            raise AssertionError(f'Exposure is < minimum! exp: {e}')
111
112        # check AF values
113        if k == 'full_3a' or k == 'af':
114          if fd < 0:
115            raise AssertionError(f'Focal distance is < 0! fd: {fd}')
116
117if __name__ == '__main__':
118  test_runner.main()
119
120