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