1# Copyright 2024 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"""Tool to check camera alignment to test chart.""" 15 16import logging 17import os.path 18 19import capture_request_utils 20import image_processing_utils 21import its_base_test 22import its_session_utils 23from mobly import test_runner 24import opencv_processing_utils 25 26_CIRCLE_COLOR = 0 # [0: black, 255: white] 27_CIRCLE_MIN_AREA = 0.01 # 1% of image size 28_FMT = 'JPEG' 29_NAME = os.path.basename(__file__).split('.')[0] 30_SCENE = 'scene4' # Using scene with circle 31 32 33def _circle_and_image_center_offset(cam, props, name_with_log_path): 34 """Find offset between circle center and image center. 35 36 Args: 37 cam: its_session_utils.ItsSession object 38 props: camera properties object 39 name_with_log_path: path to saved data 40 41 Returns: 42 x_offset: circle center's x-position vs. image center 43 y_offset: circle center's y-position vs. image center 44 """ 45 46 # Take a single JPEG capture 47 logging.debug('Using %s for reference', _FMT) 48 fmt = capture_request_utils.get_largest_jpeg_format(props) 49 req = capture_request_utils.auto_capture_request() 50 cap = cam.do_capture(req, fmt) 51 logging.debug('Captured %s %dx%d', _FMT, cap['width'], cap['height']) 52 img = image_processing_utils.convert_capture_to_rgb_image(cap, props) 53 size = (cap['height'], cap['width']) 54 55 # Get image size 56 w = size[1] 57 h = size[0] 58 img_name = f'{name_with_log_path}_{_FMT}_w{w}_h{h}.png' 59 image_processing_utils.write_image(img, img_name, True) 60 61 # Find circle. 62 img *= 255 # cv2 needs images between [0,255] 63 circle = opencv_processing_utils.find_circle( 64 img, img_name, _CIRCLE_MIN_AREA, _CIRCLE_COLOR) 65 opencv_processing_utils.append_circle_center_to_img(circle, img, img_name) 66 67 # Determine final return values. 68 x_offset, y_offset = circle['x_offset'], circle['y_offset'] 69 70 return x_offset, y_offset 71 72 73class CheckAlignmentTest(its_base_test.ItsBaseTest): 74 """Create a single capture that checks for scene center vs. circle center. 75 """ 76 77 def test_check_alignment(self): 78 with its_session_utils.ItsSession( 79 device_id=self.dut.serial, 80 camera_id=self.camera_id) as cam: 81 props = cam.get_camera_properties() 82 props = cam.override_with_hidden_physical_camera_props(props) 83 name_with_log_path = os.path.join(self.log_path, _NAME) 84 logging.info('Starting %s for camera %s', _NAME, cam.get_camera_name()) 85 86 # Load chart for scene 87 its_session_utils.copy_scenes_to_tablet(_SCENE, self.tablet.serial) 88 its_session_utils.load_scene( 89 cam, props, _SCENE, self.tablet, self.chart_distance) 90 91 # Find offset between circle center and image center 92 x_offset, y_offset = _circle_and_image_center_offset( 93 cam, props, name_with_log_path) 94 logging.info('Circle center position wrt to image center: %.3fx%.3f', 95 x_offset, y_offset) 96 97if __name__ == '__main__': 98 test_runner.main() 99 100