diff options
Diffstat (limited to 'apps/CameraITS/tests/scene2_a/test_auto_flash.py')
-rw-r--r-- | apps/CameraITS/tests/scene2_a/test_auto_flash.py | 197 |
1 files changed, 74 insertions, 123 deletions
diff --git a/apps/CameraITS/tests/scene2_a/test_auto_flash.py b/apps/CameraITS/tests/scene2_a/test_auto_flash.py index c00cd5c358c..f1b879bc1f6 100644 --- a/apps/CameraITS/tests/scene2_a/test_auto_flash.py +++ b/apps/CameraITS/tests/scene2_a/test_auto_flash.py @@ -1,4 +1,4 @@ -# Copyright 2022 The Android Open Source Project +# Copyright 2013 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -11,30 +11,27 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""Verifies that flash is fired when lighting conditions are dark.""" +"""Verifies android.flash.mode parameters is applied when set.""" import logging import os.path +from mobly import test_runner +import its_base_test import camera_properties_utils import capture_request_utils +import lighting_control_utils import image_processing_utils -import its_base_test import its_session_utils -import lighting_control_utils -from mobly import test_runner AE_MODES = {0: 'OFF', 1: 'ON', 2: 'ON_AUTO_FLASH', 3: 'ON_ALWAYS_FLASH', 4: 'ON_AUTO_FLASH_REDEYE', 5: 'ON_EXTERNAL_FLASH'} AE_STATES = {0: 'INACTIVE', 1: 'SEARCHING', 2: 'CONVERGED', 3: 'LOCKED', 4: 'FLASH_REQUIRED', 5: 'PRECAPTURE'} -FLASH_STATES = {0: 'FLASH_STATE_UNAVAILABLE', 1: 'FLASH_STATE_CHARGING', - 2: 'FLASH_STATE_READY', 3: 'FLASH_STATE_FIRED', - 4: 'FLASH_STATE_PARTIAL'} -_GRAD_DELTA_ATOL = 15 # gradiant for tablets as screen aborbs energy -_MEAN_DELTA_ATOL = 15 # mean used for reflective charts - +_GRAD_DELTA_ATOL = 50 # gradiant for tablets as screen aborbs energy +_MEAN_DELTA_ATOL = 50 # mean used for reflective charts +_NUM_FRAMES = 8 _PATCH_H = 0.25 # center 25% _PATCH_W = 0.25 _PATCH_X = 0.5 - _PATCH_W/2 @@ -43,60 +40,27 @@ _TEST_NAME = os.path.splitext(os.path.basename(__file__))[0] VGA_W, VGA_H = 640, 480 _CAPTURE_INTENT_STILL_CAPTURE = 2 _AE_MODE_ON_AUTO_FLASH = 2 -_CAPTURE_INTENT_PREVIEW = 1 -_CAPTURE_INTENT_STILL_CAPTURE = 2 -_AE_PRECAPTURE_TRIGGER_START = 1 -_AE_PRECAPTURE_TRIGGER_IDLE = 0 - - -def turn_off_tablet(tablet_device): - output = tablet_device.adb.shell('dumpsys display | grep mScreenState') - output_list = str(output.decode('utf-8')).strip().split(' ') - for val in output_list: - if 'ON' in val: - tablet_device.adb.shell(['input', 'keyevent', 'KEYCODE_POWER']) - - -def take_captures_with_flash(cam, fmt): - # Run precapture sequence by setting the aePrecapture trigger to - # START and capture intent set to Preview. - preview_req_start = capture_request_utils.auto_capture_request() - preview_req_start[ - 'android.control.aeMode'] = _AE_MODE_ON_AUTO_FLASH - preview_req_start[ - 'android.control.captureIntent'] = _CAPTURE_INTENT_PREVIEW - preview_req_start[ - 'android.control.aePrecaptureTrigger'] = _AE_PRECAPTURE_TRIGGER_START - # Repeat preview requests with aePrecapture set to IDLE - # until AE is converged. - preview_req_idle = capture_request_utils.auto_capture_request() - preview_req_idle[ - 'android.control.aeMode'] = _AE_MODE_ON_AUTO_FLASH - preview_req_idle[ - 'android.control.captureIntent'] = _CAPTURE_INTENT_PREVIEW - preview_req_idle[ - 'android.control.aePrecaptureTrigger'] = _AE_PRECAPTURE_TRIGGER_IDLE - # Single still capture request. - still_capture_req = capture_request_utils.auto_capture_request() - still_capture_req[ - 'android.control.aeMode'] = _AE_MODE_ON_AUTO_FLASH - still_capture_req[ - 'android.control.captureIntent'] = _CAPTURE_INTENT_STILL_CAPTURE - still_capture_req[ - 'android.control.aePrecaptureTrigger'] = _AE_PRECAPTURE_TRIGGER_IDLE - cap = cam.do_capture_with_flash(preview_req_start, - preview_req_idle, - still_capture_req, fmt) - return cap + + +def take_captures(cam, auto_flash=False): + req = capture_request_utils.auto_capture_request() + req['android.control.captureIntent'] = _CAPTURE_INTENT_STILL_CAPTURE + if auto_flash: + req['android.control.aeMode'] = _AE_MODE_ON_AUTO_FLASH + fmt = {'format': 'yuv', 'width': VGA_W, 'height': VGA_H} + captures = [] + for _ in range(_NUM_FRAMES): + one_capture = cam.do_capture(req, fmt) + captures.append(one_capture) + return captures class AutoFlashTest(its_base_test.ItsBaseTest): - """Test that flash is fired when lighting conditions are dark.""" + """Test that the android.flash.mode parameter is applied.""" def test_auto_flash(self): logging.debug('AE_MODES: %s', str(AE_MODES)) logging.debug('AE_STATES: %s', str(AE_STATES)) - logging.debug('FLASH_STATES: %s', str(FLASH_STATES)) with its_session_utils.ItsSession( device_id=self.dut.serial, @@ -107,10 +71,10 @@ class AutoFlashTest(its_base_test.ItsBaseTest): test_name = os.path.join(self.log_path, _TEST_NAME) # check SKIP conditions - vendor_api_level = its_session_utils.get_vendor_api_level(self.dut.serial) + first_api_level = its_session_utils.get_first_api_level(self.dut.serial) camera_properties_utils.skip_unless( camera_properties_utils.flash(props) and - vendor_api_level >= its_session_utils.ANDROID13_API_LEVEL) + first_api_level >= its_session_utils.ANDROID13_API_LEVEL) # establish connection with lighting controller arduino_serial_port = lighting_control_utils.lighting_control( @@ -122,22 +86,23 @@ class AutoFlashTest(its_base_test.ItsBaseTest): # turn OFF tablet to darken scene if self.tablet: - turn_off_tablet(self.tablet) - fmt_name = 'jpeg' - fmt = {'format': fmt_name} - logging.debug('Testing %s format.', fmt_name) + output = self.tablet.adb.shell('dumpsys display | grep mScreenState') + output_list = str(output.decode('utf-8')).strip().split(' ') + for val in output_list: + if 'ON' in val: + self.tablet.adb.shell(['input', 'keyevent', 'KEYCODE_POWER']) + no_flash_exp_x_iso = 0 no_flash_mean = 0 no_flash_grad = 0 flash_exp_x_iso = [] + flash_means = [] + flash_grads = [] - # take capture with no flash as baseline - logging.debug('Taking reference frame with no flash.') + # take captures with no flash as baseline: use last frame + logging.debug('Taking reference frame(s) with no flash.') cam.do_3a(do_af=False) - no_flash_req = capture_request_utils.auto_capture_request() - no_flash_req[ - 'android.control.captureIntent'] = _CAPTURE_INTENT_STILL_CAPTURE - cap = cam.do_capture(no_flash_req, fmt) + cap = take_captures(cam)[_NUM_FRAMES-1] metadata = cap['metadata'] exp = int(metadata['android.sensor.exposureTime']) iso = int(metadata['android.sensor.sensitivity']) @@ -155,79 +120,65 @@ class AutoFlashTest(its_base_test.ItsBaseTest): patch)[0]*255 no_flash_grad = image_processing_utils.compute_image_max_gradients( patch)[0]*255 - image_processing_utils.write_image( - y, f'{test_name}_{fmt_name}_no_flash_Y.jpg') + image_processing_utils.write_image(y, f'{test_name}_no_flash_Y.jpg') # log results logging.debug('No flash exposure X ISO %d', no_flash_exp_x_iso) logging.debug('No flash Y grad: %.4f', no_flash_grad) logging.debug('No flash Y mean: %.4f', no_flash_mean) - # take capture with auto flash enabled - logging.debug('Taking capture with auto flash enabled.') - flash_fired = False - - cap = take_captures_with_flash(cam, fmt) - y, _, _ = image_processing_utils.convert_capture_to_planes( - cap, props) - # Save captured image - image_processing_utils.write_image(y, - f'{test_name}_{fmt_name}_flash_Y.jpg') - # evaluate captured image - metadata = cap['metadata'] - exp = int(metadata['android.sensor.exposureTime']) - iso = int(metadata['android.sensor.sensitivity']) - logging.debug('cap ISO: %d, exp: %d ns', iso, exp) - logging.debug('AE_MODE (cap): %s', - AE_MODES[metadata['android.control.aeMode']]) - ae_state = AE_STATES[metadata['android.control.aeState']] - logging.debug('AE_STATE (cap): %s', ae_state) - flash_state = FLASH_STATES[metadata['android.flash.state']] - logging.debug('FLASH_STATE: %s', flash_state) - # FLASH_REQUIRED and FLASH_FIRED - if ae_state == 'FLASH_REQUIRED' and flash_state == 'FLASH_STATE_FIRED': - logging.debug('Flash fired') - flash_fired = True - flash_exp_x_iso = exp*iso + # take captures with auto flash enabled + logging.debug('Taking frames with auto flash enabled.') + cam.do_3a(do_af=False, auto_flash=True) + caps = take_captures(cam, auto_flash=True) + + # evaluate captured images + for i in range(_NUM_FRAMES): + logging.debug('frame # %d', i) + metadata = caps[i]['metadata'] + exp = int(metadata['android.sensor.exposureTime']) + iso = int(metadata['android.sensor.sensitivity']) + logging.debug('ISO: %d, exp: %d ns', iso, exp) + logging.debug('AE_MODE (cap): %s', + AE_MODES[metadata['android.control.aeMode']]) + ae_state = AE_STATES[metadata['android.control.aeState']] + logging.debug('AE_STATE (cap): %s', ae_state) + flash_exp_x_iso.append(exp*iso) y, _, _ = image_processing_utils.convert_capture_to_planes( - cap, props) + caps[i], props) patch = image_processing_utils.get_image_patch( y, _PATCH_X, _PATCH_Y, _PATCH_W, _PATCH_H) - flash_mean = image_processing_utils.compute_image_means( - patch)[0]*255 - flash_grad = image_processing_utils.compute_image_max_gradients( - patch)[0]*255 + flash_means.append( + image_processing_utils.compute_image_means(patch)[0]*255) + flash_grads.append( + image_processing_utils.compute_image_max_gradients(patch)[0]*255) - if not flash_fired: - raise AssertionError('Flash was not fired.') + image_processing_utils.write_image( + y, f'{test_name}_auto_flash_Y_{i}.jpg') + + if i == 0: + if ae_state != AE_STATES[4]: # FLASH_REQUIRED + raise AssertionError('Scene not dark enough to trigger auto-flash. ' + 'Check scene.') # log results - logging.debug('Flash exposure X ISO %d', flash_exp_x_iso) - logging.debug('Flash frames Y grad: %.4f', flash_grad) - logging.debug('Flash frames Y mean: %.4f', flash_mean) + logging.debug('Flash exposure X ISOs %s', str(flash_exp_x_iso)) + logging.debug('Flash frames Y grads: %s', str(flash_grads)) + logging.debug('Flash frames Y means: %s', str(flash_means)) + + # turn lights back ON + lighting_control_utils.set_lighting_state( + arduino_serial_port, self.lighting_ch, 'ON') # assert correct behavior - grad_delta = flash_grad - no_flash_grad - mean_delta = flash_mean - no_flash_mean + grad_delta = max(flash_grads) - no_flash_grad + mean_delta = max(flash_means) - no_flash_mean if not (grad_delta > _GRAD_DELTA_ATOL or mean_delta > _MEAN_DELTA_ATOL): raise AssertionError( f'grad FLASH-OFF: {grad_delta:.3f}, ATOL: {_GRAD_DELTA_ATOL}, ' f'mean FLASH-OFF: {mean_delta:.3f}, ATOL: {_MEAN_DELTA_ATOL}') - # Ensure that the flash is turned OFF after flash was fired. - req = capture_request_utils.auto_capture_request() - req['android.control.captureIntent'] = _CAPTURE_INTENT_STILL_CAPTURE - cap = cam.do_capture(req, fmt) - flash_state_after = FLASH_STATES[cap['metadata']['android.flash.state']] - logging.debug('FLASH_STATE after flash fired: %s', flash_state_after) - if flash_state_after != 'FLASH_STATE_READY': - raise AssertionError('Flash should turn OFF after it was fired.') - - # turn lights back ON - lighting_control_utils.set_lighting_state( - arduino_serial_port, self.lighting_ch, 'ON') - if __name__ == '__main__': test_runner.main() |