我正在尝试确定 Droid Incredible 智能手机相机的视场度数。我需要知道我正在开发的应用程序的这个值。有谁知道我如何以编程方式找出/计算它?
3 回答
Camera.Parameters getHorizontalViewAngle() 和 getVerticalViewAngle() 函数为您提供基本视角。我说“基础”,因为这些仅适用于处于未缩放状态的相机本身,并且即使视角本身发生变化,这些函数返回的值也不会改变。
Camera.Parameters p = camera.getParameters();
double thetaV = Math.toRadians(p.getVerticalViewAngle());
double thetaH = Math.toRadians(p.getHorizontalViewAngle());
有两件事会导致您的“有效”视角发生变化:缩放和使用与相机纵横比不匹配的预览纵横比。
基础数学
视场 (Θ) 的三角函数相当简单:
tan(Θ/2) = x / 2z
x = 2z tan(Θ/2)
x 是在距离 z 处可见的线性距离;即,如果您在距离 z=1 米处举起尺子,您将能够看到该尺子的 x 米。
例如在我的相机上,水平视野是 52.68°,而垂直视野是 40.74°。将这些转换为弧度并将它们代入公式中,任意 z 值为 100m,得到的 x 值为 99.0m(水平)和 74.2m(垂直)。这是 4:3 的纵横比。
飞涨
将此数学应用于缩放级别只是稍微困难一些。现在,x 保持不变,而 z 以已知比率变化;我们必须确定 Θ。
tan (Θ/2) = x / (2z)
tan (Θ'/2) = x / (2z')
Θ' = 2 atan((z / z') tan(Θ/2))
其中 z 是基本缩放级别 (100),z' 是当前缩放级别(来自 CameraParameters.getZoomRatios),Θ 是基本水平/垂直视野,Θ' 是有效视野。添加度数->弧度转换使这相当冗长。
private static double zoomAngle(double degrees, int zoom) {
double theta = Math.toRadians(degrees);
return 2d * Math.atan(100d * Math.tan(theta / 2d) / zoom);
}
Camera.Parameters p = camera.getParameters();
int zoom = p.getZoomRatios().get(p.getZoom()).intValue();
double thetaH = zoomAngle(p.getHorizontalViewAngle(), zoom);
double thetaV = zoomAngle(p.getVerticalViewAngle(), zoom);
纵横比
虽然典型的相机是 4:3 的纵横比,但预览也可能以 5:3 和 16:9 的比例提供,这似乎是通过实际扩展水平视野来实现的。这似乎没有记录,因此不可靠,但通过假设它是如何工作的,我们可以计算视野。
数学类似于缩放计算;但是,在这种情况下,z 保持不变,而变化的是 x。通过假设垂直视角保持不变,而水平视角随着纵横比的变化而变化,就可以计算出新的有效水平视角。
tan(Θ/2) = v / (2z)
tan(Θ'/2) = h / (2z)
2z = v / tan(Θ/2)
Θ' = 2 atan((h/v) tan(Θ/2))
这里 h/v 是纵横比,Θ 是基本垂直视野,而 Θ' 是有效水平视野。
Camera.Parameters p = camera.getParameters();
int zoom = p.getZoomRatios().get(p.getZoom()).intValue();
Camera.Size sz = p.getPreviewSize();
double aspect = (double) sz.width / (double) sz.height;
double thetaV = Math.toRadians(p.getVerticalViewAngle());
double thetaH = 2d * Math.atan(aspect * Math.tan(thetaV / 2));
thetaV = 2d * Math.atan(100d * Math.tan(thetaV / 2d) / zoom);
thetaH = 2d * Math.atan(100d * Math.tan(thetaH / 2d) / zoom);
正如我上面所说,由于这似乎没有记录,因此只是猜测它将适用于所有设备;它应该被认为是一种黑客行为。正确的解决方案是拆分一组新的函数 getCurrentHorizontalViewAngle 和 getCurrentVerticalViewAngle。
除非有一些 API 调用(我不是 Android 程序员,我不知道),否则我会从已知距离拍一张尺子的照片,看看图中显示了多少尺子,然后使用三角法找到这样的角度:
现在你有两个距离 l 和 d 从图中。通过一些简单的测角,可以得到:
tan(α/2) = (l/2)/d,
因此
α = 2*atan(l/2d)
因此,使用此公式,您可以计算相机的水平视野。当然,测量垂直 fov 的方式完全相同,只是您需要在垂直位置查看对象。
然后,您可以将其硬编码为程序中的常量。(当然是一个命名常量,所以很容易改变:-p)
我也有一个 Droid Incredible。Android 2.2 引入了您正在寻找的功能。在我的代码中,我有:
public double getHVA() {
return camera.getParameters().getHorizontalViewAngle();
}
public double getVVA() {
return camera.getParameters().getVerticalViewAngle();
}
但是,这些要求您打开相机。我很想知道是否有一种“最佳实践”方式不必每次都打开相机来获取这些值。
@David Zaslavsky - 怎么样?缩放级别之间的数学关系是什么?我在任何地方都找不到它(我在这个问题中问过:Android 相机缩放数字在数学上代表什么?)