爱意满满的作品展示区。
vincentchyu

写了个相机 RAW 照片 GPS 轨迹对齐、智能插值与离线反地理编码工具 Photools

  •  
  •   vincentchyu · 1h 58m ago · 162 views

    [开源] 写了个相机 RAW 照片 GPS 轨迹对齐、智能插值与离线中文地名归档工具 photools

    各位 V 友好。

    平时喜欢带着相机到处跑,同时也是个写 Go 的程序员。每次外拍或者旅行回来,把几千张 RAW 照片导进电脑整理时,总会被照片的地理信息折磨:

    1. 相机时钟偏差:相机没内置 GPS ,用手机或佳明手表录了 GPX 轨迹,但相机时间和 GPS 总会差个几秒或几分钟,手动对齐繁琐,跨时区更是灾难;
    2. 室内/盲区断点:进了室内、隧道或者短暂停留时,手机没打上点,导致同一机位拍的照片一部分有坐标、一部分完全空白;
    3. 地名逆地理体验糟糕:Lightroom 之类的工具要么依赖联网,要么反查出来的中文地名不规范,更别提自动打上「某某风景名胜区 / 5A 景区」的 POI 了;
    4. 传统脚本慢如蜗牛:以前自己写 Python 调 ExifTool 批处理,每张照片都 fork/exec 一次子进程,上万张 RAW 照片能让风扇狂转半小时;
    5. 双格式同步容易漏:RAW + JPG 同拍或者带调色 XMP 时,元数据经常不同步。

    折腾了一段时间,自己用 Go 撸了一套专门解决照片导入电脑后“第一公里”的元数据处理工具:photools。目前已经在 GitHub 开源。


    做了哪些事情?

    整个处理链路设计成了分阶段屏障流水线( Stage Barriers Pipeline ):

    [待处理照片 RAW/JPG] ──▶ 1. GPX 轨迹匹配 ──▶ 2. GPS 智能插值 ──▶ 3. 离线逆地理 ──▶ 4. 拍摄日期归档 ──▶ [归档库/YYYY/MMDD/]

    1. GPX 轨迹精准匹配与秒级偏差补偿

    • 支持 -geosync 时间偏移补偿(比如相机慢了 5 秒,直接设 +00:00:05 自动校准);
    • 采用主文件优先模型( Primary Asset Model ):以 RAW 为主决策源,写入坐标并二次校验,然后无污染同步到伴随的 JPG 和 XMP 。

    2. 室内与断点自愈( GPS 智能时间插值)

    很多时候在景区室内或峡谷拍的照片没命中 GPX 轨迹:

    • 球面大圆时间加权插值:利用前一个有效机位和后一个有效机位,按拍摄时间在球面上插值推算;
    • 同机位近邻继承:单侧锚点(刚进室内)直接继承最邻近机位,推算完动态合入索引,后面的照片就能自愈继承。

    3. 纯离线 3D KD-Tree 高精逆地理(全国 90 万+ POI )

    • 不调任何高德、腾讯或 Google 在线 API ;
    • 纯离线加载全国 90 万+ 行政区划与风景名胜 POI 数据库;
    • 毫秒级将 国家、省份、城市、区县、景区 POI 规范中文名写入 IPTC/XMP ,在 Lightroom 或系统相册里直接看中文地名。

    4. 真实拍摄日期原子归档

    • 读取 EXIF 真实拍摄时间,重命名为 YYYY-MM-DD-basename 并安全移动到 Processed/YYYY/MMDD/
    • 支持软降级容错(--allow-no-gps),没有 GPS 的照片也会安全归档,并自动生成一份 Markdown 排查清单(Logs/inbox_pending_report_latest.md)。

    一些工程与性能实现

    为了让批量处理几十万张 RAW 时不卡顿,做了一些底层优化:

    1. ExifTool Stay-Open 守护进程池(速度提升 ~20 倍)

    传统脚本慢是因为频繁启动 Perl 进程(单次 30~50ms )。photools 实现了基于管道通信的 StayOpenPool 常驻守护池(exiftool -stay_open True -@ -),单次读取开销压到了 1~2ms,并且支持子进程崩溃自愈。

    2. 3D KD-Tree 空间索引 + O(log K) 时间分桶

    • 空间:把经纬度投影为三维笛卡尔坐标 $(x, y, z)$ 建平衡二叉树,最近邻查询微秒级;
    • 时间:插值阶段在内存中按天分桶维护有序切片,通过二分查找在 ~200ns 内定位前后邻近机位,批次首轮统一提取坐标,避免循环反复读 I/O 。

    3. Go ➔ SwiftUI 进程内 C-Shared FFI 直通

    macOS 客户端用原生 SwiftUI 写的,没有在本地开 HTTP 服务或搞 RPC ,而是把 Go 核心编译成了 libphotools.dylib 动态库,SwiftUI 通过 C-Shared FFI 在进程内直接调用,延迟在 0.1ms 左右。


    界面展示

    1. 工作区引导与离线 3D KD-Tree 反查

    2. 多阶段流水线执行过程全景

    3. 执行审计看板与待处理诊断清单

    4. 终端 TUI 工作台(基于 Bubble Tea )

    习惯在终端或 Linux/NAS 跑的同学,也可以直接敲 ./photools tui 启动交互式终端界面:

    • [1/2/3/4] 快捷键开关插件;
    • [O] 调出插件设置;
    • [S] 全局设置(支持 [Tab] 路径补全);
    • [Enter] 预检与执行。

    写在最后

    项目完全开源,没有商业化诉求,主要是为了解决自己和身边摄影朋友的实际整理痛点。

    如果你也是相机常客、对照片元数据/GPS 轨迹有强迫症,欢迎试用、提 Issue 或 PR !

    2 replies    2026-08-26 12:52:02 +08:00
    bearbest
        1
    bearbest  
    PRO
       1h 19m ago
    之前确实有类似的困扰,试用一下。
    另外问一下 GPS 运动轨迹记录 OP 用的什么软件或设备?
    vincentchyu
        2
    vincentchyu  
    OP
       2 mins ago
    @bearbest 我是用 workoutdoors ,还有苹果健康,上传 strava ,两步路组合使用,还没有找到不依赖手机的 gps 记录设备
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3478 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 04:54 · PVG 12:54 · LAX 21:54 · JFK 00:54
    ♥ Do have faith in what you're doing.