Clemenz Portmann | 90f279d | 2020-01-24 09:17:29 -0800 | [diff] [blame] | 1 | # Copyright 2020 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. |
Clemenz Portmann | fc0ed29 | 2021-03-19 16:17:03 -0700 | [diff] [blame^] | 14 | """Verifies 3A converges in CONTINUOUS_PICTURE mode.""" |
Clemenz Portmann | 90f279d | 2020-01-24 09:17:29 -0800 | [diff] [blame] | 15 | |
Clemenz Portmann | 6816c02 | 2021-03-01 13:00:12 -0800 | [diff] [blame] | 16 | |
| 17 | import logging |
Clemenz Portmann | 90f279d | 2020-01-24 09:17:29 -0800 | [diff] [blame] | 18 | import os.path |
Clemenz Portmann | 90f279d | 2020-01-24 09:17:29 -0800 | [diff] [blame] | 19 | |
Clemenz Portmann | 6816c02 | 2021-03-01 13:00:12 -0800 | [diff] [blame] | 20 | from mobly import test_runner |
| 21 | |
| 22 | import its_base_test |
| 23 | import camera_properties_utils |
| 24 | import capture_request_utils |
| 25 | import image_processing_utils |
| 26 | import its_session_utils |
| 27 | |
| 28 | _CONTINUOUS_PICTURE_MODE = 4 |
| 29 | _CONVERGED_3A = (2, 2, 2) # (AE, AF, AWB) |
| 30 | _M_TO_CM = 100 |
| 31 | _NAME = os.path.splitext(os.path.basename(__file__))[0] |
| 32 | _NS_TO_MS = 1E-6 |
| 33 | _NUM_FRAMES = 50 |
| 34 | _PATCH_H = 0.1 # center 10% |
| 35 | _PATCH_W = 0.1 |
| 36 | _PATCH_X = 0.5 - _PATCH_W/2 |
| 37 | _PATCH_Y = 0.5 - _PATCH_H/2 |
| 38 | _RGB_G_CH = 1 |
| 39 | _VGA_W, _VGA_H = 640, 480 |
Clemenz Portmann | 90f279d | 2020-01-24 09:17:29 -0800 | [diff] [blame] | 40 | |
| 41 | |
Clemenz Portmann | 6816c02 | 2021-03-01 13:00:12 -0800 | [diff] [blame] | 42 | def _capture_frames(cam, log_path, debug): |
| 43 | """Captures frames, logs info, and creates cap_3a_state_list. |
Clemenz Portmann | 90f279d | 2020-01-24 09:17:29 -0800 | [diff] [blame] | 44 | |
Clemenz Portmann | 6816c02 | 2021-03-01 13:00:12 -0800 | [diff] [blame] | 45 | Args: |
| 46 | cam: a camera capture object. |
| 47 | log_path: str to identify saved image location. |
| 48 | debug: bool for debugging info. |
| 49 | Returns: |
| 50 | cap_3a_state_list: list of 3a states [AE, AF, AWB] during captures. |
| 51 | """ |
| 52 | cap_3a_state_list = [] |
| 53 | req = capture_request_utils.auto_capture_request() |
| 54 | req['android.control.afMode'] = _CONTINUOUS_PICTURE_MODE |
| 55 | fmt = {'format': 'yuv', 'width': _VGA_W, 'height': _VGA_H} |
| 56 | caps = cam.do_capture([req]*_NUM_FRAMES, fmt) |
| 57 | |
| 58 | # Extract frame metadata and frame. |
| 59 | for i, cap in enumerate(caps): |
| 60 | md = cap['metadata'] |
| 61 | exp = md['android.sensor.exposureTime'] |
| 62 | iso = md['android.sensor.sensitivity'] |
| 63 | fd = md['android.lens.focalLength'] |
| 64 | ae_state = md['android.control.aeState'] |
| 65 | af_state = md['android.control.afState'] |
| 66 | awb_state = md['android.control.awbState'] |
| 67 | fd_str = 'infinity' |
| 68 | if fd != 0.0: |
| 69 | fd_str = '%.2fcm' % (_M_TO_CM/fd) |
| 70 | img = image_processing_utils.convert_capture_to_rgb_image(cap) |
| 71 | patch = image_processing_utils.get_image_patch( |
| 72 | img, _PATCH_X, _PATCH_Y, _PATCH_W, _PATCH_H) |
| 73 | green_mean = image_processing_utils.compute_image_means(patch)[_RGB_G_CH] |
| 74 | logging.debug( |
| 75 | '%d, iso: %d, exp: %.2fms, fd: %s, avg: %.3f, [ae,af,awb]' |
| 76 | ': [%d,%d,%d]', i, iso, exp * _NS_TO_MS, fd_str, green_mean, ae_state, |
| 77 | af_state, awb_state) |
| 78 | cap_3a_state_list.append([ae_state, af_state, awb_state]) |
| 79 | if debug: |
| 80 | image_processing_utils.write_image( |
| 81 | img, '%s_%d.jpg' % (os.path.join(log_path, _NAME), i)) |
| 82 | return cap_3a_state_list |
Clemenz Portmann | 90f279d | 2020-01-24 09:17:29 -0800 | [diff] [blame] | 83 | |
| 84 | |
Clemenz Portmann | 6816c02 | 2021-03-01 13:00:12 -0800 | [diff] [blame] | 85 | class ContinuousPictureTest(its_base_test.ItsBaseTest): |
| 86 | """Test 3A converges in CONTINUOUS_PICTURE mode. |
Clemenz Portmann | 90f279d | 2020-01-24 09:17:29 -0800 | [diff] [blame] | 87 | |
Clemenz Portmann | 6816c02 | 2021-03-01 13:00:12 -0800 | [diff] [blame] | 88 | Sets camera into CONTINUOUS_PICTURE mode and does NUM_FRAMES capture. |
| 89 | By the end of NUM_FRAMES capture, 3A should be in converged state. |
| 90 | Converged state is [2, 2, 2] for [AE, AF, AWB] |
Clemenz Portmann | 90f279d | 2020-01-24 09:17:29 -0800 | [diff] [blame] | 91 | |
Clemenz Portmann | 6816c02 | 2021-03-01 13:00:12 -0800 | [diff] [blame] | 92 | State information: |
| 93 | AE_STATES: {0: INACTIVE, 1: SEARCHING, 2: CONVERGED, 3: LOCKED, |
| 94 | 4: FLASH_REQ, 5: PRECAPTURE} |
| 95 | AF_STATES: {0: INACTIVE, 1: PASSIVE_SCAN, 2: PASSIVE_FOCUSED, |
| 96 | 3: ACTIVE_SCAN, 4: FOCUS_LOCKED, 5: NOT_FOCUSED_LOCKED, |
| 97 | 6: PASSIVE_UNFOCUSED} |
| 98 | AWB_STATES: {0: INACTIVE, 1: SEARCHING, 2: CONVERGED, 3: LOCKED} |
| 99 | """ |
Clemenz Portmann | 90f279d | 2020-01-24 09:17:29 -0800 | [diff] [blame] | 100 | |
Clemenz Portmann | 6816c02 | 2021-03-01 13:00:12 -0800 | [diff] [blame] | 101 | def test_continuous_picture(self): |
| 102 | logging.debug('Starting %s', _NAME) |
| 103 | with its_session_utils.ItsSession( |
| 104 | device_id=self.dut.serial, |
| 105 | camera_id=self.camera_id, |
| 106 | hidden_physical_id=self.hidden_physical_id) as cam: |
| 107 | props = cam.get_camera_properties() |
| 108 | props = cam.override_with_hidden_physical_camera_props(props) |
| 109 | log_path = self.log_path |
| 110 | debug = self.debug_mode |
Clemenz Portmann | 90f279d | 2020-01-24 09:17:29 -0800 | [diff] [blame] | 111 | |
Clemenz Portmann | 6816c02 | 2021-03-01 13:00:12 -0800 | [diff] [blame] | 112 | # Check SKIP conditions. |
| 113 | camera_properties_utils.skip_unless( |
| 114 | camera_properties_utils.continuous_picture(props) and |
| 115 | camera_properties_utils.read_3a(props)) |
| 116 | |
| 117 | # Load chart for scene. |
| 118 | its_session_utils.load_scene( |
| 119 | cam, props, self.scene, self.tablet, self.chart_distance) |
| 120 | |
| 121 | # Do 3A up front. |
| 122 | cam.do_3a() |
| 123 | |
| 124 | # Ensure 3A settles in CONTINUOUS_PICTURE mode with no scene change. |
| 125 | cap_3a_state_list = _capture_frames(cam, log_path, debug) |
| 126 | final_3a = cap_3a_state_list[_NUM_FRAMES-1] |
| 127 | if final_3a != list(_CONVERGED_3A): |
| 128 | raise AssertionError( |
| 129 | f'Last frame [AE,AF,AWB]: {final_3a}. CONVERGED: {_CONVERGED_3A}.') |
Clemenz Portmann | 90f279d | 2020-01-24 09:17:29 -0800 | [diff] [blame] | 130 | |
| 131 | if __name__ == '__main__': |
Clemenz Portmann | 6816c02 | 2021-03-01 13:00:12 -0800 | [diff] [blame] | 132 | test_runner.main() |
| 133 | |