用几何学和 CUDA 编程给一座无名小岛定位
文章摘要
作者 yassa9 挑战的是 OSINT 研究者 Sofia Santos(Gralhix)设计的第 004 号练习题:给出一张热带度假村的航拍照片,要求回答三个问题——度假村叫什么名字、岛的坐标是多少、拍照时相机朝向哪个方位。绝大多数人会直接丢进 Google Lens 反查,但作者认为那样「浪费了一次有趣的机会」,于是决定纯靠数学、地理数据集和 GPU 暴力搜索把它算出来。
第一步是 exiftool 读元数据,结果只有「WEBP 无损、736×515」,毫无价值。于是他转向几何指纹:照片里能看到三块陆地——P0 是度假村所在的小沙洲,P1 是右侧的岛,P2 是左前方带山峰的岛。因为是无人机拍摄且高度未知,无法做严格的透视反演,他只用像素点击 GUI(01_triangle_gui.py)记录三点坐标,算出三角形在 P0 处的夹角和两边距离比,并给这两个值各留 ±20% 的容差窗口。
搜索底库用的是 OpenStreetMap 的 land-polygons-split-4326 全球海岸线矢量集(WGS84,882 MB)。过滤漏斗一层层收:①纬度带 −30°~+30°(凭天空和热带植被判断),剩 141,131 个陆地多边形;②局部密度过滤,5 km 内质心数 ≤10,排除密集礁群和群岛杂波,降到 51,576;③20 km 半径聚类,至少 3 点才算一个簇(用 scipy 的 cKDTree),得到 23,500 个簇;④每簇内做 C(n,3) 三点组合,为避免爆炸把每簇按面积分层采样(小、大、中各三分之一)截到 60 点,最终生成 80,690,777 个三元组。
匹配环节丢给 GPU:每个三元组一个 CUDA 线程,线程内先按陆地面积排序挑出最小的当 P0,再用二维叉积的符号(顺时针/逆时针)区分 P1 和 P2,然后独立计算 P0 处夹角与距离比,命中的用 atomicAdd 原子计数写进共享输出数组。在一块 RTX 3050(sm_86)上,占用 5169 MB 显存,核函数只跑了 204.1 ms,8070 万个三元组中 158,784 个通过;去重后剩 8,915 个唯一三元组。
之后是一串纯启发式的形态学筛选:「开放矩形」检查(沿 P0→P1 边、朝 P2 反方向构造一个长为边长两倍的矩形,若里面还有别的陆地就淘汰,因为照片里那片是开阔水面)→948 个;珊瑚沙洲形状检查,用 Polsby-Popper 紧凑度(4π·面积/周长²)要求 >0.5,再要求 1.5 km 内至少有 1 个面积 <0.05 km² 的微型沙洲「光环」→213 个;椭圆度检查,最小旋转外接矩形的长短边比要在 1.05~2.2 之间,填充率要 ≥0.589(即完美椭圆理论上限 π/4≈0.785 的 75%)→137 个;NDVI 植被检查,通过 Element 84 运营的 Earth Search STAC API(免费、无需 key)拉最新低云 Sentinel-2 影像,采样红光和近红外算 NDVI,阈值 0.6 →66 个;最后是高程检查,用 AWS 公开数据上的 Copernicus DEM GLO-30(30 m)瓦片,要求 P0 本身 ≤50 m,而在相机朝向(P1、P2 方位角的角平分线)±50°、2~20 km 的扇形内最高点在 100~500 m 之间 →26 个。
26 个幸存者集中在南亚、澳洲和大洋洲,只有一个在巴西附近。脚本给每个候选做点在多边形内的国家归属查询,输出一张带 Google Maps 卫星图链接的 HTML 表格。前 7 个肉眼一看就不对,第 8 个属于密克罗尼西亚联邦——正是答案。最终结果:度假村名叫 Oan,坐标 7°21′48.4″N、151°45′20.7″E(即 7.363444, 151.755750),相机方位角算出 324.97°,即西北方向(NW)。文末列出了所有数据来源与许可(OSM ODbL 1.0、Copernicus DEM、Sentinel-2、Natural Earth 10m admin-0 公有领域),代码和最终报告都在 GitHub 上。
HN 评论精华
这篇帖子拿到 526 分、87 条评论,讨论主线有两条:一是延伸出「这套思路其实就是巡航导弹的地形匹配制导」,二是围绕作者「本文非 LLM 生成」的声明爆发了一场真伪之争。
- bmurray7jhu 指出这项技术在无人机和导弹领域早有名字:地形轮廓匹配(TERCOM)。如果轮廓是光学测量的,导航就不依赖射频,因此不怕 GNSS 干扰。
- openasocket 补充 TERCOM 早在 1960 年代就用在巡航导弹上,比 GPS 和卫星导航早了几十年,「那个年代的工程师用那么点算力做出这种东西,我一直被震撼」,还推荐去看 SAGE 系统。有趣的是,TERCOM 反而限制了「战斧」在沙漠风暴行动中的使用:航线必须绕着真实地形特征规划,不能飞几百英里的平坦沙漠。
- grumbelbart2 进一步说早期巡航导弹的内存珍贵到只能装预先规划好的航线地形数据,所以不只要装订目标坐标,而要装订完整飞行计划,并且必须从预设位置发射。ponector 顺带提到苏联航天飞机的自动驾驶计算机只有 130 KB 内存。
- lexlambda 感慨 OpenStreetMap 数据对 OSINT 简直是天赐之物,在人口密集区效果更好,因为还有道路、商铺、电力线等特征可用。GaryNumanVevo 说 Claude / Gemini 配合 Overpass Turbo 已经能做自然语言查询,比如「找一个德国的公交站,周围有 5 栋以上三层楼房」——arboles 补了一刀:「只在德国能可靠工作。」
- bitcurious 观察到很多排名靠前的候选其实通不过肉眼层面的「光环」检查,觉得那个过滤器还有优化空间。作者回应说问题更可能在数据而非过滤器:OSM 海岸线多边形的概化程度取决于谁描的、用的什么底图,光环检查依赖的细部形状很多时候根本不在几何数据里,「我最后也观察到了,但当时已经累瘫了就没再深挖」。
- ape4 问潮汐会不会影响岛的轮廓,作者老实承认没想过,直接信了 OSM 多边形。
- NKosmatos 说这篇文章让他想起「HN 上还是人写文章、还有个人文风的美好旧时光」,建议再多用点 geoguessing 技巧收窄结果。作者回应他确实用了一点:靠天空和热带氛围把纬度带限制在 ±30°,而这一招奏效了。
- ohyoutravel 为文中「这是真人作品,没用 LLM 生成」的声明点赞:「没有这句免责声明,我读的时候会一直担心是 AI 幻觉,随时准备弃读。」他顺口说「密克罗尼西亚不是一个国家」,OkayPhysicist 反驳把密克罗尼西亚联邦简称为 Micronesia 跟把 USA 叫 America 一样合法,最后 ohyoutravel 承认自己去过马绍尔群岛、基里巴斯和 FSM 却没听过这种叫法,学到了。
- phalanxx 唱反调:如果代码都是 LLM 写的,「没用 LLM 生成」是什么意思?而且 Pangram 检测对这段文字也不友好。作者解释博客正文、步骤、走查全是手写,代码是 LLM 精修过的——毕竟不想发布满是测试、失败和死路的意大利面代码,但承认自己应该在文中说明。StilesCrisis 抓住「没有 EXIF、没有 GPS、没有相机品牌型号」这句话质疑是 AI 腔(「相机型号有什么用?」),作者解释他上一道 Gralhix 题目的解法恰恰来自元数据里的相机型号,所以写着就顺手带出来了;voidUpdate 也帮他说话:知道相机品牌型号可以查镜头参数,有助于反推真实世界几何。这场争论最终没有结论,作者只回了一句「ok」。