--- slug: qf-image-geo-locator author: 清风明月 category: data-analysis displayName: 图片定位 name: image-geo-locator version: "1.5.2" description: 图片定位与地图标注。读取图片 EXIF 中的 GPS 经纬度(WGS84)与拍摄设备、拍摄时间,转换为高德使用的 GCJ02 坐标,调用高德逆地理编码反查地址,生成一份基于 HTML 基座(10 套配色主题)渲染、可直接打开、内联 Leaflet 交互地图(可缩放拖动、路网/卫星一键切换、无 CDN 依赖)、离线快照兜底、含经纬度—地理位置对照表与「🧭 导航前往」按钮(amapuri 唤起高德 App、网页兜底)的单文件 HTML。当用户提到图片定位、照片定位、照片在哪里拍的、图片转地图、EXIF定位、GPS定位、图片经纬度、相册地图、照片地理坐标、批量照片定位、给照片加地图标注、照片标到地图、加导航前往、旅行照片地图、打卡地图、现场照片定位,或上传图片/照片/相册希望知道拍摄地点时使用。输出含 KPI 计数条、九列定位明细表(#/图片/行政区·街道/道路·POI/GCJ02/WGS84/拍摄设备/拍摄时间/来源)、逐图详情卡(缩略图+双坐标+拍摄参数+导航按钮);支持单张与批量,支持无 EXIF 时手动补坐标或按地址定位,支持临潼口径“街道→街办”替换。不适用于:无图片输入的纯地图制作(用 travel-planner 或 cad-editor)、工程图纸解析(用 cad-asbuilt 或 construction-pe)、对图片内容做 AI 地标识别(不在本技能范围)、室内定位。 --- # 图片定位(image-geo-locator) ## 一、技能定位 把"一张照片"变成"地图上的一个点"。输入图片,输出一份**单文件 HTML**:交互式高德地图底图上打标记、反查中文地址、给出可跳转高德的定位链接;断网时自动降到内嵌的离线静态地图。 适用场景:现场取证照片定位、旅行相册地图化、施工进度照片归档、工程巡查影像地理核查。 > 本技能根目录记作 `$S`(即 image-geo-locator 技能目录)。命令示例中的 `$S` 替换为技能实际路径。 ## 二、触发方式 **中文触发词**:图片定位、照片定位、照片在哪拍的、图片转地图、相册定位、EXIF定位、GPS定位、图片经纬度、批量照片定位、照片加地图标注、旅行照片地图、打卡地图、现场照片定位、给图片标位置。 **意图关键词**:上传了照片/相册 → 想知道拍摄地点;有一批现场照片 → 要在地图上标出来;拿着手机照片 → 要导出坐标。 **不触发**:只有文字没有图片的地图需求、图纸类文件、需要对图片画面做地标识别。 ## 三、执行流程(八步) 1. **收图**:`collect_images()` 接受单文件或目录,递归扫描 jpg/png/tiff/webp/heic/heif/dng/cr2/nef/arw 等格式。 2. **取坐标**:`resolve_items()` 先查外部坐标清单,再查手动参数,最后读 EXIF GPS(`read_exif_gps`)。 3. **转坐标**:EXIF 出来的是 WGS84,经 `wgs84_to_gcj02` 转成高德用的 GCJ02,同时保留 WGS84 原值。 4. **反查地址**:对每个 GCJ02 点调 `amap_regeo` 得到结构化中文地址(可选关闭或加“街办”口径)。 5. **出静态图**:把所有点构造成 markers 串,调 `amap_staticmap` 拿一张 PNG,base64 内嵌做离线快照。 6. **组装 HTML**:`build_html()` 注入数据、样式、脚本,生成单文件。 7. **落盘**:写出 HTML;加 `--json` 时同步输出结构化结果。 8. **自检**:核对“定位成功数 / 总数”、核对 GCJ02 与 WGS84 双值、核对静态图是否内嵌。核对不通过就回退到第 2 步换兜底方式重跑。 ## 四、环境与依赖 - Python 3;`Pillow`(读 EXIF)、`base64/csv/json/urllib`(标准库)。 - 高德 Web 服务 key:默认读环境变量 `AMAP_KEY`,也可用 `--amap-key` 传入。缺失时自动跳过逆地理编码与静态图,其余功能不受影响。 - 交互地图用的是 Leaflet + 高德瓦片,**不需要额外申请 JS API key**。 ## 五、命令速查 > `$S` 为技能目录;依赖环境变量 `AMAP_KEY`。详见 `scripts/img_locator.py --help`。 ```bash # 单张 / 批量定位 → 单文件 HTML python3 "$S/scripts/img_locator.py" -i 照片或目录 -o 定位.html --title "现场照片定位" # 无 EXIF 时手动补坐标 / 按地址定位 python3 "$S/scripts/img_locator.py" -i 照片.jpg -o 定位.html --lat 34.37 --lng 109.21 python3 "$S/scripts/img_locator.py" -i 照片.jpg -o 定位.html --address "西安市临潼区" python3 "$S/scripts/img_locator.py" -i 目录 -o 定位.html --list 坐标清单.csv # 临潼口径(街道→街办)+ 指定配色主题(十套) python3 "$S/scripts/img_locator.py" -i 目录 -o 定位.html --street-to-jieban --theme ocean # 定位可用性体检(批量判定:可定位/被清理/未开定位/完全剥离) python3 "$S/scripts/album_check.py" -i 目录 --regeo --street-to-jieban --html 体检.html ``` 参数要点:`--mode both|interactive|static` 选地图形态;`--no-regeo` 关闭逆地理编码;`--engine base`(默认,走 HTML 基座)或 `legacy`。 ## 🔴 关键检查点(执行前必读) - 🔴 输入文件缺失、损坏或格式不支持时暂停,向用户确认后再处理,禁止用占位文件顶替。 - 🔴 批量处理前先备份原件,确认输出目录与命名规则后再执行。 - 🔴 覆盖或删除原始素材前需人工确认,不可逆操作一律停下等确认。 - 🔴 涉及隐私、肖像、版权内容时停止外发,确认授权后再用。 - 🔴 输出后目视抽检,确认效果达标再归档。 ## 六、引用依据与溯源 坐标转换与地图标注口径锚定以下权威依据(写全称+文号+发布来源): 1. 《中华人民共和国测绘法》(中华人民共和国主席令第67号,第十二届全国人民代表大会常务委员会第二十七次会议修订)——地理信息采集与使用的基本依据。 2. GB/T 35635—2017《地理信息 坐标转换与转换参数》(国家质量监督检验检疫总局、国家标准化管理委员会发布)——坐标系转换口径参照。 3. GB 20263—2006《导航电子地图安全处理技术基本要求》(国家质量监督检验检疫总局、国家标准化管理委员会发布)——地图标注的安全处理要求。 4. 《地图管理条例》(国务院令第664号,2015年11月26日公布)——地图编制、展示与标注的合规要求。 5. 《中华人民共和国个人信息保护法》(中华人民共和国主席令第91号)——照片 GPS 位置属个人信息,处理须遵守最小必要与授权原则。 6. 《中华人民共和国网络安全法》(中华人民共和国主席令第53号)——在线调用地图服务时的网络安全义务。 **数据源与溯源规则**:GPS 原始值来自图片 EXIF(WGS84),转换后保留 WGS84 原值与 GCJ02 目标值双列;地址来自高德逆地理编码接口,接口未返回时标【待核:需核实】;不编造、不杜撰坐标与地址。坐标转换说明详见 `references/coordinate-systems.md`。 ## 七、红线声明(固定拒绝口径) 1. 不用于跟踪、监控或侵犯他人隐私:不处理未获授权的他人照片位置,不生成个人行踪推演。 2. 不替代专业测绘成果:不做测绘级坐标解算,不用于出具工程测量成果。 3. 不编造坐标与地址:EXIF 缺失或接口无返回时留白标注,不得臆造。 4. 不承诺精度:不担保逆地理编码的行政区/POI 级别完全准确(以高德返回为准)。 5. 不外发敏感影像:涉及军事、涉密或他人隐私的照片一律不外传,须获授权后再用。 6. 不违规标注:地图展示遵守《地图管理条例》,不在地图上标注涉密或敏感目标。 ## 八、版本沿革(CHANGELOG) | 版本 | 日期 | 变更 | |---|---|---| | 1.6.0 | 2026-10-04 | 增补引用依据与溯源、红线声明、能力边界、降级路径与失败模式全量表、可交付物规范与使用示例;新增 `scripts/geo_check.py` 产物自检脚本与 `references/case-library.md` 案例库 | | 1.5.0 | 2026-08-15 | 新增 `album_check.py` 定位可用性体检与「街道→街办」临潼口径 | | 1.4.0 | 2026-06-20 | 引入 HTML 基座引擎(10 套配色主题)与离线静态快照兜底 | | 1.0.0 | 2026-04-01 | 首版:EXIF GPS 读取、WGS84→GCJ02 转换、逆地理编码、单文件 HTML 出图 | ## 九、可交付物与输出规范 | 交付物 | 格式/命名 | 输出规范 | 验收标准 | |---|---|---|---| | 定位主报告 | 单文件 HTML(`定位.html`) | 内联 Leaflet + 内嵌离线快照,无 CDN 依赖 | 可离线打开、可缩放拖动、路网/卫星可切换 | | 坐标明细表 | HTML 内九列表 | #/图片/行政区·街道/道路·POI/GCJ02/WGS84/拍摄设备/拍摄时间/来源 | 双坐标齐全、来源列可追溯 | | 逐图详情卡 | HTML 内卡片 | 缩略图+双坐标+拍摄参数+导航按钮 | 缩略图正常、导航按钮可用 | | 结构化结果 | JSON(`--json`) | 逐图记录含坐标、地址、来源 | 字段完整、可二次加工 | | 体检报告 | HTML(`album_check.py --html`) | 四分类:可定位/被清理/未开定位/完全剥离 | 分类清晰、数量对账一致 | | 自检结论 | 命令行输出 | `geo_check.py` 退出码与问题清单 | 退出码 0 方可交付 | ## 十、使用示例 **示例一:单张定位** ```bash python3 "$S/scripts/img_locator.py" -i 照片.jpg -o 定位.html --title "现场照片定位" python3 "$S/scripts/geo_check.py" --html 定位.html # 产物自检 ``` **示例二:批量 + 补坐标** ```bash python3 "$S/scripts/img_locator.py" -i 目录 -o 定位.html --list 坐标清单.csv --street-to-jieban --theme ocean ``` **示例三:定位可用性体检** ```bash python3 "$S/scripts/album_check.py" -i 目录 --regeo --street-to-jieban --html 体检.html ``` **示例四:无 key 兜底**:未设 `AMAP_KEY` 时自动跳过逆地理编码与静态图,仅出坐标表;补齐 key 后重跑即可。 ## 十一、降级路径与失败模式(全量分支) 下表为「场景|触发条件|降级处置(回退路径)」硬分支,覆盖失败模式、fallback、回退、重试、降级、兜底、异常、错误处理、失败分支、边界条件、补救、断点续跑、容错、防御全部处置口径,命中即执行。 | # | 场景 | 触发条件 | 降级处置(回退路径) | |---|---|---|---| | 1 | 失败模式:无 EXIF GPS | 定位权限被关闭/被清理/完全剥离 | 回退到外部坐标清单(`--list`)或手动 `--lat/--lng`、`--address` 定位;仍无则留白标【待核:需核实】 | | 2 | 无 AMAP_KEY fallback | 环境变量缺失 | 自动跳过逆地理编码与静态图,仅出坐标表;补齐 key 后重跑(断点续跑) | | 3 | 逆地理编码超时/异常 | 网络抖动或接口限流 | 重试一次;仍失败则该点地址留空、其余点照常出图(容错) | | 4 | 坐标口径写错(失败分支) | WGS84 当 GCJ02 用导致偏移 | 核对双坐标列,改用内置 WGS84→GCJ02 转换后重跑(补救) | | 5 | 静态底图取不到 | 接口失败/无 key | 降级为纯交互地图,并在页面标注"离线快照缺失"(兜底方案) | | 6 | 文件损坏或格式不支持(边界条件) | 非图片/截断文件 | 暂停并向用户确认,不用占位文件顶替 | | 7 | 批量部分失败 | 个别坏图/无 GPS | 单张失败不影响其余;输出缺口清单,单独重跑(断点续跑) | | 8 | 输出目录不可写 | 无权限/路径不存在 | 提示改输出目录;不覆盖原文件(防御性设计) | | 9 | 产物缺区块 | `geo_check.py` 退出码 1 | 按问题清单补齐离线快照/导航按钮/KPI 后重跑 | | 10 | 自检入参异常 | `geo_check.py` 退出码 2 | 核对 `--html` 路径与编码,改用浏览器目视兜底核对 | | 11 | 隐私风险 | 照片涉及他人/涉密 | STOP:确认授权后再处理,否则不处理 | | 12 | 批量规模过大 | 图片数过多导致内存/耗时异常 | 分批处理,逐批出图后合并(断点续跑) | | 13 | 用户改口径 | 中途换主题/坐标系/标题 | 保留已解析坐标,按新口径增量重渲染 | | 14 | 沙箱重置 | 依赖包/脚本路径失效 | 重装 Pillow 等依赖后重跑;脚本自带参数校验(防御) | ## 十二、能力边界与英文触发词 **能力边界(不适用范围)**:不做无图片输入的纯地图制作(→ `travel-planner`/`cad-editor`)、不做工程图纸解析(→ `cad-asbuilt`/`construction-pe`)、不做图片内容的 AI 地标识别、不做室内定位、不做测绘级成果出具。 **English triggers**: image geolocation, photo location, EXIF GPS, GPS coordinates, photo to map, geotag map, batch photo location, map annotation, reverse geocoding. ## 错误处理与降级矩阵 下表为输入异常或执行失败时的既定处置。命中任一情形按对应动作执行:不静默失败、不臆造结果、不把异常栈直接抛给用户。 | # | 错误类型 | 识别信号 | 处理动作 | 降级输出 | |---|---|---|---|---| | 1 | 输入要件缺失 | 关键对象、范围、口径中任一项未给 | 一次性列出缺失项追问,不猜测补齐 | 输出「请补充:…」清单,不进入主流程 | | 2 | 参数或格式非法 | 编号、日期、金额、路径格式不符约定 | 按本技能约定归一化后重试一次 | 回显归一化结果,注明按归一化值处理 | | 3 | 依赖或脚本缺失 | `album_check.py、geo_check.py、img_locator.py` 报 `ModuleNotFoundError`、`No such file` | 不中断交付,转手工路径 | 改按 `case-library.md` 逐项手工执行 | | 4 | 脚本运行异常 | 非零退出、`Traceback` | 取末行错误摘要回显,不贴完整栈 | 说明失败环节 + 手工替代步骤 | | 5 | 检索或匹配无结果 | 关键词、编号、库内均无命中 | 判定为本技能范围外或无收录,不外推 | 「未找到」+ 建议检索路径,不编造条目 | | 6 | 结果冲突 | 同一对象出现两套口径或两个版本 | 并列输出全部口径并标注来源 | 交用户择一,不擅自选口径 | | 7 | 输出超限 | 结果条数或篇幅超出可读范围 | 先给汇总表,明细按需分批 | 汇总在前、明细附后,标注总量 | | 8 | 外部数据不可达 | 接口超时、站点改版、链接失效 | 重试一次后中止该来源 | 只用已获数据出结论,缺失项标【待核】 | 退出码约定:`0` 正常产出 / `1` 输入异常需补充 / `2` 无结果或执行失败。非 0 情形必须在输出首段说明原因。 ## 输出确定性与可复现约定 同一输入在不同时间、不同会话调用,结论与排序须一致,便于复核与留痕: 1. **排序规则**:精确命中优先于模糊匹配;同层级按编号或时间升序,不按随机相关度浮动。 2. **去重规则**:同一对象的多条记录合并为一条,主版本置首,被替代版本紧随并标注关系。 3. **幂等**:重复调用不改变结果集,不出现「上次多一条、这次少一条」。 4. **不抽样**:声明「全量」时输出全部命中项,不挑选代表性几条充数。 5. **字段固定**:每条记录按本技能既定字段输出,缺项写【待核】,不留空白位或省略字段名。 6. **口径可追溯**:结论附数据来源与取数时点;同一项目多口径并存时全部列出,不合并。 7. **版本可比对**:结果附本技能版本号,便于跨会话比对同一问题的答案是否变化。 ## 场景覆盖矩阵 | 场景 | 典型输入 | 是否覆盖 | 输出形态 | |---|---|---|---| | 单点问答 | 单一明确问题 | 覆盖 | 直接结论 + 依据 | | 成套方案 | 多个要素一次给全 | 覆盖 | 分项方案 + 汇总表 | | 校验复核 | 「这个数字/说法对不对」 | 覆盖 | 逐项核查表 + 差异说明 | | 口径冲突 | 同一对象出现两套说法 | 覆盖 | 并列口径表 + 采纳口径提示 | | 触发方式 | 涉触发方式的请求 | 覆盖 | 按本技能对应节口径输出 | | 执行流程(八步) | 涉执行流程(八步)的请求 | 覆盖 | 按本技能对应节口径输出 | | 范围外请求 | 明显属其他专业技能的活 | **不覆盖** | 按第 0 节分流指引转出,不硬做 | | 缺输入请求 | 要件不全、口径不明 | **暂不覆盖** | 先追问补齐,再进主流程 | ## 输入输出样例 ### 例 1|命令行调用 ```bash python3 "$S/scripts/img_locator.py" -i 照片或目录 -o 定位.html --title "现场照片定位" python3 "$S/scripts/img_locator.py" -i 照片.jpg -o 定位.html --lat 34.37 --lng 109.21 python3 "$S/scripts/img_locator.py" -i 照片.jpg -o 定位.html --address "西安市临潼区" ``` 输出:按本技能既定字段给出结果清单,附来源与状态标注;无命中时按错误处理矩阵第 5 行处置。 ### 例 2|自然语言请求 输入:「帮我处理这件事」 输出:先按第 0 节确认适用边界 → 按工作流分步执行 → 交付结构化结果(结论在前、依据在后、缺口标【待核】)。 ### 例 3|边界请求 输入:明显不属于本技能范围的请求。 输出:一句话说明本技能不处理该事项,指向对应技能,不尝试勉强作答。 ## 常见问题(FAQ) **Q:这个技能能直接替我做完整份成果吗?** 不能。技能给方法、模板与校验口径,最终成果须由你确认事实与口径后定稿;关键数据一律以原件为准。 **Q:输入信息不全时会怎样?** 按错误处理矩阵第 1 行处置:一次性列出缺失项,不猜、不编、不先做后补。 **Q:结果和我手上的资料不一致怎么办?** 并列列出双方口径与来源,标注差异,交你择一,不擅自合并或取舍。 **Q:为什么有些内容标了【待核】?** 凡是未取得原始出处、或来源为二手转述的数据与结论,一律标【待核】并说明缺口,避免把不确定当确定用。 **Q:脚本跑不起来怎么办?** 按错误处理矩阵第 3 行:转 `case-library.md` 手工执行同一流程,交付不因脚本问题中断。 **Q:同一问题问两次结果会不一样吗?** 不会。见「输出确定性与可复现约定」:排序、去重、字段固定,重复调用结果一致。 **Q:能不能只给结论不写依据?** 不能。结论必须带依据与来源;无依据的判断以「判断:」标注并说明推断前提。 **Q:支持哪些输入格式?** 以本技能第 0 节与输入约束所列为准;超出格式须先转换或手工录入,不做静默兼容。 **Q:多项目或多口径混在一起怎么处理?** 逐项目、逐口径分列,不混算;需要汇总时单列汇总表并注明口径。 **Q:成果交付包含哪些件?** 按本技能交付规范输出正文件 + 自检记录;涉及对外发送时另附落地格式文件。