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