I can get horizontal and vertical angles of camera view using legacy Camera
API or camera2
API (doesn't matter), same values.
But horizontal angle is correct only for 4:3 aspect ratio camera preview (for example 640x480 resolution).
If we start camera with Full HD preview size (for example 1920x1080 resolution, 16:9 aspect ratio) then such value is incorrect for this resolution.
Sometime ago I found a solution (https://mcmap.net/q/523460/-determine-angle-of-view-of-smartphone-camera) which does a little math to recalculate angles based on known camera preview aspect ratio and vertical angle values (original horizontal angle value is not needed) and we can get both horizontal and vertical angles for a specific aspect ratio.
So here's the full working code how to do it:
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")
It seems ok, but I would like to know for sure how correct this method is
For my Samsung S10 it prints:
- General rear (back) camera ("0" id):
FOV: 66.31770290433023x52.21398560685136 (original 4:3) vs 82.1243306411032x52.21398560685136 (recalculated), width: 1920.0, height: 1080.0, aspect ratio: 1.7777777777777777
- Ultra-wide lens rear (back) camera ("2" id):
104.00253387238499x87.66172361901917 (original 4:3) vs 119.26472801785447x87.66172361901917 (recalculated), width: 1920.0, height: 1080.0, aspect ratio: 1.7777777777777777
For this device I found the next info on the internet:
Samsung Galaxy S10 - featuring a triple rear camera (telephoto 12mp f/2.4, 45-degree angle of view, wide-angle 12mp dual pixel AF f/1.5-2.4 OIS 77 degree angle of view, Ultra-wide 16mp FF, f/2.2 123 degrees angle of view)
So horizontal angle values from this info and my code (in case of 16:9 aspect ratio) don't match 100% but still are similar.
I can also start camera preview on this device and calculate FOV manually (without programming) https://mcmap.net/q/523460/-determine-angle-of-view-of-smartphone-camera
I will do it later and add info here (which values I got after manual calculation in case of 1920x1080 camera size preview, 16:9, no zoom 1.0, no video stabilization which can crop camera frames, infinity focus)