构建一款可视化工具,可连续滚动显示在任意两个地点之间航线上拍摄的空中影像
飞机舷窗外的景色总是令人着迷。在漫长的飞行过程中,下方的地形会从城市、山脉、农田到海岸线不断变换。
每一次向外望去,眼前的景象都与上一次截然不同,为你提供了一个安静而无限的机会,去捕捉独特的地标,或悠闲地欣赏地貌的变化。
PyPortal 飞行器视角查看器旨在将这种天空中的观景体验带入桌面环境。
它可在 PyPortal 设备上展示两处用户自定义位置之间的连续滚动空中影像。沿途的真实景观会缓慢平移,呈现出动态的飞行过场效果。
单次飞行过场可能覆盖数千英里,耗时数小时,因此 PyPortal 飞行器视角查看器成为一款引人注目、持续变化的桌面装饰,全天候运行。
查看器功能
核心硬件组件为 Adafruit PyPortal。它配备了一块3.2英寸彩色TFT显示屏,带有电阻式触摸屏和兼容CircuitPython的微控制器。
PyPortal安装在3D打印的框架内。用户可使用打印支架或后置支架,将框架水平放置于桌面,或垂直安装在墙上。
用户可通过编辑并运行生成器脚本来创建自定义的航拍图像条带,并让其在屏幕上滚动播放。起始位置、结束位置以及缩放级别参数控制着航拍路线的直线路径和视觉细节。
例如,从加利福尼亚州旧金山飞往内华达州拉斯维加斯的航拍画面,在低缩放级别下会生成一条覆盖400英里距离的空中影像条带,沿途可见加州中央谷地的农田以及死亡谷国家公园的沙漠景观。
而从洛杉矶到纽约市的全国性航拍,则呈现出不断变化的地形,包括落基山脉、大平原以及东海岸密集的城市中心地带。这段跨国旅程需要连续滚动近两天半才能完成。
航拍图像采用“轨迹跟随”方式生成,即航拍画面会旋转以与行驶方向保持一致。当沿着屏幕的长轴滚动时,效果仿佛从上方飞行穿越路线。
当用户开启设备后,加载的航拍画面会从黑色逐渐淡出,显示起始位置的图像,并开始缓慢地在屏幕上滚动。
用户可触摸屏幕左侧(竖屏模式下为上半部分)来切换四种不同的亮度设置,或触摸右侧(竖屏模式下为下半部分)来切换五种不同的滚动速度。
动画将持续到终点位置进入视野为止。当航拍路径结束时,屏幕将逐渐变黑,然后无缝重启旅程。
航拍可视化
一条航拍路线可能长达数千英里,需要数百万像素、数吉字节大小的图像条带。
构建和存储此类图像超出了PyPortal微控制器的能力。为解决这一问题,系统使用两个独立设备上的两个不同进程分别完成航拍图像的生成与显示。
首先,一个Python生成器脚本在计算机上运行,负责下载并整合航拍图像,将其组装成一个单一的数据文件。然后,PyPortal上的脚本读取该数据文件,以渲染滚动动画。
以下各部分将详细说明每个步骤。
飞行路线生成
用户可在完整计算机上运行项目中的generate_flyover.py脚本,以生成飞行路线的图像条带。在运行脚本之前,用户需编辑三个变量来配置输出参数。
START和END定义为纬度和经度坐标对,这两个点必须位于美国境内,用于控制飞行路线的直线路径。
ZOOM定义为13到16之间的整数值,它设定所请求航拍图像的Web墨卡托缩放级别,从而决定飞行路线的地面分辨率和横跨轨道宽度。
较高的缩放值会缩小横跨轨道的覆盖范围,并增加可见细节;而较低的缩放值则会扩大该范围,降低每像素的细节。
图像条带的航拍影像来自美国地质调查局(USGS)国家地图服务,该服务是公共领域资源,通过REST API提供覆盖美国的正射影像。
脚本首先将两个点的经纬度坐标转换为Web墨卡托投影。采用这种投影方式,在给定缩放级别下像素尺寸保持一致,从而便于计算路线几何形状,并使图像请求与服务器坐标系统对齐。
随后计算投影后两点之间的直线距离,以确定所选缩放级别下图像条带的总像素长度。
由于该长度可能跨越数千个像素,因此无法在单次API请求中获取所有所需影像。为此,脚本将路线划分为固定宽度的1024像素段进行逐段处理。
每个段的地理空间范围根据其在路线上的位置、图像条带高度以及路线方位角来计算。
该范围可任意旋转角度,但影像均以北朝上方向的矩形格式下载。为处理这一情况,会计算出一个包含足迹区域(并添加几像素的缓冲区)的最小地图对齐边界框。
该边界框连同坐标系(Web Mercator)、输出格式(JPG)以及像素尺寸(由缩放比例推导得出),作为参数传递给美国地质调查局(USGS)影像服务器。服务器将返回一张覆盖该路段足迹区域的航拍图像。
通过仿射变换从下载的图像中提取该段足迹区域,这是一种单次操作,可旋转和裁剪像素,并使用双线性插值以保留细节。
这生成了一条经过处理的图像条带,分辨率为1024 × 240像素,采用轨迹向上方向,行驶方向为从左到右,路线中心线位于中间行。
将该段的像素数据从RGB转换为RGB565格式,这是一种紧凑的16位每像素颜色格式,用于PyPortal的显示控制器,并按列逐列写入输出文件flyover.dat。
由于各段在处理过程中直接写入磁盘,因此无论路线长度如何,内存使用量始终保持不变。
同样的获取、转换和写入过程会重复进行,用于路线中的每个路段。连续的下载操作在地图上依次推进,每一部分都覆盖了路线中独立的一段区域,形成一个独立的“向上北向”方框。
由于每个路段的足迹起点正好是前一段结束的位置,提取出的片段能够完美对齐,无任何空隙或重叠,随着新路段的添加,输出图像条带也会无缝扩展。
当所有路段处理完毕后,脚本会生成一张预览BMP图像,供用户进行视觉调试。整个路线被压缩成一张较短的预览图,使用户无需打开全分辨率的数据文件即可检查其外观和完整性。
确认预览效果后,将flyover.dat文件复制到microSD卡中,并插入PyPortal,即可准备显示。
飞行过场显示
项目的code.py脚本会被复制到PyPortal的CIRCUITPY驱动器中,在板子开机时自动执行。
启动时,脚本会初始化显示控制器,挂载SD卡,并设置默认的速度和亮度水平,然后进入循环,驱动飞行过场动画的播放。
flyover.dat 文件可能达到几吉字节的大小,但 PyPortal 的内存容量不足 200 KB。由于数据文件采用列主序布局,因此可以轻松管理。
由于每个图像条带列以连续的 480 字节记录形式存储,脚本能够高效地一次读取单个列的数据到内存,而无需加载整个图像。无论路线长度如何,内存使用量始终保持稳定。
动画循环在 PyPortal 保持通电期间持续运行,每次循环迭代依次执行四个步骤:
首先,脚本从 SD 卡读取新暴露的列,并将其写入显示控制器的帧缓冲区,同时覆盖最旧的列。
其次,为了移动图像,脚本会更新控制器的滚动寄存器,该寄存器的值每次刷新时决定帧缓冲区读取起始位置。这使得显示屏在视觉上平滑地移动所有列,而无需脚本重新写入任何现有像素数据。
随后,脚本会轮询电容式触摸屏以检测触控事件。用户可触摸屏幕的一半区域,切换四种亮度级别;另一半区域则用于切换五种滚动速度。
最后,背光亮度被更新。写入背光的值将用户选择的亮度级别与线性渐变斜坡相结合,在路线开始时实现渐亮,并在路线结束时逐渐变暗。
构建说明
以下是组装PyPortal航拍查看器、生成航拍图像并将其显示在设备上的操作说明。
本说明假设您已具备使用PyPortal的经验,安装了最新的CircuitPython,并能在电脑上运行终端命令。
下载项目文件
完整的项目文件(包括源代码和CAD模型)包含在PyPortal航拍查看器的GitHub仓库中。
1. 前往项目 GitHub 仓库。点击“代码”,然后选择“下载 ZIP”。
这将下载一个名为 pyportal-flyover-main.zip 的文件,其中包含仓库主分支中的所有文件。
2. 解压下载的ZIP文件。
项目文件将提取到pyportal-flyover-main目录中,后续设置步骤可在此目录下进行访问。
硬件设置
首先使用Adafruit PyPortal板及其3D打印部件组装显示器,然后开始构建。
1. 3D打印查看器框架和选定的支架
项目文件中的cad/export/目录包含三个STL模型文件,其中包括查看器框架以及竖屏或横屏方向的支架选项。
本制作指南中使用PLA塑料作为打印材料。
2. 组装框架、PyPortal 和支架
将框架、PyPortal 和所选支架的安装孔对齐,使用四个M3机械螺丝将三部分固定在一起。
本指南中使用的是景观支架,可将观察者水平放置在桌面或其他平坦表面上。
生成图像数据
飞越图像条带通过项目文件中的 generate_flyover.py 脚本,在完整的计算机上生成。
1. 在 pyportal-flyover-main 目录下打开终端,运行以下命令以初始化 Python 虚拟环境:
此一次性设置将创建一个虚拟环境,并安装生成器脚本所需的库。
2. 在代码编辑器中打开 generate_flyover.py 文件,并修改 START、END 和 ZOOM 变量的值。
START 和 END 是航路的两个端点,以纬度和经度对的形式表示为元组。两者必须位于美国境内。
ZOOM 表示所需的图像缩放级别,定义为 13 到 16 之间的整数值。它通过确定图像的地面分辨率,从而有效设定视图高度和横跨轨道的覆盖范围。
请注意,较高的缩放值会产生更大的数据文件,并需要下载更多的图像瓦片。
3. 使用以下命令运行生成器脚本:
该脚本将打印路线的摘要信息,包括路线长度、数据文件大小以及美国地质调查局(USGS)航拍图像请求次数,然后逐段下载图像。
完成后,脚本会将 flyover.dat 文件和预览图像 flyover.bmp 保存到 generator/output/ 目录中。
在继续之前,请打开 generator/output/flyover.bmp 查看路线。该水平压缩的预览图显示了从起点到终点的完整飞行路径。请检查图像沿路线的显示是否正确。如果路线或高度需要调整,请更新脚本中的相关数值并重新运行脚本。
4. 将已格式化为FAT32的microSD卡插入电脑,并将生成的数据文件复制到该卡上:
请将“Volumes/SD_CARD_NAME/”替换为操作系统文件管理器中显示的microSD卡的实际卷名。
文件传输完成后,从电脑中弹出microSD卡,并将其插入PyPortal的背面。
上传显示代码
PyPortal通过项目文件中包含的firmware/code.py脚本来渲染滚动动画。
1. 使用USB数据线将PyPortal连接到电脑。
通过数据传输功能的USB数据线进行连接,板子将自动上电,并在文件系统中以名为CIRCUITPY的驱动器形式显示。
2. 使用以下命令将显示脚本复制到PyPortal:
请将目标路径替换为计算机上CIRCUITPY驱动器实际出现的路径。
文件传输完成后,PyPortal会自动检测到新的code.py脚本并重新启动。显示屏将从黑色淡入,并开始滚动SD卡中加载的飞行图像。
本文编译自hackster.io





