Android 在没有额外计算的情况下,默认情况下,Camera或camera2 API返回4:3纵横比的FOV角度值?

Android 在没有额外计算的情况下,默认情况下,Camera或camera2 API返回4:3纵横比的FOV角度值?,android,camera,android-camera,android-camera2,Android,Camera,Android Camera,Android Camera2,我可以使用传统的cameraAPI或camera2API(无所谓)获得摄影机视图的水平和垂直角度,值相同 但水平角度仅适用于4:3纵横比相机预览(例如640x480分辨率) 如果我们使用全高清预览尺寸(例如1920x1080分辨率,16:9纵横比)启动相机,则此分辨率的值不正确 不久前我发现了一个解决方案(),它做了一些数学运算,根据已知的相机预览纵横比和垂直角度值(不需要原始水平角度值)重新计算角度,我们可以得到特定纵横比的水平和垂直角度 下面是完整的工作代码: val cameraManag

我可以使用传统的
camera
API或
camera2
API(无所谓)获得摄影机视图的水平和垂直角度,值相同

但水平角度仅适用于4:3纵横比相机预览(例如640x480分辨率)

如果我们使用全高清预览尺寸(例如1920x1080分辨率,16:9纵横比)启动相机,则此分辨率的值不正确

不久前我发现了一个解决方案(),它做了一些数学运算,根据已知的相机预览纵横比和垂直角度值(不需要原始水平角度值)重新计算角度,我们可以得到特定纵横比的水平和垂直角度

下面是完整的工作代码:

val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
val cameraCharacteristics = cameraManager.getCameraCharacteristics("0") // hardcoded first back camera

val focalLength = cameraCharacteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)?.firstOrNull() ?: return
val sensorSize = cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE) ?: return
val horizontalAngle = (2f * atan((sensorSize.width / (focalLength * 2f)).toDouble())) * 180.0 / Math.PI
val verticalAngle = (2f * atan((sensorSize.height / (focalLength * 2f)).toDouble())) * 180.0 / Math.PI
// using camera2 API we got the same data as with legacy Camera API (with it was easier):
// val parameters = camera.getParameters()
// val horizontalAngle = parameters.getHorizontalViewAngle()
// val verticalAngle = parameters.getVerticalViewAngle()

// but usually only vertical angle value is correct here
// horizontal angle value is correct only for 4:3 aspect ratio
// so we need do some math to get correct horizontal angle for example for 16:9 aspect ratio
// usually the widest one on smartphones

val streamConfigurationMap = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!!
val resolutions = streamConfigurationMap.getOutputSizes(SurfaceTexture::class.java)

// get camera size with highest aspect value
val previewSize = resolutions.maxByOrNull { it.width.toFloat() / it.height.toFloat() }!!
val width = previewSize.width.toDouble()
val height = previewSize.height.toDouble()
val aspect = width / height // or hardcode it to "16 / 9" if you need to find out angles at specific ratio
val zoom = 100.0 // 100 == default 1.0 (no zoom), you can get zoom using camera and camera2, for camera2 you have to multiple it by 100
var verticalAngle2 = Math.toRadians(verticalAngle)
var horizontalAngle2 = 2.0 * atan(aspect * tan(verticalAngle2 / 2))
verticalAngle2 = Math.toDegrees(2.0 * atan(100.0 * tan(verticalAngle2 / 2.0) / zoom))
horizontalAngle2 = Math.toDegrees(2.0 * atan(100.0 * tan(horizontalAngle2 / 2.0) / zoom))

Timber.d("FOV: ${horizontalAngle}x${verticalAngle} (original 4:3) vs ${horizontalAngle2}x$verticalAngle2 (recalculated), width: $width, height: $height, aspect ratio: $aspect")
看起来还可以,但我想知道这个方法有多正确

对于我的三星S10,它打印:

  • 通用后(后)摄像头(“0”id):
视野:66.31770290433023x52.21398560685136(原4:3)vs 82.1243306411032x52.21398506685136(重新计算),宽度:1920.0,高度:1080.0,纵横比:1.7777

  • 超宽镜头后(后)摄像头(“2”id):
104.00253387238499x87.66172361901917(原4:3)对119.26472801785447x87.66172361901917(重新计算),宽:1920.0,高:1080.0,宽高比:1.7777

对于此设备,我在internet上找到了下一个信息:

三星Galaxy S10-配备三重后置摄像头(长焦镜头12mp f/2.4,45度视角,广角12mp双像素AF f/1.5-2.4 OIS 77度视角,超宽16mp FF,f/2.2 123 度数(视角)

因此,此信息和我的代码中的水平角度值(在16:9纵横比的情况下)不匹配100%,但仍然相似

我还可以在此设备上启动相机预览,并手动计算FOV(无需编程)


我稍后会这样做,并在此处添加信息(在1920x1080相机尺寸预览、16:9、无缩放1.0、无视频稳定(可裁剪相机帧、无限聚焦)的情况下,我在手动计算后得到的值)

为什么您认为FOV值仅适用于4:3?对于camera2,它们对完整的像素阵列有效,像素阵列可以具有任何纵横比(但通常为4:3)。camera2的裁剪规则意味着4:3传感器的16:9裁剪将具有相同的水平视野,但具有不同的(较小的)垂直视野。@EddyTalvala基于此答案(纵横比)垂直视野没有改变,水平视野正在改变(对于不同的纵横比)