1# Copyright 2023 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 landscape to portrait override works as intended.""" 15 16 17import logging 18import os 19 20from mobly import test_runner 21 22import its_base_test 23import camera_properties_utils 24import its_session_utils 25import opencv_processing_utils 26 27 28_NAME = os.path.splitext(os.path.basename(__file__))[0] 29_OPT_VAL_THRESHOLD = 0.5 30_ENABLED = 'enabled' 31_DISABLED = 'disabled' 32 33 34def _get_true_sensor_orientation(cam, camera_id): 35 """Returns a camera's properties and its true sensor orientation. 36 37 Args: 38 cam: The camera object 39 camera_id: The id of the camera 40 41 Returns: 42 Pair of camera properties and sensor orientation. 43 """ 44 props = cam.get_camera_properties_by_id(camera_id, 45 override_to_portrait=False) 46 props = cam.override_with_hidden_physical_camera_props(props) 47 sensor_orientation = camera_properties_utils.sensor_orientation(props) 48 return (props, sensor_orientation) 49 50 51def _create_image_folder(log_path, suffix): 52 """Creates a new folder for storing debugging images and returns its path. 53 54 Args: 55 log_path: The root log path for LandscapeToPortraitTest 56 suffix: The suffix string for the image folder ("enabled" or "disabled") 57 58 Returns: 59 The newly created log path string, a subfolder of LandscapeToPortraitTest 60 """ 61 image_path = os.path.join(log_path, f'test_landscape_to_portrait_{suffix}') 62 os.mkdir(image_path) 63 return image_path 64 65 66def _verify_opt_val(chart): 67 """Checks that the opt_val for template matching is sufficient to pass. 68 69 Args: 70 chart: The chart for the test 71 """ 72 if chart.opt_val is None: 73 raise AssertionError('Unable to find a template match!') 74 elif chart.opt_val < _OPT_VAL_THRESHOLD: 75 raise AssertionError('Poor template match (opt val: ' 76 f'{chart.opt_val:.3f} thresh: {_OPT_VAL_THRESHOLD}' 77 '). Check jpeg output.') 78 79 80class LandscapeToPortraitTest(its_base_test.ItsBaseTest): 81 """Test the landscape to portrait override. 82 83 Note the test does not require a specific target but does perform 84 both automatic and manual captures so it requires a fixed scene 85 where 3A can converge. 86 """ 87 88 def test_landscape_to_portrait_enabled(self): 89 logging.debug('Starting %s: %s', _NAME, _ENABLED) 90 with its_session_utils.ItsSession( 91 device_id=self.dut.serial, 92 camera_id=self.camera_id, 93 hidden_physical_id=self.hidden_physical_id, 94 override_to_portrait=True) as cam: 95 96 # Read the properties with overrideToPortrait off to find the real sensor 97 # orientation 98 props, sensor_orientation = _get_true_sensor_orientation( 99 cam, self.camera_id) 100 101 # check SKIP conditions 102 camera_properties_utils.skip_unless( 103 cam.is_landscape_to_portrait_enabled() and 104 (sensor_orientation == 0 or sensor_orientation == 180)) 105 106 # Load chart for scene 107 its_session_utils.load_scene( 108 cam, props, self.scene, self.tablet, self.chart_distance) 109 110 # Initialize chart class and locate chart in scene 111 # Make a separate log dir for the chart images, otherwise they'll get 112 # overwritten 113 image_path = _create_image_folder(self.log_path, _ENABLED) 114 chart = opencv_processing_utils.Chart( 115 cam, props, image_path, distance=self.chart_distance, rotation=90) 116 117 _verify_opt_val(chart) 118 119 def test_landscape_to_portrait_disabled(self): 120 logging.debug('Starting %s: %s', _NAME, _DISABLED) 121 with its_session_utils.ItsSession( 122 device_id=self.dut.serial, 123 camera_id=self.camera_id, 124 hidden_physical_id=self.hidden_physical_id) as cam: 125 126 # Read the properties with overrideToPortrait off to find the real sensor 127 # orientation 128 props, sensor_orientation = _get_true_sensor_orientation( 129 cam, self.camera_id) 130 131 # check SKIP conditions. 132 camera_properties_utils.skip_unless( 133 sensor_orientation == 0 or sensor_orientation == 180) 134 135 # Load chart for scene 136 its_session_utils.load_scene( 137 cam, props, self.scene, self.tablet, self.chart_distance) 138 139 # Initialize chart class and locate chart in scene 140 # Make a separate log dir for the chart images, otherwise they'll get 141 # overwritten 142 image_path = _create_image_folder(self.log_path, _DISABLED) 143 chart = opencv_processing_utils.Chart( 144 cam, props, image_path, distance=self.chart_distance) 145 146 _verify_opt_val(chart) 147 148if __name__ == '__main__': 149 test_runner.main() 150