1 /* 2 * Copyright 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.camera.camera2.internal; 18 19 import android.graphics.Rect; 20 import android.hardware.camera2.CameraCharacteristics; 21 import android.util.Size; 22 import android.util.SizeF; 23 24 import androidx.annotation.IntRange; 25 import androidx.camera.camera2.internal.compat.CameraAccessExceptionCompat; 26 import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat; 27 import androidx.camera.camera2.internal.compat.CameraManagerCompat; 28 import androidx.camera.core.CameraSelector; 29 import androidx.camera.core.impl.utils.TransformUtils; 30 import androidx.core.util.Preconditions; 31 32 import org.jspecify.annotations.NonNull; 33 34 /** 35 * Contains utility methods related to view angle transformation. 36 */ 37 public class FovUtil { 38 39 private static final String TAG = "FovUtil"; 40 41 // Do not allow instantiation. FovUtil()42 private FovUtil() { 43 } 44 45 /** 46 * Calculates view angle by focal length and sensor length. 47 * 48 * <p>The returned view angle is inexact and might not be hundred percent accurate comparing 49 * to the output image. 50 * 51 * <p>The returned view angle should between 0 and 360. 52 */ 53 @IntRange(from = 0, to = 360) focalLengthToViewAngleDegrees(float focalLength, float sensorLength)54 public static int focalLengthToViewAngleDegrees(float focalLength, float sensorLength) { 55 Preconditions.checkArgument(focalLength > 0, "Focal length should be positive."); 56 Preconditions.checkArgument(sensorLength > 0, "Sensor length should be positive."); 57 58 int viewAngleDegrees = (int) Math.toDegrees( 59 2 * Math.atan(sensorLength / (2 * focalLength))); 60 Preconditions.checkArgumentInRange(viewAngleDegrees, 0, 360, "The provided focal length " 61 + "and sensor length result in an invalid view angle degrees."); 62 63 return viewAngleDegrees; 64 } 65 66 /** 67 * Gets the angle of view of the default camera on the device. 68 * 69 * <p>The default cameras is the camera selected by 70 * {@link CameraSelector#DEFAULT_FRONT_CAMERA} or {@link CameraSelector#DEFAULT_BACK_CAMERA} 71 * depending on the specified lens facing. 72 */ getDeviceDefaultViewAngleDegrees(@onNull CameraManagerCompat cameraManager, @CameraSelector.LensFacing int lensFacing)73 public static int getDeviceDefaultViewAngleDegrees(@NonNull CameraManagerCompat cameraManager, 74 @CameraSelector.LensFacing int lensFacing) { 75 try { 76 String[] cameraIds = cameraManager.getCameraIdList(); 77 for (String cameraId : cameraIds) { 78 CameraCharacteristicsCompat cameraCharacteristics = 79 cameraManager.getCameraCharacteristicsCompat(cameraId); 80 Integer cameraCharacteristicsLensFacing = 81 cameraCharacteristics.get(CameraCharacteristics.LENS_FACING); 82 Preconditions.checkNotNull(cameraCharacteristicsLensFacing, 83 "Lens facing can not be null"); 84 if (cameraCharacteristicsLensFacing == LensFacingUtil.getLensFacingInt( 85 lensFacing)) { 86 return focalLengthToViewAngleDegrees( 87 getDefaultFocalLength(cameraCharacteristics), 88 getSensorHorizontalLength(cameraCharacteristics)); 89 } 90 } 91 } catch (CameraAccessExceptionCompat e) { 92 throw new IllegalArgumentException("Unable to get the default focal length."); 93 } 94 95 throw new IllegalArgumentException("Unable to get the default focal length with the " 96 + "specified lens facing."); 97 } 98 99 /** 100 * Gets the length of the horizontal side of the sensor. 101 * 102 * <p>The horizontal side is the width of the sensor size after rotated by the sensor 103 * orientation. 104 */ getSensorHorizontalLength( @onNull CameraCharacteristicsCompat cameraCharacteristics)105 public static float getSensorHorizontalLength( 106 @NonNull CameraCharacteristicsCompat cameraCharacteristics) { 107 SizeF sensorSize = 108 cameraCharacteristics.get( 109 CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE); 110 final Rect activeArrayRect = 111 cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 112 Size pixelArraySize = cameraCharacteristics.get( 113 CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE); 114 final Integer sensorOrientation = 115 cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); 116 Preconditions.checkNotNull(sensorSize, "The sensor size can't be null."); 117 Preconditions.checkNotNull(sensorOrientation, "The sensor orientation can't be " 118 + "null."); 119 Preconditions.checkNotNull(activeArrayRect, "The active array size can't be null."); 120 Preconditions.checkNotNull(pixelArraySize, "The pixel array size can't be null."); 121 122 Size activeArraySize = TransformUtils.rectToSize(activeArrayRect); 123 if (TransformUtils.is90or270(sensorOrientation)) { 124 sensorSize = TransformUtils.reverseSizeF(sensorSize); 125 activeArraySize = TransformUtils.reverseSize(activeArraySize); 126 pixelArraySize = TransformUtils.reverseSize(pixelArraySize); 127 } 128 129 return sensorSize.getWidth() * activeArraySize.getWidth() / pixelArraySize.getWidth(); 130 } 131 132 /** 133 * Gets the default focal length from a {@link CameraCharacteristics}. 134 * 135 * <p>If the camera is a logical camera that consists of multiple physical cameras, the 136 * default focal length is the focal length of the physical camera that produces image at 137 * zoom ratio {@code 1.0}. 138 */ getDefaultFocalLength( @onNull CameraCharacteristicsCompat cameraCharacteristics)139 public static float getDefaultFocalLength( 140 @NonNull CameraCharacteristicsCompat cameraCharacteristics) { 141 final float[] focalLengths = 142 cameraCharacteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS); 143 Preconditions.checkNotNull(focalLengths, "The focal lengths can not be empty."); 144 145 // Assume the first focal length is the default focal length. This will not be true if the 146 // camera is a logical camera consist of multiple physical cameras and reports multiple 147 // focal lengths. However for this kind of cameras, it's suggested to use zoom ratio to 148 // do optical zoom. 149 return focalLengths[0]; 150 } 151 } 152