1*b7c941bbSAndroid Build Coastguard Worker# Copyright 2024 The Android Open Source Project 2*b7c941bbSAndroid Build Coastguard Worker# 3*b7c941bbSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*b7c941bbSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*b7c941bbSAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*b7c941bbSAndroid Build Coastguard Worker# 7*b7c941bbSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*b7c941bbSAndroid Build Coastguard Worker# 9*b7c941bbSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*b7c941bbSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*b7c941bbSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*b7c941bbSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*b7c941bbSAndroid Build Coastguard Worker# limitations under the License. 14*b7c941bbSAndroid Build Coastguard Worker"""Tool to check camera alignment to test chart.""" 15*b7c941bbSAndroid Build Coastguard Worker 16*b7c941bbSAndroid Build Coastguard Workerimport logging 17*b7c941bbSAndroid Build Coastguard Workerimport os.path 18*b7c941bbSAndroid Build Coastguard Worker 19*b7c941bbSAndroid Build Coastguard Workerimport capture_request_utils 20*b7c941bbSAndroid Build Coastguard Workerimport image_processing_utils 21*b7c941bbSAndroid Build Coastguard Workerimport its_base_test 22*b7c941bbSAndroid Build Coastguard Workerimport its_session_utils 23*b7c941bbSAndroid Build Coastguard Workerfrom mobly import test_runner 24*b7c941bbSAndroid Build Coastguard Workerimport opencv_processing_utils 25*b7c941bbSAndroid Build Coastguard Worker 26*b7c941bbSAndroid Build Coastguard Worker_CIRCLE_COLOR = 0 # [0: black, 255: white] 27*b7c941bbSAndroid Build Coastguard Worker_CIRCLE_MIN_AREA = 0.01 # 1% of image size 28*b7c941bbSAndroid Build Coastguard Worker_FMT = 'JPEG' 29*b7c941bbSAndroid Build Coastguard Worker_NAME = os.path.basename(__file__).split('.')[0] 30*b7c941bbSAndroid Build Coastguard Worker_SCENE = 'scene4' # Using scene with circle 31*b7c941bbSAndroid Build Coastguard Worker 32*b7c941bbSAndroid Build Coastguard Worker 33*b7c941bbSAndroid Build Coastguard Workerdef _circle_and_image_center_offset(cam, props, name_with_log_path): 34*b7c941bbSAndroid Build Coastguard Worker """Find offset between circle center and image center. 35*b7c941bbSAndroid Build Coastguard Worker 36*b7c941bbSAndroid Build Coastguard Worker Args: 37*b7c941bbSAndroid Build Coastguard Worker cam: its_session_utils.ItsSession object 38*b7c941bbSAndroid Build Coastguard Worker props: camera properties object 39*b7c941bbSAndroid Build Coastguard Worker name_with_log_path: path to saved data 40*b7c941bbSAndroid Build Coastguard Worker 41*b7c941bbSAndroid Build Coastguard Worker Returns: 42*b7c941bbSAndroid Build Coastguard Worker x_offset: circle center's x-position vs. image center 43*b7c941bbSAndroid Build Coastguard Worker y_offset: circle center's y-position vs. image center 44*b7c941bbSAndroid Build Coastguard Worker """ 45*b7c941bbSAndroid Build Coastguard Worker 46*b7c941bbSAndroid Build Coastguard Worker # Take a single JPEG capture 47*b7c941bbSAndroid Build Coastguard Worker logging.debug('Using %s for reference', _FMT) 48*b7c941bbSAndroid Build Coastguard Worker fmt = capture_request_utils.get_largest_format('jpeg', props) 49*b7c941bbSAndroid Build Coastguard Worker req = capture_request_utils.auto_capture_request() 50*b7c941bbSAndroid Build Coastguard Worker cap = cam.do_capture(req, fmt) 51*b7c941bbSAndroid Build Coastguard Worker logging.debug('Captured %s %dx%d', _FMT, cap['width'], cap['height']) 52*b7c941bbSAndroid Build Coastguard Worker img = image_processing_utils.convert_capture_to_rgb_image(cap, props) 53*b7c941bbSAndroid Build Coastguard Worker size = (cap['height'], cap['width']) 54*b7c941bbSAndroid Build Coastguard Worker 55*b7c941bbSAndroid Build Coastguard Worker # Get image size 56*b7c941bbSAndroid Build Coastguard Worker w = size[1] 57*b7c941bbSAndroid Build Coastguard Worker h = size[0] 58*b7c941bbSAndroid Build Coastguard Worker img_name = f'{name_with_log_path}_{_FMT}_w{w}_h{h}.png' 59*b7c941bbSAndroid Build Coastguard Worker image_processing_utils.write_image(img, img_name, True) 60*b7c941bbSAndroid Build Coastguard Worker 61*b7c941bbSAndroid Build Coastguard Worker # Find circle. 62*b7c941bbSAndroid Build Coastguard Worker img *= 255 # cv2 needs images between [0,255] 63*b7c941bbSAndroid Build Coastguard Worker circle = opencv_processing_utils.find_circle( 64*b7c941bbSAndroid Build Coastguard Worker img, img_name, _CIRCLE_MIN_AREA, _CIRCLE_COLOR) 65*b7c941bbSAndroid Build Coastguard Worker opencv_processing_utils.append_circle_center_to_img(circle, img, img_name) 66*b7c941bbSAndroid Build Coastguard Worker 67*b7c941bbSAndroid Build Coastguard Worker # Determine final return values. 68*b7c941bbSAndroid Build Coastguard Worker x_offset, y_offset = circle['x_offset'], circle['y_offset'] 69*b7c941bbSAndroid Build Coastguard Worker 70*b7c941bbSAndroid Build Coastguard Worker return x_offset, y_offset 71*b7c941bbSAndroid Build Coastguard Worker 72*b7c941bbSAndroid Build Coastguard Worker 73*b7c941bbSAndroid Build Coastguard Workerclass CheckAlignmentTest(its_base_test.ItsBaseTest): 74*b7c941bbSAndroid Build Coastguard Worker """Create a single capture that checks for scene center vs. circle center. 75*b7c941bbSAndroid Build Coastguard Worker """ 76*b7c941bbSAndroid Build Coastguard Worker 77*b7c941bbSAndroid Build Coastguard Worker def test_check_alignment(self): 78*b7c941bbSAndroid Build Coastguard Worker with its_session_utils.ItsSession( 79*b7c941bbSAndroid Build Coastguard Worker device_id=self.dut.serial, 80*b7c941bbSAndroid Build Coastguard Worker camera_id=self.camera_id, 81*b7c941bbSAndroid Build Coastguard Worker hidden_physical_id=self.hidden_physical_id) as cam: 82*b7c941bbSAndroid Build Coastguard Worker props = cam.get_camera_properties() 83*b7c941bbSAndroid Build Coastguard Worker props = cam.override_with_hidden_physical_camera_props(props) 84*b7c941bbSAndroid Build Coastguard Worker name_with_log_path = os.path.join(self.log_path, _NAME) 85*b7c941bbSAndroid Build Coastguard Worker logging.info('Starting %s for camera %s', _NAME, cam.get_camera_name()) 86*b7c941bbSAndroid Build Coastguard Worker 87*b7c941bbSAndroid Build Coastguard Worker # Load chart for scene 88*b7c941bbSAndroid Build Coastguard Worker its_session_utils.copy_scenes_to_tablet(_SCENE, self.tablet.serial) 89*b7c941bbSAndroid Build Coastguard Worker its_session_utils.load_scene( 90*b7c941bbSAndroid Build Coastguard Worker cam, props, _SCENE, self.tablet, self.chart_distance) 91*b7c941bbSAndroid Build Coastguard Worker 92*b7c941bbSAndroid Build Coastguard Worker # Find offset between circle center and image center 93*b7c941bbSAndroid Build Coastguard Worker x_offset, y_offset = _circle_and_image_center_offset( 94*b7c941bbSAndroid Build Coastguard Worker cam, props, name_with_log_path) 95*b7c941bbSAndroid Build Coastguard Worker logging.info('Circle center position wrt to image center: %.3fx%.3f', 96*b7c941bbSAndroid Build Coastguard Worker x_offset, y_offset) 97*b7c941bbSAndroid Build Coastguard Worker 98*b7c941bbSAndroid Build Coastguard Workerif __name__ == '__main__': 99*b7c941bbSAndroid Build Coastguard Worker test_runner.main() 100*b7c941bbSAndroid Build Coastguard Worker 101