教程·阅读约 2 分钟·
不用 Google Lens:用几何 + CUDA 在全地球 8000 万个候选里定位一个无名小岛

不用 Google Lens:用几何 + CUDA 在全地球 8000 万个候选里定位一个无名小岛

一个 OSINT 挑战的硬核解法:从照片里三块陆地的相对几何构建指纹,用 8000 万个三元组在全球海岸线数据上跑 CUDA 暴力匹配,再叠加密度、形状、植被、海拔七道筛选,最终锁定密克罗尼西亚的度假村。

原文来源:yassa9.github.io — 作者用几何指纹 + CUDA 并行匹配 + 七道地理筛选,从全球陆地数据中定位一张无名小岛照片的真实位置,全程不用 LLM 和图像搜索。

网上流传着一类 OSINT(开源情报)挑战:给你一张没有地理信息的照片,让你找出它是在哪里拍的。大多数人第一反应是 Google Lens 反向搜图,但这位作者认为那样"浪费了一个好玩的机会"——他选择用数学和编程硬解。结果是写了一个相当完整的定位管线:先用照片里的几何关系构建"指纹",再让 CUDA 在 8000 万个候选上并行匹配,最后用七道筛选逼近答案

任务:一张照片,三个问题

照片是一个度假村,位于某座小岛上。要回答三个问题:度假村叫什么名字?岛屿坐标是多少?拍摄时相机朝向哪个方向?

照片本身没有任何可用元数据——exiftool 查下来只有尺寸,没有 EXIF、GPS、相机型号。

—— 广告 ——

第一步:把照片变成几何指纹

照片里能辨认出三块陆地:

  • P0:照片主体所在的小岛(度假村所在地)
  • P1:右侧的岛屿
  • P2:左前方有一座山峰的岛屿

由于照片是无人机拍的,无法准确估计拍摄高度,作者放弃建立俯视透视模型,转而只提取三块陆地之间的相对几何关系:P0 处三角形的角度、P1/P2 到 P0 的距离比。他写了一个小 GUI 工具,点击记录三个点在像素坐标系中的位置,自动算出三角形几何。

他承认这种估算"凭直觉",因此后续搜索时给角度和距离比都加了 ±20% 的容差带。

第二步:全球搜索——8000 万个候选三元组

有了指纹,下一步是对比地球上的每一块陆地。数据集用的是 OpenStreetMap 的 split land polygon 全球海岸线矢量数据(WGS84 坐标,882MB)。

直接比对整片大陆显然不行,作者设计了几道启发式筛选逐层收窄:

① 热带纬度带。 照片里的植被明显是热带,先砍掉纬度 ±30° 之外的所有陆地。剩下 141,131 个多边形

② 局部密度过滤。 照片里的小岛孤零零的,周围 5km 内不该有超过 10 个其他陆地中心点——否则就是拥挤的礁群或群岛,不是照片里这种 3-4 座岛的孤立组合。筛完剩 51,576

③ 聚类。 照片里至少需要 3 块陆地组成三角形,所以每个点找 20km 内的邻居,不足 2 个的丢掉。剩下 23,500 个簇

④ 生成三元组。 每个簇内所有 3 点组合都是候选三角形:C(n,3)。大簇会爆炸——60 个点的簇就有 34,220 个三元组,所以每簇先按面积分层采样封顶 60 点(小岛三分之一、大岛三分之一、中间三分之一)。全部簇加起来得到 80,690,777 个三元组——这就是要并行匹配的总量。

第三步:CUDA 暴力匹配

每个三元组分配一个 CUDA 线程。线程内先按陆地面积排序找出 P0(最小的那块,即度假村所在小岛),再用二维叉积的符号判断 P1/P2 的左右顺序,然后独立计算 P0 处角度、距离比、P0 大小、P0-P1 间距等所有指标。

一个三元组只有在全部指标都落进指纹容差带时才存活。通过线程用 atomicAdd 原子计数器写入共享输出数组,避免并发覆盖。

实测:RTX 3050 上 8070 万个线程、占用 5.2GB 显存,内核只跑了 204 毫秒。158,784 个三元组通过匹配,去重后剩 8,915 个唯一候选

第四步:七道地理筛选

剩下的候选还需要和照片里的其他线索对齐:

⑤ 开阔水域检查。 照片里 P0 和 P1 之间是大片开阔海面。对每个候选,在 P0→P1 边、P2 不在的那一侧构建一个矩形,检查里面有没有别的陆地——有就淘汰。8,915 → 948

⑥ 珊瑚礁形状检查。 度假村小岛是典型的珊瑚礁(珊瑚沙环礁),形状接近圆形且周围常有微型沙洲。用 Polsby-Popper 紧凑度(4π·面积/周长²,1.0 为完美圆)要求 ≥0.5;再检查 P0 周围 1.5km 内有没有至少 1 块小于 0.05km² 的微型珊瑚礁。948 → 213

⑦ 椭圆形状检查。 对 P0 的多边形拟合最小外接旋转矩形,要求长宽比在 1.05–2.2 之间(不能太圆也不能太长),填充比 ≥ 椭圆的 75%(π/4 ≈ 0.785 是完美椭圆的填充上限)。新月形、环形、锯齿海岸全部出局。213 → 137

⑧ NDVI 植被检查。 最后一道 API 级检查:通过 Element 84 提供的公共 STAC 接口(免费、无需 API key)拉取该点最近的 Sentinel-2 低云影像,取红波段和近红外波段算 NDVI。棕榈树冠在近红外反射强、吸收红光,健康植被 NDVI 远高于 0;裸沙和水面接近 0 或为负。阈值 0.6,要求 P0 必须有真正的树冠覆盖。137 → 66

⑨ 海拔与山峰检查。 照片正前方(P0 到 P1/P2 方向的角平分线 ±50°、2-20km 半径扇形)必须有真实的高地——用免费的 Copernicus DEM GLO-30 30 米分辨率数据采样。要求 P0 本身海拔 ≤50m(低矮礁岛),前方扇形内最高点 100–500m(照片里那座山)。66 → 26

第五步:人眼确认

26 个幸存者分布在东南亚、澳大利亚和大洋洲,巴西附近还有一个。作者逐个打开 Google Maps 卫星图核对——直到第 8 个,密克罗尼西亚的一个珊瑚环礁完全吻合:度假村叫 Oan,坐标 7.363444°N, 151.755750°E。再验证 P1、P2 两块陆地,分毫不差。

相机朝向通过球面几何的 atan2 方位角公式算出来是 324.97°,即西北方向

这套方法能学到什么

这个案例最漂亮的地方是把一道"看起来只能靠搜图"的题,拆解成了几何建模 → 数据筛选 → 并行计算 → 遥感验证的完整工程管线。几个可复用的经验:

  • 把模糊问题变成数值指纹:照片里无法精确测量的东西,用相对几何(角度、比例)加容差带表达,就能变成可计算的匹配条件。
  • 筛选顺序决定性能:最便宜的空间过滤(纬度带、密度)放在最前面,把 14 万砍到 5 万;最贵的 GPU 匹配只留给真正值得的候选。裁剪一个量级,后面每个环节都快 10 倍。
  • 免费卫星数据就是超级工具:Sentinel-2 的 NDVI 和 Copernicus DEM 都通过 AWS Open Data 免费开放,无需任何密钥就能用。任何"判断某处有没有植被/山脉"的问题,现在都有标准答案可查。
  • CUDA 一行一个候选:8070 万个三元组、204 毫秒,这种"给每个候选一个线程"的粗暴并行在数据规模可控时比任何聪明算法都快。

作者在文末特意注明这是纯人工作品、没有用 LLM 生成——对一个连图像搜索都拒绝的挑战来说,算是把"自己动手"贯彻到底了。完整的代码、报告和数据都放在 GitHub 上,想复现这个管线的读者可以直接照着跑一遍。

分享到
微博Twitter

© 2026 四月

原文链接:https://www.aprilzz.com/tutorials/geolocating-island-cuda