1# Copyright 2015 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"""Validate aspect ratio, crop and FoV vs format.""" 15 16 17import logging 18import math 19import os.path 20from mobly import test_runner 21import numpy as np 22 23import cv2 24import its_base_test 25import camera_properties_utils 26import capture_request_utils 27import image_processing_utils 28import its_session_utils 29import opencv_processing_utils 30 31_ANDROID11_API_LEVEL = 30 32_CIRCLE_COLOR = 0 # [0: black, 255: white]. 33_CIRCLE_MIN_AREA = 0.01 # 1% of image size. 34_FOV_PERCENT_RTOL = 0.15 # Relative tolerance on circle FoV % to expected. 35_LARGE_SIZE = 2000 # Size of a large image (compared against max(w, h)). 36_NAME = os.path.splitext(os.path.basename(__file__))[0] 37_PREVIEW_SIZE = (1920, 1080) 38_THRESH_AR_L = 0.02 # Aspect ratio test threshold of large images. 39_THRESH_AR_S = 0.075 # Aspect ratio test threshold of mini images. 40_THRESH_CROP_L = 0.02 # Crop test threshold of large images. 41_THRESH_CROP_S = 0.075 # Crop test threshold of mini images. 42_THRESH_MIN_PIXEL = 4 # Crop test allowed offset. 43 44# Before API level 30, only resolutions with the following listed aspect ratio 45# are checked. Device launched after API level 30 will need to pass the test 46# for all advertised resolutions. Device launched before API level 30 just 47# needs to pass the test for all resolutions within these aspect ratios. 48_AR_CHECKED_PRE_API_30 = ('4:3', '16:9', '18:9') 49_AR_DIFF_ATOL = 0.01 50 51 52def _check_skip_conditions(first_api_level, props): 53 """Check the skip conditions based on first API level.""" 54 if first_api_level < _ANDROID11_API_LEVEL: # Original constraint. 55 camera_properties_utils.skip_unless(camera_properties_utils.read_3a(props)) 56 else: # Loosen from read_3a to enable LIMITED coverage. 57 camera_properties_utils.skip_unless( 58 camera_properties_utils.ae_lock(props) and 59 camera_properties_utils.awb_lock(props)) 60 61 62def _check_basic_correctness(cap, fmt_iter, w_iter, h_iter): 63 """Check the capture for basic correctness.""" 64 if cap['format'] != fmt_iter: 65 raise AssertionError 66 if cap['width'] != w_iter: 67 raise AssertionError 68 if cap['height'] != h_iter: 69 raise AssertionError 70 71 72def _create_format_list(): 73 """Create format list for multiple capture objects. 74 75 Do multi-capture of 'iter' and 'cmpr'. Iterate through all the available 76 sizes of 'iter', and only use the size specified for 'cmpr'. 77 The 'cmpr' capture is only used so that we have multiple capture target 78 instead of just one, which should help catching more potential issues. 79 The test doesn't look into the output of 'cmpr' images at all. 80 The 'iter_max' or 'cmpr_size' key defines the maximal size being iterated 81 or selected for the 'iter' and 'cmpr' stream accordingly. None means no 82 upper bound is specified. 83 84 Args: 85 None 86 87 Returns: 88 format_list 89 """ 90 format_list = [] 91 format_list.append({'iter': 'yuv', 'iter_max': None, 92 'cmpr': 'yuv', 'cmpr_size': _PREVIEW_SIZE}) 93 format_list.append({'iter': 'yuv', 'iter_max': _PREVIEW_SIZE, 94 'cmpr': 'jpeg', 'cmpr_size': None}) 95 format_list.append({'iter': 'yuv', 'iter_max': _PREVIEW_SIZE, 96 'cmpr': 'raw', 'cmpr_size': None}) 97 format_list.append({'iter': 'jpeg', 'iter_max': None, 98 'cmpr': 'raw', 'cmpr_size': None}) 99 format_list.append({'iter': 'jpeg', 'iter_max': None, 100 'cmpr': 'yuv', 'cmpr_size': _PREVIEW_SIZE}) 101 return format_list 102 103 104def _print_failed_test_results(failed_ar, failed_fov, failed_crop, 105 first_api_level, level_3): 106 """Print failed test results.""" 107 if failed_ar: 108 logging.error('Aspect ratio test summary') 109 logging.error('Images failed in the aspect ratio test:') 110 logging.error('Aspect ratio value: width / height') 111 for fa in failed_ar: 112 logging.error('%s', fa) 113 114 if failed_fov: 115 logging.error('FoV test summary') 116 logging.error('Images failed in the FoV test:') 117 for fov in failed_fov: 118 logging.error('%s', str(fov)) 119 120 if failed_crop: 121 logging.error('Crop test summary') 122 logging.error('Images failed in the crop test:') 123 logging.error('Circle center (H x V) relative to the image center.') 124 for fc in failed_crop: 125 logging.error('%s', fc) 126 if failed_ar: 127 raise RuntimeError 128 if failed_fov: 129 raise RuntimeError 130 if first_api_level > _ANDROID11_API_LEVEL: 131 if failed_crop: # failed_crop = [] if run_crop_test = False. 132 raise RuntimeError 133 else: 134 if failed_crop and level_3: 135 raise RuntimeError 136 137 138def _is_checked_aspect_ratio(first_api_level, w, h): 139 """Determine if format aspect ratio is a checked on based of first_API.""" 140 if first_api_level >= _ANDROID11_API_LEVEL: 141 return True 142 143 for ar_check in _AR_CHECKED_PRE_API_30: 144 match_ar_list = [float(x) for x in ar_check.split(':')] 145 match_ar = match_ar_list[0] / match_ar_list[1] 146 if np.isclose(float(w) / h, match_ar, atol=_AR_DIFF_ATOL): 147 return True 148 149 return False 150 151 152def _calc_expected_circle_image_ratio(ref_fov, img_w, img_h): 153 """Determine the circle image area ratio in percentage for a given image size. 154 155 Cropping happens either horizontally or vertically. In both cases crop results 156 in the visble area reduced by a ratio r (r < 1) and the circle will in turn 157 occupy ref_pct/r (percent) on the target image size. 158 159 Args: 160 ref_fov: dict with {fmt, % coverage, w, h, circle_w, circle_h} 161 img_w: the image width 162 img_h: the image height 163 164 Returns: 165 chk_percent: the expected circle image area ratio in percentage 166 """ 167 ar_ref = ref_fov['w'] / ref_fov['h'] 168 ar_target = img_w / img_h 169 170 r = ar_ref / ar_target 171 if r < 1.0: 172 r = 1.0 / r 173 return ref_fov['percent'] * r 174 175 176def _find_raw_fov_reference(cam, req, props, log_path): 177 """Determine the circle coverage of the image in RAW reference image. 178 179 Captures a full-frame RAW and uses its aspect ratio and circle center 180 location as ground truth for the other jpeg or yuv images. 181 182 The intrinsics and distortion coefficients are meant for full-sized RAW, 183 so convert_capture_to_rgb_image returns a 2x downsampled version, so resizes 184 RGB back to full size. 185 186 If the device supports lens distortion correction, applies the coefficients on 187 the RAW image so it can be compared to YUV/JPEG outputs which are subject 188 to the same correction via ISP. 189 190 Finds circle size and location for reference values in calculations for other 191 formats. 192 193 Args: 194 cam: camera object 195 req: camera request 196 props: camera properties 197 log_path: location to save data 198 199 Returns: 200 ref_fov: dict with [fmt, % coverage, w, h, circle_w, circle_h] 201 cc_ct_gt: circle center position relative to the center of image. 202 aspect_ratio_gt: aspect ratio of the detected circle in float. 203 """ 204 logging.debug('Creating references for fov_coverage from RAW') 205 out_surface = {'format': 'raw'} 206 cap_raw = cam.do_capture(req, out_surface) 207 logging.debug('Captured RAW %dx%d', cap_raw['width'], cap_raw['height']) 208 img_raw = image_processing_utils.convert_capture_to_rgb_image( 209 cap_raw, props=props) 210 # Resize back up to full scale. 211 img_raw = cv2.resize(img_raw, (0, 0), fx=2.0, fy=2.0) 212 213 if (camera_properties_utils.distortion_correction(props) and 214 camera_properties_utils.intrinsic_calibration(props)): 215 logging.debug('Applying intrinsic calibration and distortion params') 216 fd = float(cap_raw['metadata']['android.lens.focalLength']) 217 k = camera_properties_utils.get_intrinsic_calibration(props, True, fd) 218 opencv_dist = camera_properties_utils.get_distortion_matrix(props) 219 img_raw = cv2.undistort(img_raw, k, opencv_dist) 220 221 # Get image size. 222 size_raw = img_raw.shape 223 w_raw = size_raw[1] 224 h_raw = size_raw[0] 225 img_name = '%s_%s_w%d_h%d.png' % ( 226 os.path.join(log_path, _NAME), 'raw', w_raw, h_raw) 227 image_processing_utils.write_image(img_raw, img_name, True) 228 229 # Find circle. 230 img_raw *= 255 # cv2 needs images between [0,255]. 231 circle_raw = opencv_processing_utils.find_circle( 232 img_raw, img_name, _CIRCLE_MIN_AREA, _CIRCLE_COLOR) 233 opencv_processing_utils.append_circle_center_to_img(circle_raw, img_raw, 234 img_name) 235 236 # Determine final return values. 237 aspect_ratio_gt = circle_raw['w'] / circle_raw['h'] 238 cc_ct_gt = {'hori': circle_raw['x_offset'], 'vert': circle_raw['y_offset']} 239 raw_fov_percent = _calc_circle_image_ratio(circle_raw['r'], w_raw, h_raw) 240 ref_fov = {} 241 ref_fov['fmt'] = 'RAW' 242 ref_fov['percent'] = raw_fov_percent 243 ref_fov['w'] = w_raw 244 ref_fov['h'] = h_raw 245 ref_fov['circle_w'] = circle_raw['w'] 246 ref_fov['circle_h'] = circle_raw['h'] 247 logging.debug('Using RAW reference: %s', str(ref_fov)) 248 return ref_fov, cc_ct_gt, aspect_ratio_gt 249 250 251def _find_jpeg_fov_reference(cam, req, props, log_path): 252 """Determine the circle coverage of the image in JPEG reference image. 253 254 Similar to _find_raw_fov_reference() and used when RAW is not available. 255 256 Args: 257 cam: camera object 258 req: camera request 259 props: camera properties 260 log_path: location to save data 261 262 Returns: 263 ref_fov: dict with [fmt, % coverage, w, h, circle_w, circle_h] 264 cc_ct_gt: circle center position relative to the center of image. 265 """ 266 ref_fov = {} 267 fmt = capture_request_utils.get_largest_jpeg_format(props) 268 # Capture and determine circle area in image. 269 cap = cam.do_capture(req, fmt) 270 w = cap['width'] 271 h = cap['height'] 272 273 img = image_processing_utils.convert_capture_to_rgb_image(cap, props) 274 img *= 255 # cv2 works with [0,255] images. 275 logging.debug('Captured JPEG %dx%d', w, h) 276 img_name = '%s_jpeg_w%d_h%d.png' % (os.path.join(log_path, _NAME), w, h) 277 circle_jpg = opencv_processing_utils.find_circle( 278 img, img_name, _CIRCLE_MIN_AREA, _CIRCLE_COLOR) 279 opencv_processing_utils.append_circle_center_to_img(circle_jpg, img, 280 img_name) 281 282 # Determine final return values. 283 cc_ct_gt = {'hori': circle_jpg['x_offset'], 'vert': circle_jpg['y_offset']} 284 fov_percent = _calc_circle_image_ratio(circle_jpg['r'], w, h) 285 ref_fov = {} 286 ref_fov['fmt'] = 'JPEG' 287 ref_fov['percent'] = fov_percent 288 ref_fov['w'] = w 289 ref_fov['h'] = h 290 ref_fov['circle_w'] = circle_jpg['w'] 291 ref_fov['circle_h'] = circle_jpg['h'] 292 logging.debug('Using JPEG reference: %s', str(ref_fov)) 293 return ref_fov, cc_ct_gt 294 295 296def _calc_circle_image_ratio(radius, img_w, img_h): 297 """Calculate the percent of area the input circle covers in input image. 298 299 Args: 300 radius: radius of circle 301 img_w: int width of image 302 img_h: int height of image 303 Returns: 304 fov_percent: float % of image covered by circle 305 """ 306 return 100 * math.pi * math.pow(radius, 2) / (img_w * img_h) 307 308 309def _check_fov(circle, ref_fov, w, h, first_api_level): 310 """Check the FoV for correct size.""" 311 fov_percent = _calc_circle_image_ratio(circle['r'], w, h) 312 chk_percent = _calc_expected_circle_image_ratio(ref_fov, w, h) 313 chk_enabled = _is_checked_aspect_ratio(first_api_level, w, h) 314 if chk_enabled and not np.isclose(fov_percent, chk_percent, 315 rtol=_FOV_PERCENT_RTOL): 316 e_msg = 'FoV %%: %.2f, Ref FoV %%: %.2f, ' % (fov_percent, chk_percent) 317 e_msg += 'TOL=%.f%%, img: %dx%d, ref: %dx%d' % ( 318 _FOV_PERCENT_RTOL*100, w, h, ref_fov['w'], ref_fov['h']) 319 return e_msg 320 321 322def _check_ar(circle, ar_gt, w, h, fmt_iter, fmt_cmpr): 323 """Check the aspect ratio of the circle. 324 325 size is the larger of w or h. 326 if size >= LARGE_SIZE: use THRESH_AR_L 327 elif size == 0 (extreme case): THRESH_AR_S 328 elif 0 < image size < LARGE_SIZE: scale between THRESH_AR_S & THRESH_AR_L 329 330 Args: 331 circle: dict with circle parameters 332 ar_gt: aspect ratio ground truth to compare against 333 w: width of image 334 h: height of image 335 fmt_iter: format of primary capture 336 fmt_cmpr: format of secondary capture 337 338 Returns: 339 error string if check fails 340 """ 341 thresh_ar = max(_THRESH_AR_L, _THRESH_AR_S + 342 max(w, h) * (_THRESH_AR_L-_THRESH_AR_S) / _LARGE_SIZE) 343 ar = circle['w'] / circle['h'] 344 if not np.isclose(ar, ar_gt, atol=thresh_ar): 345 e_msg = (f'{fmt_iter} with {fmt_cmpr} {w}x{h}: aspect_ratio {ar:.3f}, ' 346 f'thresh {thresh_ar:.3f}') 347 return e_msg 348 349 350def _check_crop(circle, cc_gt, w, h, fmt_iter, fmt_cmpr, crop_thresh_factor): 351 """Check cropping. 352 353 if size >= LARGE_SIZE: use thresh_crop_l 354 elif size == 0 (extreme case): thresh_crop_s 355 elif 0 < size < LARGE_SIZE: scale between thresh_crop_s & thresh_crop_l 356 Also allow at least THRESH_MIN_PIXEL to prevent threshold being too tight 357 for very small circle. 358 359 Args: 360 circle: dict of circle values 361 cc_gt: circle center {'hori', 'vert'} ground truth (ref'd to img center) 362 w: width of image 363 h: height of image 364 fmt_iter: format of primary capture 365 fmt_cmpr: format of secondary capture 366 crop_thresh_factor: scaling factor for crop thresholds 367 368 Returns: 369 error string if check fails 370 """ 371 thresh_crop_l = _THRESH_CROP_L * crop_thresh_factor 372 thresh_crop_s = _THRESH_CROP_S * crop_thresh_factor 373 thresh_crop_hori = max( 374 [thresh_crop_l, 375 thresh_crop_s + w * (thresh_crop_l - thresh_crop_s) / _LARGE_SIZE, 376 _THRESH_MIN_PIXEL / circle['w']]) 377 thresh_crop_vert = max( 378 [thresh_crop_l, 379 thresh_crop_s + h * (thresh_crop_l - thresh_crop_s) / _LARGE_SIZE, 380 _THRESH_MIN_PIXEL / circle['h']]) 381 382 if (not np.isclose(circle['x_offset'], cc_gt['hori'], 383 atol=thresh_crop_hori) or 384 not np.isclose(circle['y_offset'], cc_gt['vert'], 385 atol=thresh_crop_vert)): 386 valid_x_range = (cc_gt['hori'] - thresh_crop_hori, 387 cc_gt['hori'] + thresh_crop_hori) 388 valid_y_range = (cc_gt['vert'] - thresh_crop_vert, 389 cc_gt['vert'] + thresh_crop_vert) 390 e_msg = (f'{fmt_iter} with {fmt_cmpr} {w}x{h} ' 391 f"offset X {circle['x_offset']:.3f}, Y {circle['y_offset']:.3f}, " 392 f'valid X range: {valid_x_range[0]:.3f} ~ {valid_x_range[1]:.3f}, ' 393 f'valid Y range: {valid_y_range[0]:.3f} ~ {valid_y_range[1]:.3f}') 394 return e_msg 395 396 397class AspectRatioAndCropTest(its_base_test.ItsBaseTest): 398 """Test aspect ratio/field of view/cropping for each tested fmt combinations. 399 400 This test checks for: 401 1. Aspect ratio: images are not stretched 402 2. Crop: center of images is not shifted 403 3. FOV: images cropped to keep maximum possible FOV with only 1 dimension 404 (horizontal or veritical) cropped. 405 406 Aspect ratio and FOV test runs on level3, full and limited devices. 407 Crop test only runs on level3 and full devices. 408 409 The test chart is a black circle inside a black square. When raw capture is 410 available, set the height vs. width ratio of the circle in the full-frame 411 raw as ground truth. In an ideal setup such ratio should be very close to 412 1.0, but here we just use the value derived from full resolution RAW as 413 ground truth to account for the possibility that the chart is not well 414 positioned to be precisely parallel to image sensor plane. 415 The test then compares the ground truth ratio with the same ratio measured 416 on images captued using different stream combinations of varying formats 417 ('jpeg' and 'yuv') and resolutions. 418 If raw capture is unavailable, a full resolution JPEG image is used to setup 419 ground truth. In this case, the ground truth aspect ratio is defined as 1.0 420 and it is the tester's responsibility to make sure the test chart is 421 properly positioned so the detected circles indeed have aspect ratio close 422 to 1.0 assuming no bugs causing image stretched. 423 424 The aspect ratio test checks the aspect ratio of the detected circle and 425 it will fail if the aspect ratio differs too much from the ground truth 426 aspect ratio mentioned above. 427 428 The FOV test examines the ratio between the detected circle area and the 429 image size. When the aspect ratio of the test image is the same as the 430 ground truth image, the ratio should be very close to the ground truth 431 value. When the aspect ratio is different, the difference is factored in 432 per the expectation of the Camera2 API specification, which mandates the 433 FOV reduction from full sensor area must only occur in one dimension: 434 horizontally or vertically, and never both. For example, let's say a sensor 435 has a 16:10 full sensor FOV. For all 16:10 output images there should be no 436 FOV reduction on them. For 16:9 output images the FOV should be vertically 437 cropped by 9/10. For 4:3 output images the FOV should be cropped 438 horizontally instead and the ratio (r) can be calculated as follows: 439 (16 * r) / 10 = 4 / 3 => r = 40 / 48 = 0.8333 440 Say the circle is covering x percent of the 16:10 sensor on the full 16:10 441 FOV, and assume the circle in the center will never be cut in any output 442 sizes (this can be achieved by picking the right size and position of the 443 test circle), the from above cropping expectation we can derive on a 16:9 444 output image the circle will cover (x / 0.9) percent of the 16:9 image; on 445 a 4:3 output image the circle will cover (x / 0.8333) percent of the 4:3 446 image. 447 448 The crop test checks that the center of any output image remains aligned 449 with center of sensor's active area, no matter what kind of cropping or 450 scaling is applied. The test verifies that by checking the relative vector 451 from the image center to the center of detected circle remains unchanged. 452 The relative part is normalized by the detected circle size to account for 453 scaling effect. 454 """ 455 456 def test_aspect_ratio_and_crop(self): 457 logging.debug('Starting %s', _NAME) 458 failed_ar = [] # Streams failed the aspect ratio test. 459 failed_crop = [] # Streams failed the crop test. 460 failed_fov = [] # Streams that fail FoV test. 461 format_list = _create_format_list() 462 463 with its_session_utils.ItsSession( 464 device_id=self.dut.serial, 465 camera_id=self.camera_id, 466 hidden_physical_id=self.hidden_physical_id) as cam: 467 props = cam.get_camera_properties() 468 fls_logical = props['android.lens.info.availableFocalLengths'] 469 logging.debug('logical available focal lengths: %s', str(fls_logical)) 470 props = cam.override_with_hidden_physical_camera_props(props) 471 fls_physical = props['android.lens.info.availableFocalLengths'] 472 logging.debug('physical available focal lengths: %s', str(fls_physical)) 473 log_path = self.log_path 474 475 # Check SKIP conditions. 476 first_api_level = its_session_utils.get_first_api_level(self.dut.serial) 477 _check_skip_conditions(first_api_level, props) 478 479 # Load chart for scene. 480 its_session_utils.load_scene( 481 cam, props, self.scene, self.tablet, self.chart_distance) 482 483 # Determine camera capabilities. 484 full_or_better = camera_properties_utils.full_or_better(props) 485 level3 = camera_properties_utils.level3(props) 486 raw_avlb = camera_properties_utils.raw16(props) 487 debug = self.debug_mode 488 489 # Converge 3A. 490 cam.do_3a() 491 req = capture_request_utils.auto_capture_request() 492 493 # If raw is available and main camera, use it as ground truth. 494 if raw_avlb and (fls_physical == fls_logical): 495 ref_fov, cc_ct_gt, aspect_ratio_gt = _find_raw_fov_reference( 496 cam, req, props, log_path) 497 else: 498 aspect_ratio_gt = 1.0 # Ground truth circle width/height ratio. 499 ref_fov, cc_ct_gt = _find_jpeg_fov_reference(cam, req, props, log_path) 500 501 run_crop_test = full_or_better and raw_avlb 502 if run_crop_test: 503 # Normalize the circle size to 1/4 of the image size, so that 504 # circle size won't affect the crop test result 505 crop_thresh_factor = ((min(ref_fov['w'], ref_fov['h']) / 4.0) / 506 max(ref_fov['circle_w'], ref_fov['circle_h'])) 507 else: 508 logging.debug('Crop test skipped') 509 510 # Take pictures of each settings with all the image sizes available. 511 for fmt in format_list: 512 fmt_iter = fmt['iter'] 513 fmt_cmpr = fmt['cmpr'] 514 # Get the size of 'cmpr'. 515 sizes = capture_request_utils.get_available_output_sizes( 516 fmt_cmpr, props, fmt['cmpr_size']) 517 if not sizes: # Device might not support RAW. 518 continue 519 w_cmpr, h_cmpr = sizes[0][0], sizes[0][1] 520 for size_iter in capture_request_utils.get_available_output_sizes( 521 fmt_iter, props, fmt['iter_max']): 522 w_iter, h_iter = size_iter[0], size_iter[1] 523 # Skip same format/size combination: ITS doesn't handle that properly. 524 if w_iter*h_iter == w_cmpr*h_cmpr and fmt_iter == fmt_cmpr: 525 continue 526 out_surface = [{'width': w_iter, 'height': h_iter, 527 'format': fmt_iter}] 528 out_surface.append({'width': w_cmpr, 'height': h_cmpr, 529 'format': fmt_cmpr}) 530 531 cap = cam.do_capture(req, out_surface)[0] 532 _check_basic_correctness(cap, fmt_iter, w_iter, h_iter) 533 logging.debug('Captured %s with %s %dx%d. Compared size: %dx%d', 534 fmt_iter, fmt_cmpr, w_iter, h_iter, w_cmpr, h_cmpr) 535 img = image_processing_utils.convert_capture_to_rgb_image(cap) 536 img *= 255 # cv2 uses [0, 255]. 537 img_name = '%s_%s_with_%s_w%d_h%d.png' % ( 538 os.path.join(log_path, _NAME), fmt_iter, fmt_cmpr, w_iter, h_iter) 539 circle = opencv_processing_utils.find_circle( 540 img, img_name, _CIRCLE_MIN_AREA, _CIRCLE_COLOR) 541 if debug: 542 opencv_processing_utils.append_circle_center_to_img(circle, img, 543 img_name) 544 545 # Check pass/fail for fov coverage for all fmts in AR_CHECKED 546 img /= 255 # image_processing_utils uses [0, 1]. 547 fov_chk_msg = _check_fov(circle, ref_fov, w_iter, h_iter, 548 first_api_level) 549 if fov_chk_msg: 550 failed_fov.append(fov_chk_msg) 551 image_processing_utils.write_image(img, img_name, True) 552 553 # Check pass/fail for aspect ratio. 554 ar_chk_msg = _check_ar( 555 circle, aspect_ratio_gt, w_iter, h_iter, fmt_iter, fmt_cmpr) 556 if ar_chk_msg: 557 failed_ar.append(ar_chk_msg) 558 image_processing_utils.write_image(img, img_name, True) 559 560 # Check pass/fail for crop. 561 if run_crop_test: 562 crop_chk_msg = _check_crop(circle, cc_ct_gt, w_iter, h_iter, 563 fmt_iter, fmt_cmpr, crop_thresh_factor) 564 if crop_chk_msg: 565 failed_crop.append(crop_chk_msg) 566 image_processing_utils.write_image(img, img_name, True) 567 568 # Print any failed test results. 569 _print_failed_test_results(failed_ar, failed_fov, failed_crop, 570 first_api_level, level3) 571 572if __name__ == '__main__': 573 test_runner.main() 574