1# Copyright 2014 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"""Utility functions to determine what functionality the camera supports.""" 15 16 17import logging 18import math 19import types 20 21from mobly import asserts 22import numpy as np 23 24import capture_request_utils 25 26FD_CAL_RTOL = 0.20 27LENS_FACING = types.MappingProxyType({'FRONT': 0, 'BACK': 1, 'EXTERNAL': 2}) 28MULTI_CAMERA_SYNC_CALIBRATED = 1 29NUM_DISTORTION_PARAMS = 5 # number of terms in lens.distortion 30NUM_INTRINSIC_CAL_PARAMS = 5 # number of terms in intrinsic calibration 31NUM_POSE_ROTATION_PARAMS = 4 # number of terms in poseRotation 32NUM_POSE_TRANSLATION_PARAMS = 3 # number of terms in poseTranslation 33SKIP_RET_MSG = 'Test skipped' 34SOLID_COLOR_TEST_PATTERN = 1 35COLOR_BARS_TEST_PATTERN = 2 36USE_CASE_STILL_CAPTURE = 2 37DEFAULT_AE_TARGET_FPS_RANGE = (15, 30) 38COLOR_SPACES = [ 39 'SRGB', 'LINEAR_SRGB', 'EXTENDED_SRGB', 40 'LINEAR_EXTENDED_SRGB', 'BT709', 'BT2020', 41 'DCI_P3', 'DISPLAY_P3', 'NTSC_1953', 'SMPTE_C', 42 'ADOBE_RGB', 'PRO_PHOTO_RGB', 'ACES', 'ACESCG', 43 'CIE_XYZ', 'CIE_LAB', 'BT2020_HLG', 'BT2020_PQ' 44] 45SETTINGS_OVERRIDE_ZOOM = 1 46STABILIZATION_MODE_OFF = 0 47STABILIZATION_MODE_PREVIEW = 2 48LENS_OPTICAL_STABILIZATION_MODE_ON = 1 49 50_M_TO_CM = 100 51 52 53def log_minimum_focus_distance(props): 54 """Log the minimum focus distance for debugging AF issues. 55 56 Args: 57 props: Camera properties object. 58 """ 59 min_fd_diopters = props['android.lens.info.minimumFocusDistance'] 60 if min_fd_diopters: # not equal to 0 61 min_fd_cm = 1 / min_fd_diopters * _M_TO_CM 62 logging.debug('Minimum focus distance (cm): %.2f', min_fd_cm) 63 else: 64 logging.debug('Fixed focus camera') 65 66 67def check_front_or_rear_camera(props): 68 """Raises an error if not LENS_FACING FRONT or BACK. 69 70 Args: 71 props: Camera properties object. 72 73 Raises: 74 assertionError if not front or rear camera. 75 """ 76 facing = props['android.lens.facing'] 77 if not (facing == LENS_FACING['BACK'] or facing == LENS_FACING['FRONT']): 78 raise AssertionError('Unknown lens facing: {facing}.') 79 80 81def legacy(props): 82 """Returns whether a device is a LEGACY capability camera2 device. 83 84 Args: 85 props: Camera properties object. 86 87 Returns: 88 Boolean. True if device is a LEGACY camera. 89 """ 90 return props.get('android.info.supportedHardwareLevel') == 2 91 92 93def limited(props): 94 """Returns whether a device is a LIMITED capability camera2 device. 95 96 Args: 97 props: Camera properties object. 98 99 Returns: 100 Boolean. True if device is a LIMITED camera. 101 """ 102 return props.get('android.info.supportedHardwareLevel') == 0 103 104 105def full_or_better(props): 106 """Returns whether a device is a FULL or better camera2 device. 107 108 Args: 109 props: Camera properties object. 110 111 Returns: 112 Boolean. True if device is FULL or LEVEL3 camera. 113 """ 114 return (props.get('android.info.supportedHardwareLevel') >= 1 and 115 props.get('android.info.supportedHardwareLevel') != 2) 116 117 118def level3(props): 119 """Returns whether a device is a LEVEL3 capability camera2 device. 120 121 Args: 122 props: Camera properties object. 123 124 Returns: 125 Boolean. True if device is LEVEL3 camera. 126 """ 127 return props.get('android.info.supportedHardwareLevel') == 3 128 129 130def manual_sensor(props): 131 """Returns whether a device supports MANUAL_SENSOR capabilities. 132 133 Args: 134 props: Camera properties object. 135 136 Returns: 137 Boolean. True if devices supports MANUAL_SENSOR capabilities. 138 """ 139 return 1 in props.get('android.request.availableCapabilities', []) 140 141 142def manual_post_proc(props): 143 """Returns whether a device supports MANUAL_POST_PROCESSING capabilities. 144 145 Args: 146 props: Camera properties object. 147 148 Returns: 149 Boolean. True if device supports MANUAL_POST_PROCESSING capabilities. 150 """ 151 return 2 in props.get('android.request.availableCapabilities', []) 152 153 154def raw(props): 155 """Returns whether a device supports RAW capabilities. 156 157 Args: 158 props: Camera properties object. 159 160 Returns: 161 Boolean. True if device supports RAW capabilities. 162 """ 163 return 3 in props.get('android.request.availableCapabilities', []) 164 165 166def sensor_fusion(props): 167 """Checks the camera and motion sensor timestamps. 168 169 Returns whether the camera and motion sensor timestamps for the device 170 are in the same time domain and can be compared directly. 171 172 Args: 173 props: Camera properties object. 174 175 Returns: 176 Boolean. True if camera and motion sensor timestamps in same time domain. 177 """ 178 return props.get('android.sensor.info.timestampSource') == 1 179 180 181def burst_capture_capable(props): 182 """Returns whether a device supports burst capture. 183 184 Args: 185 props: Camera properties object. 186 187 Returns: 188 Boolean. True if the device supports burst capture. 189 """ 190 return 6 in props.get('android.request.availableCapabilities', []) 191 192 193def logical_multi_camera(props): 194 """Returns whether a device is a logical multi-camera. 195 196 Args: 197 props: Camera properties object. 198 199 Returns: 200 Boolean. True if the device is a logical multi-camera. 201 """ 202 return 11 in props.get('android.request.availableCapabilities', []) 203 204 205def logical_multi_camera_physical_ids(props): 206 """Returns a logical multi-camera's underlying physical cameras. 207 208 Args: 209 props: Camera properties object. 210 211 Returns: 212 list of physical cameras backing the logical multi-camera. 213 """ 214 physical_ids_list = [] 215 if logical_multi_camera(props): 216 physical_ids_list = props['camera.characteristics.physicalCamIds'] 217 return physical_ids_list 218 219 220def skip_unless(cond, msg=None): 221 """Skips the test if the condition is false. 222 223 If a test is skipped, then it is exited and returns the special code 224 of 101 to the calling shell, which can be used by an external test 225 harness to differentiate a skip from a pass or fail. 226 227 Args: 228 cond: Boolean, which must be true for the test to not skip. 229 msg: String, reason for test to skip 230 231 Returns: 232 Nothing. 233 """ 234 if not cond: 235 skip_msg = SKIP_RET_MSG if not msg else f'{SKIP_RET_MSG}: {msg}' 236 asserts.skip(skip_msg) 237 238 239def backward_compatible(props): 240 """Returns whether a device supports BACKWARD_COMPATIBLE. 241 242 Args: 243 props: Camera properties object. 244 245 Returns: 246 Boolean. True if the devices supports BACKWARD_COMPATIBLE. 247 """ 248 return 0 in props.get('android.request.availableCapabilities', []) 249 250 251def lens_calibrated(props): 252 """Returns whether lens position is calibrated or not. 253 254 android.lens.info.focusDistanceCalibration has 3 modes. 255 0: Uncalibrated 256 1: Approximate 257 2: Calibrated 258 259 Args: 260 props: Camera properties objects. 261 262 Returns: 263 Boolean. True if lens is CALIBRATED. 264 """ 265 return 'android.lens.info.focusDistanceCalibration' in props and props[ 266 'android.lens.info.focusDistanceCalibration'] == 2 267 268 269def lens_approx_calibrated(props): 270 """Returns whether lens position is calibrated or not. 271 272 android.lens.info.focusDistanceCalibration has 3 modes. 273 0: Uncalibrated 274 1: Approximate 275 2: Calibrated 276 277 Args: 278 props: Camera properties objects. 279 280 Returns: 281 Boolean. True if lens is APPROXIMATE or CALIBRATED. 282 """ 283 return props.get('android.lens.info.focusDistanceCalibration') in [1, 2] 284 285 286def raw10(props): 287 """Returns whether a device supports RAW10 capabilities. 288 289 Args: 290 props: Camera properties object. 291 292 Returns: 293 Boolean. True if device supports RAW10 capabilities. 294 """ 295 if capture_request_utils.get_available_output_sizes('raw10', props): 296 return True 297 return False 298 299 300def raw12(props): 301 """Returns whether a device supports RAW12 capabilities. 302 303 Args: 304 props: Camera properties object. 305 306 Returns: 307 Boolean. True if device supports RAW12 capabilities. 308 """ 309 if capture_request_utils.get_available_output_sizes('raw12', props): 310 return True 311 return False 312 313 314def raw16(props): 315 """Returns whether a device supports RAW16 output. 316 317 Args: 318 props: Camera properties object. 319 320 Returns: 321 Boolean. True if device supports RAW16 capabilities. 322 """ 323 if capture_request_utils.get_available_output_sizes('raw', props): 324 return True 325 return False 326 327 328def raw_output(props): 329 """Returns whether a device supports any of the RAW output formats. 330 331 Args: 332 props: Camera properties object. 333 334 Returns: 335 Boolean. True if device supports any of the RAW output formats 336 """ 337 return raw16(props) or raw10(props) or raw12(props) 338 339 340def per_frame_control(props): 341 """Returns whether a device supports per frame control. 342 343 Args: 344 props: Camera properties object. 345 346 Returns: Boolean. True if devices supports per frame control. 347 """ 348 return 'android.sync.maxLatency' in props and props[ 349 'android.sync.maxLatency'] == 0 350 351 352def mono_camera(props): 353 """Returns whether a device is monochromatic. 354 355 Args: 356 props: Camera properties object. 357 Returns: Boolean. True if MONO camera. 358 """ 359 return 12 in props.get('android.request.availableCapabilities', []) 360 361 362def fixed_focus(props): 363 """Returns whether a device is fixed focus. 364 365 props[android.lens.info.minimumFocusDistance] == 0 is fixed focus 366 367 Args: 368 props: Camera properties objects. 369 370 Returns: 371 Boolean. True if device is a fixed focus camera. 372 """ 373 return 'android.lens.info.minimumFocusDistance' in props and props[ 374 'android.lens.info.minimumFocusDistance'] == 0 375 376 377def face_detect(props): 378 """Returns whether a device has face detection mode. 379 380 props['android.statistics.info.availableFaceDetectModes'] != 0 381 382 Args: 383 props: Camera properties objects. 384 385 Returns: 386 Boolean. True if device supports face detection. 387 """ 388 return 'android.statistics.info.availableFaceDetectModes' in props and props[ 389 'android.statistics.info.availableFaceDetectModes'] != [0] 390 391 392def read_3a(props): 393 """Return whether a device supports reading out the below 3A settings. 394 395 sensitivity 396 exposure time 397 awb gain 398 awb cct 399 focus distance 400 401 Args: 402 props: Camera properties object. 403 404 Returns: 405 Boolean. True if device supports reading out 3A settings. 406 """ 407 return manual_sensor(props) and manual_post_proc(props) 408 409 410def compute_target_exposure(props): 411 """Return whether a device supports target exposure computation. 412 413 Args: 414 props: Camera properties object. 415 416 Returns: 417 Boolean. True if device supports target exposure computation. 418 """ 419 return manual_sensor(props) and manual_post_proc(props) 420 421 422def y8(props): 423 """Returns whether a device supports Y8 output. 424 425 Args: 426 props: Camera properties object. 427 428 Returns: 429 Boolean. True if device suupports Y8 output. 430 """ 431 if capture_request_utils.get_available_output_sizes('y8', props): 432 return True 433 return False 434 435 436def jpeg_quality(props): 437 """Returns whether a device supports JPEG quality.""" 438 return ('camera.characteristics.requestKeys' in props) and ( 439 'android.jpeg.quality' in props['camera.characteristics.requestKeys']) 440 441 442def jpeg_orientation(props): 443 """Returns whether a device supports JPEG orientation.""" 444 return ('camera.characteristics.requestKeys' in props) and ( 445 'android.jpeg.orientation' in props['camera.characteristics.requestKeys']) 446 447 448def sensor_orientation(props): 449 """Returns the sensor orientation of the camera.""" 450 return props['android.sensor.orientation'] 451 452 453def zoom_ratio_range(props): 454 """Returns whether a device supports zoom capabilities. 455 456 Args: 457 props: Camera properties object. 458 459 Returns: 460 Boolean. True if device supports zoom capabilities. 461 """ 462 return 'android.control.zoomRatioRange' in props and props[ 463 'android.control.zoomRatioRange'] is not None 464 465 466def low_latency_zoom(props): 467 """Returns whether a device supports low latency zoom via settings override. 468 469 Args: 470 props: Camera properties object. 471 472 Returns: 473 Boolean. True if device supports SETTINGS_OVERRIDE_ZOOM. 474 """ 475 return ('android.control.availableSettingsOverrides') in props and ( 476 SETTINGS_OVERRIDE_ZOOM in props[ 477 'android.control.availableSettingsOverrides']) 478 479 480def sync_latency(props): 481 """Returns sync latency in number of frames. 482 483 If undefined, 8 frames. 484 485 Args: 486 props: Camera properties object. 487 488 Returns: 489 integer number of frames. 490 """ 491 latency = props['android.sync.maxLatency'] 492 if latency < 0: 493 latency = 8 494 return latency 495 496 497def get_max_digital_zoom(props): 498 """Returns the maximum amount of zooming possible by the camera device. 499 500 Args: 501 props: Camera properties object. 502 503 Returns: 504 A float indicating the maximum amount of zooming possible by the 505 camera device. 506 """ 507 z_max = 1.0 508 if 'android.scaler.availableMaxDigitalZoom' in props: 509 z_max = props['android.scaler.availableMaxDigitalZoom'] 510 return z_max 511 512 513def get_ae_target_fps_ranges(props): 514 """Returns the AE target FPS ranges supported by the camera device. 515 516 Args: 517 props: Camera properties object. 518 519 Returns: 520 A list of AE target FPS ranges supported by the camera device. 521 """ 522 ranges = [] # return empty list instead of Boolean if no FPS range in props 523 if 'android.control.aeAvailableTargetFpsRanges' in props: 524 ranges = props['android.control.aeAvailableTargetFpsRanges'] 525 return ranges 526 527 528def get_fps_range_to_test(fps_ranges): 529 """Returns an AE target FPS range to test based on camera device properties. 530 531 Args: 532 fps_ranges: list of AE target FPS ranges supported by camera. 533 e.g. [[7, 30], [24, 30], [30, 30]] 534 Returns: 535 An AE target FPS range for testing. 536 """ 537 default_range_min, default_range_max = DEFAULT_AE_TARGET_FPS_RANGE 538 default_range_size = default_range_max - default_range_min 539 logging.debug('AE target FPS ranges: %s', fps_ranges) 540 widest_fps_range = max(fps_ranges, key=lambda r: r[1] - r[0]) 541 if widest_fps_range[1] - widest_fps_range[0] < default_range_size: 542 logging.debug('Default range %s is wider than widest ' 543 'available AE target FPS range %s.', 544 DEFAULT_AE_TARGET_FPS_RANGE, 545 widest_fps_range) 546 logging.debug('Accepted AE target FPS range: %s', widest_fps_range) 547 return widest_fps_range 548 549 550def ae_lock(props): 551 """Returns whether a device supports AE lock. 552 553 Args: 554 props: Camera properties object. 555 556 Returns: 557 Boolean. True if device supports AE lock. 558 """ 559 return 'android.control.aeLockAvailable' in props and props[ 560 'android.control.aeLockAvailable'] == 1 561 562 563def awb_lock(props): 564 """Returns whether a device supports AWB lock. 565 566 Args: 567 props: Camera properties object. 568 569 Returns: 570 Boolean. True if device supports AWB lock. 571 """ 572 return 'android.control.awbLockAvailable' in props and props[ 573 'android.control.awbLockAvailable'] == 1 574 575 576def ev_compensation(props): 577 """Returns whether a device supports ev compensation. 578 579 Args: 580 props: Camera properties object. 581 582 Returns: 583 Boolean. True if device supports EV compensation. 584 """ 585 return 'android.control.aeCompensationRange' in props and props[ 586 'android.control.aeCompensationRange'] != [0, 0] 587 588 589def flash(props): 590 """Returns whether a device supports flash control. 591 592 Args: 593 props: Camera properties object. 594 595 Returns: 596 Boolean. True if device supports flash control. 597 """ 598 return 'android.flash.info.available' in props and props[ 599 'android.flash.info.available'] == 1 600 601 602def distortion_correction(props): 603 """Returns whether a device supports android.lens.distortion capabilities. 604 605 Args: 606 props: Camera properties object. 607 608 Returns: 609 Boolean. True if device supports lens distortion correction capabilities. 610 """ 611 return 'android.lens.distortion' in props and props[ 612 'android.lens.distortion'] is not None 613 614 615def distortion_correction_mode(props, mode): 616 """Returns whether a device supports a distortionCorrection mode. 617 618 Args: 619 props: Camera properties object 620 mode: Integer indicating distortion correction mode 621 622 Returns: 623 Boolean. True if device supports distortion correction mode(s). 624 """ 625 if 'android.distortionCorrection.availableModes' in props: 626 logging.debug('distortionCorrection.availableModes: %s', 627 props['android.distortionCorrection.availableModes']) 628 else: 629 logging.debug('distortionCorrection.availableModes not in props!') 630 return ('android.distortionCorrection.availableModes' in props and 631 mode in props['android.distortionCorrection.availableModes']) 632 633 634def freeform_crop(props): 635 """Returns whether a device supports freefrom cropping. 636 637 Args: 638 props: Camera properties object. 639 640 Returns: 641 Boolean. True if device supports freeform cropping. 642 """ 643 return 'android.scaler.croppingType' in props and props[ 644 'android.scaler.croppingType'] == 1 645 646 647def noise_reduction_mode(props, mode): 648 """Returns whether a device supports the noise reduction mode. 649 650 Args: 651 props: Camera properties objects. 652 mode: Integer indicating noise reduction mode to check for availability. 653 654 Returns: 655 Boolean. True if devices supports noise reduction mode(s). 656 """ 657 return ('android.noiseReduction.availableNoiseReductionModes' in props and 658 mode in props['android.noiseReduction.availableNoiseReductionModes']) 659 660 661def lsc_map(props): 662 """Returns whether a device supports lens shading map output. 663 664 Args: 665 props: Camera properties object. 666 Returns: Boolean. True if device supports lens shading map output. 667 """ 668 return 1 in props.get('android.statistics.info.availableLensShadingMapModes', 669 []) 670 671 672def lsc_off(props): 673 """Returns whether a device supports disabling lens shading correction. 674 675 Args: 676 props: Camera properties object. 677 678 Returns: 679 Boolean. True if device supports disabling lens shading correction. 680 """ 681 return 0 in props.get('android.shading.availableModes', []) 682 683 684def edge_mode(props, mode): 685 """Returns whether a device supports the edge mode. 686 687 Args: 688 props: Camera properties objects. 689 mode: Integer, indicating the edge mode to check for availability. 690 691 Returns: 692 Boolean. True if device supports edge mode(s). 693 """ 694 return 'android.edge.availableEdgeModes' in props and mode in props[ 695 'android.edge.availableEdgeModes'] 696 697 698def tonemap_mode(props, mode): 699 """Returns whether a device supports the tonemap mode. 700 701 Args: 702 props: Camera properties object. 703 mode: Integer, indicating the tonemap mode to check for availability. 704 705 Return: 706 Boolean. 707 """ 708 return 'android.tonemap.availableToneMapModes' in props and mode in props[ 709 'android.tonemap.availableToneMapModes'] 710 711 712def yuv_reprocess(props): 713 """Returns whether a device supports YUV reprocessing. 714 715 Args: 716 props: Camera properties object. 717 718 Returns: 719 Boolean. True if device supports YUV reprocessing. 720 """ 721 return 'android.request.availableCapabilities' in props and 7 in props[ 722 'android.request.availableCapabilities'] 723 724 725def private_reprocess(props): 726 """Returns whether a device supports PRIVATE reprocessing. 727 728 Args: 729 props: Camera properties object. 730 731 Returns: 732 Boolean. True if device supports PRIVATE reprocessing. 733 """ 734 return 'android.request.availableCapabilities' in props and 4 in props[ 735 'android.request.availableCapabilities'] 736 737 738def stream_use_case(props): 739 """Returns whether a device has stream use case capability. 740 741 Args: 742 props: Camera properties object. 743 744 Returns: 745 Boolean. True if the device has stream use case capability. 746 """ 747 return 'android.request.availableCapabilities' in props and 19 in props[ 748 'android.request.availableCapabilities'] 749 750 751def cropped_raw_stream_use_case(props): 752 """Returns whether a device supports the CROPPED_RAW stream use case. 753 754 Args: 755 props: Camera properties object. 756 757 Returns: 758 Boolean. True if the device supports the CROPPED_RAW stream use case. 759 """ 760 return stream_use_case(props) and 6 in props[ 761 'android.scaler.availableStreamUseCases'] 762 763 764def dynamic_range_ten_bit(props): 765 """Returns whether a device supports the DYNAMIC_RANGE_TEN_BIT capability. 766 767 Args: 768 props: Camera properties object. 769 770 Returns: 771 Boolean. True if the device supports the DYNAMIC_RANGE_TEN_BIT capability. 772 """ 773 return 'android.request.availableCapabilities' in props and 18 in props[ 774 'android.request.availableCapabilities'] 775 776 777def intrinsic_calibration(props): 778 """Returns whether a device supports android.lens.intrinsicCalibration. 779 780 Args: 781 props: Camera properties object. 782 783 Returns: 784 Boolean. True if device supports android.lens.intrinsicCalibratino. 785 """ 786 return props.get('android.lens.intrinsicCalibration') is not None 787 788 789def get_intrinsic_calibration(props, metadata, debug, fd=None): 790 """Get intrinsicCalibration and create intrisic matrix. 791 792 If intrinsic android.lens.intrinsicCalibration does not exist, return None. 793 794 Args: 795 props: camera properties. 796 metadata: dict; camera capture metadata. 797 debug: boolean; enable printing more information. 798 fd: float; focal length from capture metadata. 799 800 Returns: 801 numpy array for intrinsic transformation matrix or None 802 k = [[f_x, s, c_x], 803 [0, f_y, c_y], 804 [0, 0, 1]] 805 """ 806 if metadata.get('android.lens.intrinsicCalibration'): 807 ical = np.array(metadata['android.lens.intrinsicCalibration']) 808 logging.debug('Using capture metadata android.lens.intrinsicCalibration') 809 elif props.get('android.lens.intrinsicCalibration'): 810 ical = np.array(props['android.lens.intrinsicCalibration']) 811 logging.debug('Using camera property android.lens.intrinsicCalibration') 812 else: 813 logging.error('Camera does not have android.lens.intrinsicCalibration.') 814 return None 815 816 # basic checks for parameter correctness 817 ical_len = len(ical) 818 if ical_len != NUM_INTRINSIC_CAL_PARAMS: 819 raise ValueError( 820 f'instrisicCalibration has wrong number of params: {ical_len}.') 821 822 if fd is not None: 823 # detailed checks for parameter correctness 824 # Intrinsic cal is of format: [f_x, f_y, c_x, c_y, s] 825 # [f_x, f_y] is the horizontal and vertical focal lengths, 826 # [c_x, c_y] is the position of the optical axis, 827 # and s is skew of sensor plane vs lens plane. 828 sensor_h = props['android.sensor.info.physicalSize']['height'] 829 sensor_w = props['android.sensor.info.physicalSize']['width'] 830 pixel_h = props['android.sensor.info.pixelArraySize']['height'] 831 pixel_w = props['android.sensor.info.pixelArraySize']['width'] 832 fd_w_pix = pixel_w * fd / sensor_w 833 fd_h_pix = pixel_h * fd / sensor_h 834 835 if not math.isclose(fd_w_pix, ical[0], rel_tol=FD_CAL_RTOL): 836 raise ValueError(f'fd_w(pixels): {fd_w_pix:.2f}\tcal[0](pixels): ' 837 f'{ical[0]:.2f}\tTOL=20%') 838 if not math.isclose(fd_h_pix, ical[1], rel_tol=FD_CAL_RTOL): 839 raise ValueError(f'fd_h(pixels): {fd_h_pix:.2f}\tcal[1](pixels): ' 840 f'{ical[1]:.2f}\tTOL=20%') 841 842 # generate instrinsic matrix 843 k = np.array([[ical[0], ical[4], ical[2]], 844 [0, ical[1], ical[3]], 845 [0, 0, 1]]) 846 if debug: 847 logging.debug('k: %s', str(k)) 848 return k 849 850 851def get_translation_matrix(props, debug): 852 """Get translation matrix. 853 854 Args: 855 props: dict of camera properties 856 debug: boolean flag to log more info 857 858 Returns: 859 android.lens.poseTranslation matrix if it exists, otherwise None. 860 """ 861 if props['android.lens.poseTranslation']: 862 t = np.array(props['android.lens.poseTranslation']) 863 else: 864 logging.error('Device does not have android.lens.poseTranslation.') 865 return None 866 867 if debug: 868 logging.debug('translation: %s', str(t)) 869 t_len = len(t) 870 if t_len != NUM_POSE_TRANSLATION_PARAMS: 871 raise ValueError(f'poseTranslation has wrong # of params: {t_len}.') 872 return t 873 874 875def get_rotation_matrix(props, debug): 876 """Convert the rotation parameters to 3-axis data. 877 878 Args: 879 props: camera properties 880 debug: boolean for more information 881 882 Returns: 883 3x3 matrix w/ rotation parameters if poseRotation exists, otherwise None 884 """ 885 if props['android.lens.poseRotation']: 886 rotation = np.array(props['android.lens.poseRotation']) 887 else: 888 logging.error('Device does not have android.lens.poseRotation.') 889 return None 890 891 if debug: 892 logging.debug('rotation: %s', str(rotation)) 893 rotation_len = len(rotation) 894 if rotation_len != NUM_POSE_ROTATION_PARAMS: 895 raise ValueError(f'poseRotation has wrong # of params: {rotation_len}.') 896 x = rotation[0] 897 y = rotation[1] 898 z = rotation[2] 899 w = rotation[3] 900 return np.array([[1-2*y**2-2*z**2, 2*x*y-2*z*w, 2*x*z+2*y*w], 901 [2*x*y+2*z*w, 1-2*x**2-2*z**2, 2*y*z-2*x*w], 902 [2*x*z-2*y*w, 2*y*z+2*x*w, 1-2*x**2-2*y**2]]) 903 904 905def get_distortion_matrix(props): 906 """Get android.lens.distortion matrix and convert to cv2 fmt. 907 908 Args: 909 props: dict of camera properties 910 911 Returns: 912 cv2 reordered android.lens.distortion if it exists, otherwise None. 913 """ 914 if props['android.lens.distortion']: 915 dist = np.array(props['android.lens.distortion']) 916 else: 917 logging.error('Device does not have android.lens.distortion.') 918 return None 919 920 dist_len = len(dist) 921 if len(dist) != NUM_DISTORTION_PARAMS: 922 raise ValueError(f'lens.distortion has wrong # of params: {dist_len}.') 923 cv2_distort = np.array([dist[0], dist[1], dist[3], dist[4], dist[2]]) 924 logging.debug('cv2 distortion params: %s', str(cv2_distort)) 925 return cv2_distort 926 927 928def post_raw_sensitivity_boost(props): 929 """Returns whether a device supports post RAW sensitivity boost. 930 931 Args: 932 props: Camera properties object. 933 934 Returns: 935 Boolean. True if android.control.postRawSensitivityBoost is supported. 936 """ 937 return ( 938 'android.control.postRawSensitivityBoostRange' in 939 props['camera.characteristics.keys'] and 940 props.get('android.control.postRawSensitivityBoostRange') != [100, 100]) 941 942 943def sensor_fusion_capable(props): 944 """Determine if test_sensor_fusion is run.""" 945 return all([sensor_fusion(props), 946 manual_sensor(props), 947 props['android.lens.facing'] != LENS_FACING['EXTERNAL']]) 948 949 950def continuous_picture(props): 951 """Returns whether a device supports CONTINUOUS_PICTURE. 952 953 Args: 954 props: Camera properties object. 955 956 Returns: 957 Boolean. True if CONTINUOUS_PICTURE in android.control.afAvailableModes. 958 """ 959 return 4 in props.get('android.control.afAvailableModes', []) 960 961 962def af_scene_change(props): 963 """Returns whether a device supports AF_SCENE_CHANGE. 964 965 Args: 966 props: Camera properties object. 967 968 Returns: 969 Boolean. True if android.control.afSceneChange supported. 970 """ 971 return 'android.control.afSceneChange' in props.get( 972 'camera.characteristics.resultKeys') 973 974 975def multi_camera_frame_sync_capable(props): 976 """Determines if test_multi_camera_frame_sync can be run.""" 977 return all([ 978 read_3a(props), 979 per_frame_control(props), 980 logical_multi_camera(props), 981 sensor_fusion(props), 982 ]) 983 984 985def multi_camera_sync_calibrated(props): 986 """Determines if multi-camera sync type is CALIBRATED or APPROXIMATE. 987 988 Args: 989 props: Camera properties object. 990 991 Returns: 992 Boolean. True if android.logicalMultiCamera.sensorSyncType is CALIBRATED. 993 """ 994 return props.get('android.logicalMultiCamera.sensorSyncType' 995 ) == MULTI_CAMERA_SYNC_CALIBRATED 996 997 998def solid_color_test_pattern(props): 999 """Determines if camera supports solid color test pattern. 1000 1001 Args: 1002 props: Camera properties object. 1003 1004 Returns: 1005 Boolean. True if android.sensor.availableTestPatternModes has 1006 SOLID_COLOR_TEST_PATTERN. 1007 """ 1008 return SOLID_COLOR_TEST_PATTERN in props.get( 1009 'android.sensor.availableTestPatternModes') 1010 1011 1012def color_bars_test_pattern(props): 1013 """Determines if camera supports color bars test pattern. 1014 1015 Args: 1016 props: Camera properties object. 1017 1018 Returns: 1019 Boolean. True if android.sensor.availableTestPatternModes has 1020 COLOR_BARS_TEST_PATTERN. 1021 """ 1022 return COLOR_BARS_TEST_PATTERN in props.get( 1023 'android.sensor.availableTestPatternModes') 1024 1025 1026def linear_tonemap(props): 1027 """Determines if camera supports CONTRAST_CURVE or GAMMA_VALUE in tonemap. 1028 1029 Args: 1030 props: Camera properties object. 1031 1032 Returns: 1033 Boolean. True if android.tonemap.availableToneMapModes has 1034 CONTRAST_CURVE (0) or GAMMA_VALUE (3). 1035 """ 1036 return ('android.tonemap.availableToneMapModes' in props and 1037 (0 in props.get('android.tonemap.availableToneMapModes') or 1038 3 in props.get('android.tonemap.availableToneMapModes'))) 1039 1040 1041def get_reprocess_formats(props): 1042 """Retrieve the list of supported reprocess formats. 1043 1044 Args: 1045 props: The camera properties. 1046 1047 Returns: 1048 A list of supported reprocess formats. 1049 """ 1050 reprocess_formats = [] 1051 if yuv_reprocess(props): 1052 reprocess_formats.append('yuv') 1053 if private_reprocess(props): 1054 reprocess_formats.append('private') 1055 return reprocess_formats 1056 1057 1058def color_space_to_int(color_space): 1059 """Returns the integer ordinal of a named color space. 1060 1061 Args: 1062 color_space: The color space string. 1063 1064 Returns: 1065 Int. Ordinal of the color space. 1066 """ 1067 if color_space == 'UNSPECIFIED': 1068 return -1 1069 1070 return COLOR_SPACES.index(color_space) 1071 1072 1073def autoframing(props): 1074 """Returns whether a device supports autoframing. 1075 1076 Args: 1077 props: Camera properties object. 1078 1079 Returns: 1080 Boolean. True if android.control.autoframing is supported. 1081 """ 1082 return 'android.control.autoframingAvailable' in props and props[ 1083 'android.control.autoframingAvailable'] == 1 1084 1085 1086def ae_regions(props): 1087 """Returns whether a device supports CONTROL_AE_REGIONS. 1088 1089 Args: 1090 props: Camera properties object. 1091 1092 Returns: 1093 Boolean. True if android.control.aeRegions is supported. 1094 """ 1095 return 'android.control.maxRegionsAe' in props and props[ 1096 'android.control.maxRegionsAe'] != 0 1097 1098 1099def awb_regions(props): 1100 """Returns whether a device supports CONTROL_AWB_REGIONS. 1101 1102 Args: 1103 props: Camera properties object. 1104 1105 Returns: 1106 Boolean. True if android.control.awbRegions is supported. 1107 """ 1108 return 'android.control.maxRegionsAwb' in props and props[ 1109 'android.control.maxRegionsAwb'] != 0 1110 1111 1112def preview_stabilization_supported(props): 1113 """Returns whether preview stabilization is supported. 1114 1115 Args: 1116 props: Camera properties object. 1117 1118 Returns: 1119 Boolean. True if preview stabilization is supported. 1120 """ 1121 supported_stabilization_modes = props[ 1122 'android.control.availableVideoStabilizationModes' 1123 ] 1124 supported = ( 1125 supported_stabilization_modes is not None and 1126 STABILIZATION_MODE_PREVIEW in supported_stabilization_modes 1127 ) 1128 return supported 1129 1130 1131def optical_stabilization_supported(props): 1132 """Returns whether optical image stabilization is supported. 1133 1134 Args: 1135 props: Camera properties object. 1136 1137 Returns: 1138 Boolean. True if optical image stabilization is supported. 1139 """ 1140 optical_stabilization_modes = props[ 1141 'android.lens.info.availableOpticalStabilization' 1142 ] 1143 logging.debug('optical_stabilization_modes = %s', 1144 str(optical_stabilization_modes)) 1145 1146 # Check if OIS supported 1147 ois_supported = (optical_stabilization_modes is not None and 1148 LENS_OPTICAL_STABILIZATION_MODE_ON in 1149 optical_stabilization_modes) 1150 return ois_supported 1151