| # Copyright 2015 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. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # 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. |
| """Validate aspect ratio, crop and FoV vs format.""" |
| |
| |
| import logging |
| import math |
| import os.path |
| from mobly import test_runner |
| import numpy as np |
| |
| import cv2 |
| import its_base_test |
| import camera_properties_utils |
| import capture_request_utils |
| import image_processing_utils |
| import its_session_utils |
| import opencv_processing_utils |
| |
| _ANDROID11_API_LEVEL = 30 |
| _CIRCLE_COLOR = 0 # [0: black, 255: white]. |
| _CIRCLE_MIN_AREA = 0.01 # 1% of image size. |
| _FOV_PERCENT_RTOL = 0.15 # Relative tolerance on circle FoV % to expected. |
| _LARGE_SIZE = 2000 # Size of a large image (compared against max(w, h)). |
| _NAME = os.path.splitext(os.path.basename(__file__))[0] |
| _PREVIEW_SIZE = (1920, 1080) |
| _THRESH_AR_L = 0.02 # Aspect ratio test threshold of large images. |
| _THRESH_AR_S = 0.075 # Aspect ratio test threshold of mini images. |
| _THRESH_CROP_L = 0.02 # Crop test threshold of large images. |
| _THRESH_CROP_S = 0.075 # Crop test threshold of mini images. |
| _THRESH_MIN_PIXEL = 4 # Crop test allowed offset. |
| |
| # Before API level 30, only resolutions with the following listed aspect ratio |
| # are checked. Device launched after API level 30 will need to pass the test |
| # for all advertised resolutions. Device launched before API level 30 just |
| # needs to pass the test for all resolutions within these aspect ratios. |
| _AR_CHECKED_PRE_API_30 = ('4:3', '16:9', '18:9') |
| _AR_DIFF_ATOL = 0.01 |
| |
| |
| def _check_skip_conditions(first_api_level, props): |
| """Check the skip conditions based on first API level.""" |
| if first_api_level < _ANDROID11_API_LEVEL: # Original constraint. |
| camera_properties_utils.skip_unless(camera_properties_utils.read_3a(props)) |
| else: # Loosen from read_3a to enable LIMITED coverage. |
| camera_properties_utils.skip_unless( |
| camera_properties_utils.ae_lock(props) and |
| camera_properties_utils.awb_lock(props)) |
| |
| |
| def _check_basic_correctness(cap, fmt_iter, w_iter, h_iter): |
| """Check the capture for basic correctness.""" |
| if cap['format'] != fmt_iter: |
| raise AssertionError |
| if cap['width'] != w_iter: |
| raise AssertionError |
| if cap['height'] != h_iter: |
| raise AssertionError |
| |
| |
| def _create_format_list(): |
| """Create format list for multiple capture objects. |
| |
| Do multi-capture of 'iter' and 'cmpr'. Iterate through all the available |
| sizes of 'iter', and only use the size specified for 'cmpr'. |
| The 'cmpr' capture is only used so that we have multiple capture target |
| instead of just one, which should help catching more potential issues. |
| The test doesn't look into the output of 'cmpr' images at all. |
| The 'iter_max' or 'cmpr_size' key defines the maximal size being iterated |
| or selected for the 'iter' and 'cmpr' stream accordingly. None means no |
| upper bound is specified. |
| |
| Args: |
| None |
| |
| Returns: |
| format_list |
| """ |
| format_list = [] |
| format_list.append({'iter': 'yuv', 'iter_max': None, |
| 'cmpr': 'yuv', 'cmpr_size': _PREVIEW_SIZE}) |
| format_list.append({'iter': 'yuv', 'iter_max': _PREVIEW_SIZE, |
| 'cmpr': 'jpeg', 'cmpr_size': None}) |
| format_list.append({'iter': 'yuv', 'iter_max': _PREVIEW_SIZE, |
| 'cmpr': 'raw', 'cmpr_size': None}) |
| format_list.append({'iter': 'jpeg', 'iter_max': None, |
| 'cmpr': 'raw', 'cmpr_size': None}) |
| format_list.append({'iter': 'jpeg', 'iter_max': None, |
| 'cmpr': 'yuv', 'cmpr_size': _PREVIEW_SIZE}) |
| return format_list |
| |
| |
| def _print_failed_test_results(failed_ar, failed_fov, failed_crop, |
| first_api_level, level_3): |
| """Print failed test results.""" |
| if failed_ar: |
| logging.error('Aspect ratio test summary') |
| logging.error('Images failed in the aspect ratio test:') |
| logging.error('Aspect ratio value: width / height') |
| for fa in failed_ar: |
| logging.error('%s', fa) |
| |
| if failed_fov: |
| logging.error('FoV test summary') |
| logging.error('Images failed in the FoV test:') |
| for fov in failed_fov: |
| logging.error('%s', str(fov)) |
| |
| if failed_crop: |
| logging.error('Crop test summary') |
| logging.error('Images failed in the crop test:') |
| logging.error('Circle center (H x V) relative to the image center.') |
| for fc in failed_crop: |
| logging.error('%s', fc) |
| if failed_ar: |
| raise RuntimeError |
| if failed_fov: |
| raise RuntimeError |
| if first_api_level > _ANDROID11_API_LEVEL: |
| if failed_crop: # failed_crop = [] if run_crop_test = False. |
| raise RuntimeError |
| else: |
| if failed_crop and level_3: |
| raise RuntimeError |
| |
| |
| def _is_checked_aspect_ratio(first_api_level, w, h): |
| """Determine if format aspect ratio is a checked on based of first_API.""" |
| if first_api_level >= _ANDROID11_API_LEVEL: |
| return True |
| |
| for ar_check in _AR_CHECKED_PRE_API_30: |
| match_ar_list = [float(x) for x in ar_check.split(':')] |
| match_ar = match_ar_list[0] / match_ar_list[1] |
| if np.isclose(float(w) / h, match_ar, atol=_AR_DIFF_ATOL): |
| return True |
| |
| return False |
| |
| |
| def _calc_expected_circle_image_ratio(ref_fov, img_w, img_h): |
| """Determine the circle image area ratio in percentage for a given image size. |
| |
| Cropping happens either horizontally or vertically. In both cases crop results |
| in the visble area reduced by a ratio r (r < 1) and the circle will in turn |
| occupy ref_pct/r (percent) on the target image size. |
| |
| Args: |
| ref_fov: dict with {fmt, % coverage, w, h, circle_w, circle_h} |
| img_w: the image width |
| img_h: the image height |
| |
| Returns: |
| chk_percent: the expected circle image area ratio in percentage |
| """ |
| ar_ref = ref_fov['w'] / ref_fov['h'] |
| ar_target = img_w / img_h |
| |
| r = ar_ref / ar_target |
| if r < 1.0: |
| r = 1.0 / r |
| return ref_fov['percent'] * r |
| |
| |
| def _find_raw_fov_reference(cam, req, props, log_path): |
| """Determine the circle coverage of the image in RAW reference image. |
| |
| Captures a full-frame RAW and uses its aspect ratio and circle center |
| location as ground truth for the other jpeg or yuv images. |
| |
| The intrinsics and distortion coefficients are meant for full-sized RAW, |
| so convert_capture_to_rgb_image returns a 2x downsampled version, so resizes |
| RGB back to full size. |
| |
| If the device supports lens distortion correction, applies the coefficients on |
| the RAW image so it can be compared to YUV/JPEG outputs which are subject |
| to the same correction via ISP. |
| |
| Finds circle size and location for reference values in calculations for other |
| formats. |
| |
| Args: |
| cam: camera object |
| req: camera request |
| props: camera properties |
| log_path: location to save data |
| |
| Returns: |
| ref_fov: dict with [fmt, % coverage, w, h, circle_w, circle_h] |
| cc_ct_gt: circle center position relative to the center of image. |
| aspect_ratio_gt: aspect ratio of the detected circle in float. |
| """ |
| logging.debug('Creating references for fov_coverage from RAW') |
| out_surface = {'format': 'raw'} |
| cap_raw = cam.do_capture(req, out_surface) |
| logging.debug('Captured RAW %dx%d', cap_raw['width'], cap_raw['height']) |
| img_raw = image_processing_utils.convert_capture_to_rgb_image( |
| cap_raw, props=props) |
| # Resize back up to full scale. |
| img_raw = cv2.resize(img_raw, (0, 0), fx=2.0, fy=2.0) |
| |
| if (camera_properties_utils.distortion_correction(props) and |
| camera_properties_utils.intrinsic_calibration(props)): |
| logging.debug('Applying intrinsic calibration and distortion params') |
| fd = float(cap_raw['metadata']['android.lens.focalLength']) |
| k = camera_properties_utils.get_intrinsic_calibration(props, True, fd) |
| opencv_dist = camera_properties_utils.get_distortion_matrix(props) |
| img_raw = cv2.undistort(img_raw, k, opencv_dist) |
| |
| # Get image size. |
| size_raw = img_raw.shape |
| w_raw = size_raw[1] |
| h_raw = size_raw[0] |
| img_name = '%s_%s_w%d_h%d.png' % ( |
| os.path.join(log_path, _NAME), 'raw', w_raw, h_raw) |
| image_processing_utils.write_image(img_raw, img_name, True) |
| |
| # Find circle. |
| img_raw *= 255 # cv2 needs images between [0,255]. |
| circle_raw = opencv_processing_utils.find_circle( |
| img_raw, img_name, _CIRCLE_MIN_AREA, _CIRCLE_COLOR) |
| opencv_processing_utils.append_circle_center_to_img(circle_raw, img_raw, |
| img_name) |
| |
| # Determine final return values. |
| aspect_ratio_gt = circle_raw['w'] / circle_raw['h'] |
| cc_ct_gt = {'hori': circle_raw['x_offset'], 'vert': circle_raw['y_offset']} |
| raw_fov_percent = _calc_circle_image_ratio(circle_raw['r'], w_raw, h_raw) |
| ref_fov = {} |
| ref_fov['fmt'] = 'RAW' |
| ref_fov['percent'] = raw_fov_percent |
| ref_fov['w'] = w_raw |
| ref_fov['h'] = h_raw |
| ref_fov['circle_w'] = circle_raw['w'] |
| ref_fov['circle_h'] = circle_raw['h'] |
| logging.debug('Using RAW reference: %s', str(ref_fov)) |
| return ref_fov, cc_ct_gt, aspect_ratio_gt |
| |
| |
| def _find_jpeg_fov_reference(cam, req, props, log_path): |
| """Determine the circle coverage of the image in JPEG reference image. |
| |
| Similar to _find_raw_fov_reference() and used when RAW is not available. |
| |
| Args: |
| cam: camera object |
| req: camera request |
| props: camera properties |
| log_path: location to save data |
| |
| Returns: |
| ref_fov: dict with [fmt, % coverage, w, h, circle_w, circle_h] |
| cc_ct_gt: circle center position relative to the center of image. |
| """ |
| ref_fov = {} |
| fmt = capture_request_utils.get_largest_jpeg_format(props) |
| # Capture and determine circle area in image. |
| cap = cam.do_capture(req, fmt) |
| w = cap['width'] |
| h = cap['height'] |
| |
| img = image_processing_utils.convert_capture_to_rgb_image(cap, props) |
| img *= 255 # cv2 works with [0,255] images. |
| logging.debug('Captured JPEG %dx%d', w, h) |
| img_name = '%s_jpeg_w%d_h%d.png' % (os.path.join(log_path, _NAME), w, h) |
| circle_jpg = opencv_processing_utils.find_circle( |
| img, img_name, _CIRCLE_MIN_AREA, _CIRCLE_COLOR) |
| opencv_processing_utils.append_circle_center_to_img(circle_jpg, img, |
| img_name) |
| |
| # Determine final return values. |
| cc_ct_gt = {'hori': circle_jpg['x_offset'], 'vert': circle_jpg['y_offset']} |
| fov_percent = _calc_circle_image_ratio(circle_jpg['r'], w, h) |
| ref_fov = {} |
| ref_fov['fmt'] = 'JPEG' |
| ref_fov['percent'] = fov_percent |
| ref_fov['w'] = w |
| ref_fov['h'] = h |
| ref_fov['circle_w'] = circle_jpg['w'] |
| ref_fov['circle_h'] = circle_jpg['h'] |
| logging.debug('Using JPEG reference: %s', str(ref_fov)) |
| return ref_fov, cc_ct_gt |
| |
| |
| def _calc_circle_image_ratio(radius, img_w, img_h): |
| """Calculate the percent of area the input circle covers in input image. |
| |
| Args: |
| radius: radius of circle |
| img_w: int width of image |
| img_h: int height of image |
| Returns: |
| fov_percent: float % of image covered by circle |
| """ |
| return 100 * math.pi * math.pow(radius, 2) / (img_w * img_h) |
| |
| |
| def _check_fov(circle, ref_fov, w, h, first_api_level): |
| """Check the FoV for correct size.""" |
| fov_percent = _calc_circle_image_ratio(circle['r'], w, h) |
| chk_percent = _calc_expected_circle_image_ratio(ref_fov, w, h) |
| chk_enabled = _is_checked_aspect_ratio(first_api_level, w, h) |
| if chk_enabled and not np.isclose(fov_percent, chk_percent, |
| rtol=_FOV_PERCENT_RTOL): |
| e_msg = 'FoV %%: %.2f, Ref FoV %%: %.2f, ' % (fov_percent, chk_percent) |
| e_msg += 'TOL=%.f%%, img: %dx%d, ref: %dx%d' % ( |
| _FOV_PERCENT_RTOL*100, w, h, ref_fov['w'], ref_fov['h']) |
| return e_msg |
| |
| |
| def _check_ar(circle, ar_gt, w, h, fmt_iter, fmt_cmpr): |
| """Check the aspect ratio of the circle. |
| |
| size is the larger of w or h. |
| if size >= LARGE_SIZE: use THRESH_AR_L |
| elif size == 0 (extreme case): THRESH_AR_S |
| elif 0 < image size < LARGE_SIZE: scale between THRESH_AR_S & THRESH_AR_L |
| |
| Args: |
| circle: dict with circle parameters |
| ar_gt: aspect ratio ground truth to compare against |
| w: width of image |
| h: height of image |
| fmt_iter: format of primary capture |
| fmt_cmpr: format of secondary capture |
| |
| Returns: |
| error string if check fails |
| """ |
| thresh_ar = max(_THRESH_AR_L, _THRESH_AR_S + |
| max(w, h) * (_THRESH_AR_L-_THRESH_AR_S) / _LARGE_SIZE) |
| ar = circle['w'] / circle['h'] |
| if not np.isclose(ar, ar_gt, atol=thresh_ar): |
| e_msg = (f'{fmt_iter} with {fmt_cmpr} {w}x{h}: aspect_ratio {ar:.3f}, ' |
| f'thresh {thresh_ar:.3f}') |
| return e_msg |
| |
| |
| def _check_crop(circle, cc_gt, w, h, fmt_iter, fmt_cmpr, crop_thresh_factor): |
| """Check cropping. |
| |
| if size >= LARGE_SIZE: use thresh_crop_l |
| elif size == 0 (extreme case): thresh_crop_s |
| elif 0 < size < LARGE_SIZE: scale between thresh_crop_s & thresh_crop_l |
| Also allow at least THRESH_MIN_PIXEL to prevent threshold being too tight |
| for very small circle. |
| |
| Args: |
| circle: dict of circle values |
| cc_gt: circle center {'hori', 'vert'} ground truth (ref'd to img center) |
| w: width of image |
| h: height of image |
| fmt_iter: format of primary capture |
| fmt_cmpr: format of secondary capture |
| crop_thresh_factor: scaling factor for crop thresholds |
| |
| Returns: |
| error string if check fails |
| """ |
| thresh_crop_l = _THRESH_CROP_L * crop_thresh_factor |
| thresh_crop_s = _THRESH_CROP_S * crop_thresh_factor |
| thresh_crop_hori = max( |
| [thresh_crop_l, |
| thresh_crop_s + w * (thresh_crop_l - thresh_crop_s) / _LARGE_SIZE, |
| _THRESH_MIN_PIXEL / circle['w']]) |
| thresh_crop_vert = max( |
| [thresh_crop_l, |
| thresh_crop_s + h * (thresh_crop_l - thresh_crop_s) / _LARGE_SIZE, |
| _THRESH_MIN_PIXEL / circle['h']]) |
| |
| if (not np.isclose(circle['x_offset'], cc_gt['hori'], |
| atol=thresh_crop_hori) or |
| not np.isclose(circle['y_offset'], cc_gt['vert'], |
| atol=thresh_crop_vert)): |
| valid_x_range = (cc_gt['hori'] - thresh_crop_hori, |
| cc_gt['hori'] + thresh_crop_hori) |
| valid_y_range = (cc_gt['vert'] - thresh_crop_vert, |
| cc_gt['vert'] + thresh_crop_vert) |
| e_msg = (f'{fmt_iter} with {fmt_cmpr} {w}x{h} ' |
| f"offset X {circle['x_offset']:.3f}, Y {circle['y_offset']:.3f}, " |
| f'valid X range: {valid_x_range[0]:.3f} ~ {valid_x_range[1]:.3f}, ' |
| f'valid Y range: {valid_y_range[0]:.3f} ~ {valid_y_range[1]:.3f}') |
| return e_msg |
| |
| |
| class AspectRatioAndCropTest(its_base_test.ItsBaseTest): |
| """Test aspect ratio/field of view/cropping for each tested fmt combinations. |
| |
| This test checks for: |
| 1. Aspect ratio: images are not stretched |
| 2. Crop: center of images is not shifted |
| 3. FOV: images cropped to keep maximum possible FOV with only 1 dimension |
| (horizontal or veritical) cropped. |
| |
| Aspect ratio and FOV test runs on level3, full and limited devices. |
| Crop test only runs on level3 and full devices. |
| |
| The test chart is a black circle inside a black square. When raw capture is |
| available, set the height vs. width ratio of the circle in the full-frame |
| raw as ground truth. In an ideal setup such ratio should be very close to |
| 1.0, but here we just use the value derived from full resolution RAW as |
| ground truth to account for the possibility that the chart is not well |
| positioned to be precisely parallel to image sensor plane. |
| The test then compares the ground truth ratio with the same ratio measured |
| on images captued using different stream combinations of varying formats |
| ('jpeg' and 'yuv') and resolutions. |
| If raw capture is unavailable, a full resolution JPEG image is used to setup |
| ground truth. In this case, the ground truth aspect ratio is defined as 1.0 |
| and it is the tester's responsibility to make sure the test chart is |
| properly positioned so the detected circles indeed have aspect ratio close |
| to 1.0 assuming no bugs causing image stretched. |
| |
| The aspect ratio test checks the aspect ratio of the detected circle and |
| it will fail if the aspect ratio differs too much from the ground truth |
| aspect ratio mentioned above. |
| |
| The FOV test examines the ratio between the detected circle area and the |
| image size. When the aspect ratio of the test image is the same as the |
| ground truth image, the ratio should be very close to the ground truth |
| value. When the aspect ratio is different, the difference is factored in |
| per the expectation of the Camera2 API specification, which mandates the |
| FOV reduction from full sensor area must only occur in one dimension: |
| horizontally or vertically, and never both. For example, let's say a sensor |
| has a 16:10 full sensor FOV. For all 16:10 output images there should be no |
| FOV reduction on them. For 16:9 output images the FOV should be vertically |
| cropped by 9/10. For 4:3 output images the FOV should be cropped |
| horizontally instead and the ratio (r) can be calculated as follows: |
| (16 * r) / 10 = 4 / 3 => r = 40 / 48 = 0.8333 |
| Say the circle is covering x percent of the 16:10 sensor on the full 16:10 |
| FOV, and assume the circle in the center will never be cut in any output |
| sizes (this can be achieved by picking the right size and position of the |
| test circle), the from above cropping expectation we can derive on a 16:9 |
| output image the circle will cover (x / 0.9) percent of the 16:9 image; on |
| a 4:3 output image the circle will cover (x / 0.8333) percent of the 4:3 |
| image. |
| |
| The crop test checks that the center of any output image remains aligned |
| with center of sensor's active area, no matter what kind of cropping or |
| scaling is applied. The test verifies that by checking the relative vector |
| from the image center to the center of detected circle remains unchanged. |
| The relative part is normalized by the detected circle size to account for |
| scaling effect. |
| """ |
| |
| def test_aspect_ratio_and_crop(self): |
| logging.debug('Starting %s', _NAME) |
| failed_ar = [] # Streams failed the aspect ratio test. |
| failed_crop = [] # Streams failed the crop test. |
| failed_fov = [] # Streams that fail FoV test. |
| format_list = _create_format_list() |
| |
| with its_session_utils.ItsSession( |
| device_id=self.dut.serial, |
| camera_id=self.camera_id, |
| hidden_physical_id=self.hidden_physical_id) as cam: |
| props = cam.get_camera_properties() |
| fls_logical = props['android.lens.info.availableFocalLengths'] |
| logging.debug('logical available focal lengths: %s', str(fls_logical)) |
| props = cam.override_with_hidden_physical_camera_props(props) |
| fls_physical = props['android.lens.info.availableFocalLengths'] |
| logging.debug('physical available focal lengths: %s', str(fls_physical)) |
| log_path = self.log_path |
| |
| # Check SKIP conditions. |
| first_api_level = its_session_utils.get_first_api_level(self.dut.serial) |
| _check_skip_conditions(first_api_level, props) |
| |
| # Load chart for scene. |
| its_session_utils.load_scene( |
| cam, props, self.scene, self.tablet, self.chart_distance) |
| |
| # Determine camera capabilities. |
| full_or_better = camera_properties_utils.full_or_better(props) |
| level3 = camera_properties_utils.level3(props) |
| raw_avlb = camera_properties_utils.raw16(props) |
| debug = self.debug_mode |
| |
| # Converge 3A. |
| cam.do_3a() |
| req = capture_request_utils.auto_capture_request() |
| |
| # If raw is available and main camera, use it as ground truth. |
| if raw_avlb and (fls_physical == fls_logical): |
| ref_fov, cc_ct_gt, aspect_ratio_gt = _find_raw_fov_reference( |
| cam, req, props, log_path) |
| else: |
| aspect_ratio_gt = 1.0 # Ground truth circle width/height ratio. |
| ref_fov, cc_ct_gt = _find_jpeg_fov_reference(cam, req, props, log_path) |
| |
| run_crop_test = full_or_better and raw_avlb |
| if run_crop_test: |
| # Normalize the circle size to 1/4 of the image size, so that |
| # circle size won't affect the crop test result |
| crop_thresh_factor = ((min(ref_fov['w'], ref_fov['h']) / 4.0) / |
| max(ref_fov['circle_w'], ref_fov['circle_h'])) |
| else: |
| logging.debug('Crop test skipped') |
| |
| # Take pictures of each settings with all the image sizes available. |
| for fmt in format_list: |
| fmt_iter = fmt['iter'] |
| fmt_cmpr = fmt['cmpr'] |
| # Get the size of 'cmpr'. |
| sizes = capture_request_utils.get_available_output_sizes( |
| fmt_cmpr, props, fmt['cmpr_size']) |
| if not sizes: # Device might not support RAW. |
| continue |
| w_cmpr, h_cmpr = sizes[0][0], sizes[0][1] |
| for size_iter in capture_request_utils.get_available_output_sizes( |
| fmt_iter, props, fmt['iter_max']): |
| w_iter, h_iter = size_iter[0], size_iter[1] |
| # Skip same format/size combination: ITS doesn't handle that properly. |
| if w_iter*h_iter == w_cmpr*h_cmpr and fmt_iter == fmt_cmpr: |
| continue |
| out_surface = [{'width': w_iter, 'height': h_iter, |
| 'format': fmt_iter}] |
| out_surface.append({'width': w_cmpr, 'height': h_cmpr, |
| 'format': fmt_cmpr}) |
| |
| cap = cam.do_capture(req, out_surface)[0] |
| _check_basic_correctness(cap, fmt_iter, w_iter, h_iter) |
| logging.debug('Captured %s with %s %dx%d. Compared size: %dx%d', |
| fmt_iter, fmt_cmpr, w_iter, h_iter, w_cmpr, h_cmpr) |
| img = image_processing_utils.convert_capture_to_rgb_image(cap) |
| img *= 255 # cv2 uses [0, 255]. |
| img_name = '%s_%s_with_%s_w%d_h%d.png' % ( |
| os.path.join(log_path, _NAME), fmt_iter, fmt_cmpr, w_iter, h_iter) |
| circle = opencv_processing_utils.find_circle( |
| img, img_name, _CIRCLE_MIN_AREA, _CIRCLE_COLOR) |
| if debug: |
| opencv_processing_utils.append_circle_center_to_img(circle, img, |
| img_name) |
| |
| # Check pass/fail for fov coverage for all fmts in AR_CHECKED |
| img /= 255 # image_processing_utils uses [0, 1]. |
| fov_chk_msg = _check_fov(circle, ref_fov, w_iter, h_iter, |
| first_api_level) |
| if fov_chk_msg: |
| failed_fov.append(fov_chk_msg) |
| image_processing_utils.write_image(img, img_name, True) |
| |
| # Check pass/fail for aspect ratio. |
| ar_chk_msg = _check_ar( |
| circle, aspect_ratio_gt, w_iter, h_iter, fmt_iter, fmt_cmpr) |
| if ar_chk_msg: |
| failed_ar.append(ar_chk_msg) |
| image_processing_utils.write_image(img, img_name, True) |
| |
| # Check pass/fail for crop. |
| if run_crop_test: |
| crop_chk_msg = _check_crop(circle, cc_ct_gt, w_iter, h_iter, |
| fmt_iter, fmt_cmpr, crop_thresh_factor) |
| if crop_chk_msg: |
| failed_crop.append(crop_chk_msg) |
| image_processing_utils.write_image(img, img_name, True) |
| |
| # Print any failed test results. |
| _print_failed_test_results(failed_ar, failed_fov, failed_crop, |
| first_api_level, level3) |
| |
| if __name__ == '__main__': |
| test_runner.main() |