65.9K
CodeProject 正在变化。 阅读更多。
Home

测量地球的扁平度

2023年4月1日

CPOL

17分钟阅读

viewsIcon

13075

downloadIcon

112

如何判断地球是平的还是不平的?只需使用提供的应用程序和数码相机。

目录

Do you still believe in spherical Earth?

引言
海浪法
想法
基本计算
考虑镜头畸变
考虑波浪谱
考虑波浪形状
考虑空气折射
沙丘图案法
建议
云层图案法
蓝天渐变法
想法
计算
建议
用法
通用摄影建议
使用应用程序
实现
源代码隔离
WPF 主程序
软件兼容性和构建
未来研究
文学
许可说明

引言

关于地球是平坦的还是球形凹陷形状的争论越来越激烈。

然而,这两组观点之间的争论似乎都不可信。平地论者不相信出版物中提供的证据,因为众所周知,政府总是隐瞒真相。另一方面,相信地球是球形的人也认为不应相信直接的感知。

这里的问题是:双方都认为无法进行不依赖任何外部数据、可负担且可验证的直接独立实验。这种假设不仅是错误的——而且是荒谬的。在过去,当现代计算机尚未出现,摄影技术也不够先进时,这种假设是合理的。

如今,我们只需要一台性能不错的数码相机和一台计算能力足够高的电脑。利用本文提供的应用程序,我们可以获取地球表面特征图案的透视图像,并对不同距离和角度看到的特征进行图像识别和统计处理。在本文中,我将解释这是如何实现的。

我们将讨论四种截然不同的方法。前两种方法基于海浪或沙丘的图案。从软件的角度来看,海浪和沙丘方法是相同的,只是拍摄说明略有不同。另外两种方法使用云层图案和晴朗蓝天的渐变。第一种方法最重要,所以我们先从海浪开始。

海浪法

要使用这种方法,我们可以用数码相机拍摄海面。我们需要拍摄一些表面上的重力波,如图 图 1 所示。

Angles

图 1 - 使用数码相机拍摄表面波浪的波峰

想法

在图 1 中,我们将数码相机放置在海平面以上高度 `h`。其镜头的 the main optical axes 应严格垂直于地球的重力向量 `G`。地球的半径为 `R`。在地球平坦的特殊情况下,我们得到一条红色的水平直线。

现在,让我们拍摄海面上带有重力波的海面。让我们注意一下在数码照片上看到的波浪的角度大小。它们由三个因素定义:1) 实际波长,2) 到观察到的波峰的距离,2) 以及透视效果,由波峰位置的局部垂直方向与视线之间的角度定义。地球的曲率以相同方向影响最后两个因素:曲率越大,观察到的波峰距离随视角 `α` 减小的速度越快,并且透视角度 `β` 增长得越快,因此,一对波峰的观测角度大小随着 `α` 的增大而减小得越快。

作为比较,请看图 1 中所示的两对物体,它们是地球平坦(用红线表示)的两个绿色点对,以及地球弯曲的两个黄色点对。在弯曲的地球上,两对物体相同的角度大小对应于弯曲地球上黄色点对之间更大的实际距离。因此,地球的曲率越大,在地球表面上观察到的物体的大小就越小。这个效应是计算地球曲率的基本因素。

基本计算

为了计算视距和透视效果角度,让我们像图 2 中那样进一步夸大地球的曲率。

Angles

图 2 - 视距和透视效果角度的计算

在图 2 中,A 点是相机的位置,B 点是两个相邻波峰的位置,C 是地球的中心。在三角形 ABC 中,角度 `∠CAB` 是已知的,等于 `π/2` - `α`,并且两条边是已知的:`AC = R + h` 和 `CB = R`,其中 `R` 是地球半径,`h` 是相机在海平面以上的高度。在观测到的波峰位置的切线用红色表示。

两个已知边和一个已知角完全确定了三角形 `ABC`。从这个三角形,我们计算视距 `l = AB` 和透视效果角度 `π/2` - `β`。

现在我们需要计算波峰(图 1 中的黄色点)之间的角度距离 `γ`。我们需要考虑透视效果

Foreshortening

图 3 - 透视效果

如果波峰之间的距离(图 1 中的黄色点)是 `p`,给定视距 `d = AB`,观测到的波浪的角度大小是 `p/d cos β`。这个大小与两个波峰的观测图像成正比,正如它们出现在相机传感器上一样。

该软件通过图像识别检查波峰之间所有观测到的角度距离,并收集这些值随视角 `α` 变化的统计分布。地球半径 `R`(可能是无穷大)是该分布的参数。该软件对分布进行建模,并使用 `R` 作为参数来拟合观测到的分布。最佳拟合结果就是 `R` 的值,即地球表面的曲率。

上述计算是简化的,因为它忽略了一些重要因素。这些因素可能会严重影响 `R` 的最终值,因此我们需要将它们考虑在内。

考虑镜头畸变

没有任何光学系统是没有像差的。我们需要关注的像差类别是图像畸变

镜头畸变的具体效果是,它的效果类似于地球曲率。桶形畸变会产生凹陷弯曲地球的视觉效果,而表面实际上是完全平坦的。枕形畸变会减小地球的视观曲率。同时,一个具有明显畸变的优质镜头不会引入太多图像模糊,而这一点是最重要的。

幸运的是,畸变很容易补偿以获得更正的计算。尽管推荐使用长焦镜头,但它也无法完全消除畸变。为了考虑畸变,需要镜头模型。该软件从相机生成的文件的EXIF信息中获取这些数据。

拥有相机规格后,该软件会使用已知镜头的数据库来获取光学系统特性。因此,推荐使用知名优质镜头。

考虑波浪谱

基本计算的解释中,我们假设我们知道波长。然而,实际上,并没有固定的波长,而是一整个不同波长的谱。为了考虑这个谱,我们首先需要将考虑范围限定在重力波,而不考虑毛细波重力-毛细波,并且只考虑深水波。

海浪的分类可以在[1] 中找到。

对于波浪谱的建模,我们使用了[2] 中解释的计算。

考虑波浪形状

波浪形状重要吗?在图 4 中,我们可以看到实际的波峰距离和在某个视角(图 1 和图 2 中的角度 `α`)下观察到的距离之间存在微小差异。

尽管差异很微妙,但显而易见,图像的形状在观察中确实会产生一些差异。为了将这一点考虑在内,该软件使用了[3] 中解释的波浪剖面计算。

Wave

图 4 - 重力表面波剖面

考虑空气折射

基本计算的解释中,我们假设光学计算中的直线实际上是直的。这也是一个巨大的简化。实际上,我们需要考虑地球大气层的空气折射。

对于大气折射的建模,该软件使用了NASA[4] 中描述的改进模型。目前,该模型主要用于卫星激光测距。

这是一个地理定位非常有用之处。如果EXIF 中提供了地理定位数据,软件会联系拍照地点附近的天气数据中心,并提取拍摄时该地点的天气信息。然后,天气信息用于校正折射参数。

沙丘图案法

沙丘图案法在所有方面都与海浪法相似。主要区别在于相机高度应相对于平均地表高度计算,而不是相对于海平面,这可能是一个问题。

此方法存在的问题是,您需要使用平均平坦的地表,或者用于支持地球假想球形形状的地表。出于自然原因,这样的土地确实存在,但这使得该方法不太适合争论。平地论者会争辩说,相信地球是球形的人可能已经地球改造了土地以支持他们的观点,而相信地球是球形的人可能会怀疑他们的对手已经将其夷为平地。

然而,该方法对于那些想自己进行实验,但又无法获得其他方法所需条件的人来说是合适的。

建议

  1. 避免在沙虫(巨型沙虫)活动期间拍照。这些动物可能会引起相机振动,破坏要拍摄的表面。
  2. 避开流沙区域。此类摄影需要缓慢移动的沙子。请注意,三脚架和相机沉入会使相机高度 `h` 的确定不可靠。
  3. 如果您遇到塔斯肯掠夺者,请记住沙地人很容易受惊,但他们很快就会回来,而且人数更多。

云层图案法

云层图案法也与海浪法类似,但算法不同,因为我们必须处理凹面而不是凸面。我们不是观察海浪,而是观察由云形成的类似规则的图案。

Clouds

图 5 - 云层图案

[5] 中可以找到合适的云结构示例。通常在卷云形成规则图案时会出现这种情况。

另一种有趣的可能性是利用由开尔文-亥姆霍兹不稳定性产生的云。例如,也可以参考[6]

此外,由于尺度不同,相机需要向上倾斜 `π/4`。然而,所有的推理和几何构造在很大程度上都是类比的。读者可以根据海浪法的描述轻松重现它们。

与其他方法不同,对于此方法,相机传感器质量和光学分辨率不太关键。另一方面,该方法对相机倾斜敏感,即相机围绕镜头的 the main optical axes 旋转。

此方法精度较低,并且需要特殊的、非常罕见的天气条件,但摄影起来要容易得多。

蓝天渐变法

这是迄今为止最优雅、最简单的实验条件下的方法。同时,计算是最复杂的。要使用此方法,我们只需在晴朗的白天拍摄蓝天。

想法

观察到的蓝天归因于瑞利散射。光波在空气密度波动上散射,而空气密度波动反过来又导致空气折射率波动。

任何人都可以观察到蓝天的渐变。天顶处的蓝天颜色更深,而在天空圆顶的边缘,颜色则更浅。这种渐变取决于假想的地球曲率,并且对于平坦地球模型确实存在。

显而易见,这种渐变取决于地球的曲率。在图 6 中,我们可以考虑太阳在天顶的例子。在这种情况下,更高的地球曲率会使渐变效果不那么明显,因为一部分散射光来自地平线附近较薄的空气层,而一部分阳光穿过地平线以下的区域。

Sky

图 6 - 瑞利散射和蓝天渐变

计算

当阳光穿过地球大气层时,它会在大气层的每个点向各个方向散射,但每个相机像素收集的是朝向相机的光。要计算像素值,我们需要对散射光的量进行积分,并根据 R、G、B 像素的灵敏度进行加权。积分的空间是地球表面到无穷远,由于大气分子密度分布,积分会收敛。

我使用了关于模拟天空颜色的文章[7] 中描述的方程和推理。但是,软件算法是不同的。软件不是计算天空颜色,而是使用相机记录的颜色,并利用它们与地球半径(该值包括可能的无穷大值)的依赖关系来找到最符合测量到的渐变模式的半径。

建议

  1. 使用晴天。
  2. 仅在雨后的中午晴朗时段进行拍摄,以确保空气尽可能清洁。
  3. 使用标准镜头,不要使用任何滤镜或镜头上的其他附件。
  4. 更重要的是,不要使用任何偏振滤镜。
  5. 远离烟雾、喷发的火山和龙卷风。
  6. 此外,远离不明飞行物(UFO)飞行区域。UFO 的运行基于以太的扭曲,并导致额外的光折射,称为以太折射,这会扰乱正常的瑞利散射模式。UFO 的机制是一个单独的文章主题。
  7. 将相机设置好,使其镜头的 the main optical axes 严格垂直于地球重力向量。尽可能使用相机内置的加速度计。

用法

通用摄影建议

  1. 尝试使用带加速度计/倾角计、遥控器和地理定位功能的相机。
  2. 始终使用三脚架。
  3. 所有方法都需要一个长焦距镜头,100 毫米及以上。云层图案法除外,它在短焦距镜头(50 毫米至鱼眼镜头)下效果更好。
  4. 镜头质量很重要。避免使用无名镜头,因为镜头型号应该记录在EXIF 元数据中。软件会查阅镜头数据库,并使用镜头特性来考虑畸变。
  5. 另一方面,避免使用直线“建筑”镜头和其他设计过于复杂的镜头。镜头无畸变特性完全无用,并且由于软件会补偿畸变,因此会降低测量质量。对于过于复杂的镜头,软件补偿畸变极其困难。软件处理后,鱼眼镜头的结果精度优于直线镜头。
  6. 使用手动或光圈优先模式。
  7. 可以使用一张照片。但是,如果可能,请使用延时摄影(https://en.wikipedia.org/wiki/Time-lapse_photography),并提供至少 1-2 千张图像。收集的统计数据越多,结果的准确性就越高。

使用应用程序

使用方法非常简单:加载一个或多个图像文件,然后单击 Process/Run。

Application

图 7 - 应用程序

该应用程序使用起来非常简单。它只有 5 个菜单命令:File/Load Source Images…、File/Exit、Process/Start、Process/Cancel 和 Help/About。这是典型的工作流程。

  1. 下载并安装当前的 .NET,从 .NET 5 开始的任何版本都可以。
  2. 运行 Curvature.exe。
  3. 使用 File/Load Source Images… 加载单个图像或一组延时图像。大约 1000 张图像的集合是接近最优的。将显示该集合的第一张图像。
  4. 使用主菜单下方的单选按钮组选择合适的方法。
  5. 使用 Process/Start 菜单命令开始处理。
  6. 如果出现问题,请使用 Process/Cancel 重新开始。如果需要重新加载图像,可以这样做。
  7. 通过查看图像上显示的进程阶段的图形指示来观察进度。
  8. 在处理过程中,应用程序保持响应,您可以调整应用程序窗口大小、取消处理等。
  9. 如果有些地方不清楚,请使用 Help/About。

如果您有足够的耐心等待处理完成,您将看到计算结果。享受吧!

实现

在实现部分,我们仅概述一些有趣且通用的技术。

源代码隔离

从标准模板创建的 .NET 解决方案和项目会生成源代码和构建工件的混合体。这非常不方便。源代码应完全隔离。可以通过在解决方案文件同级目录中放置文件“Directory.Build.props”来解决此问题。在此文件中,可以定义中间文件和输出文件的目录,使其位于源代码目录之外,并且源代码目录始终保持不变。

这种方法的一个额外好处是避免了生成的可执行文件的重复。

“Directory.Build.props”

<Project>
 
    <PropertyGroup>
        <BaseIntermediateOutputPath>$(SolutionDir).intermediateOutput\$(MSBuildProjectName)\$(Configuration).$(Platform)</BaseIntermediateOutputPath>
        <OutputPath>$(SolutionDir)\output.$(Configuration).$(Platform)</OutputPath>
        <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
        <ProduceReferenceAssembly>false</ProduceReferenceAssembly>
        <TargetFramework>net5.0-windows</TargetFramework>

        <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
        <WarningsAsErrors />

        <RootNamespace>SA</RootNamespace>
        <Copyright>Copyright © 2023 Sergey A Kryukov</Copyright>
        <Product>Measurements of Earth's Flattness</Product>
        <Description>Measurements of Earth's Flattness, April 1st Article for Code Project</Description>
        <Authors>Sergey A Kryukov</Authors>

        <AssemblyVersion>1.0.0.0</AssemblyVersion>
        <FileVersion>1.0.0.0</FileVersion>
        <Version>1.0.0.0</Version>
        <InformationalVersion>1.0.0.0</InformationalVersion>

    </PropertyGroup>
</Project>

这种方法的另一个好处是可以统一所有项目的公共属性,例如产品名称、作者、版权和版本信息。当需要时,某些项目属性可以在各个项目级别被覆盖。

WPF 主程序

从标准模板创建的 WPF 项目没有入口点方法 `main`。实际上,它确实有,但不是由作者明确编写的。而是从 XAML 数据生成,然后编译。必需的源文件是“app.xml”。

我无法接受这个特性。我知道许多需要显式访问 `Main` 的情况。我不明白为什么依赖近乎无用的“app.xml”。如果需要保留项目范围的资源,这不是一个好理由,因为最好有单独的资源 XAML 文件并重复使用它们。

这个问题已经解决了。具有入口点 `Main` 的文件是“Main/main.cs”。

namespace SA.Main {

    static class ApplicationStart {
        [System.STAThread]
        static void Main() {
            View.WindowMain.AddKeyGestures(); // trivial reason to use Main
            new UI.AdvancedApplication<View.WindowMain>().Run();
        } //Main
    } //class ApplicationStart

}

在这里,我们扩展了“Main/AdvancedApplication.cs”中的 `Application` 类。这是一个泛型类,使用应用程序主窗口的类型作为泛型参数 `MAINVIEW`。

namespace SA.UI {
    using System;
    using System.Windows;
    using System.Reflection;

    public abstract class AdvancedApplicationBase : Application {
        private protected abstract Window CreateMainWindow();
        protected override void OnStartup(StartupEventArgs e) {
            this.ShutdownMode = ShutdownMode.OnMainWindowClose;
            var mainWindow = CreateMainWindow();
            MainWindow = mainWindow;
            mainWindow.Title = DefinitionSet.formatTitle(ProductName);
            mainWindow.Show();
            base.OnStartup(e);
            startupComplete = true;
        } //OnStartup
        // ...
    } //AdvancedApplicationBase
    
    // ...
    
    public class AdvancedApplication<mainview> :
        AdvancedApplicationBase where MAINVIEW : Window, new() {
        private protected override Window CreateMainWindow() {
            MAINVIEW mainWindow = new();
            if (mainWindow is IExceptionPresenter exceptionPresenter)
                base.exceptionPresenter = exceptionPresenter;
            return mainWindow;
        }
    } //class AdvancedApplication

}

`AdvancedApplicationBase` 类还有许多其他高级功能。首先,它用于检索应用程序级别的元数据,例如产品名称、描述、作者、版权和版本信息。这些信息可以在“Directory.Build.props”或任何单个项目文件中定义。

软件兼容性和构建

该软件基于跨平台 .NET,版本 5 或更高版本。目标版本可以通过编辑“Directory.Build.props”文件中的 `<TargetFramework>` 属性来修改。由于使用了 WPF,因此只能构建 Windows 版本。其他平台的 UI 前端是完全可能的,如果用户需要,可以予以考虑。

也可以使用已弃用的 .NET Framework,但然后用户需要为此目的创建一个单独的“.csproj”文件。

提供了批量构建和清理功能,请使用文件“build.cmd”和“clear.cmd”。通过批量构建,不需要 Visual Studio 或任何其他 IDE。

未来研究

下一研究阶段将包括测量龟壳的曲率以及支撑地球的三头大象的质量。

文学

  1. Hilmar Hofmann,《Characteristics and implications of surface gravity waves in the littoral zone of a large lake
  2. Michael S. Schwendeman 和 Jim Thomson,《Sharp-Crested Breaking Surface Waves Observed from a Ship-Based Stereo Video System
  3. Mats Ehrnstrom,《A Note on Surface Profiles for Symmetric Gravity Waves with Vorticity
  4. G. Hulley 和 E. C. Pavlis,《Improvement of Current Refraction Modeling in Satellite Laser Ranging (SLR) by Ray Tracing through Meteorological Data
  5. M. Paperin,《Cloud Structures
  6. Kelvin-Helmholtz clouds look like ocean waves》,Earth Sky
  7. Simulating the Colors of the SkyScratchapixel,源代码可在GitHub 查看。

许可说明

Code Project Open License 外。

所有图像均为原创,由文章作者从头开始创作。

© . All rights reserved.