图片GPS经纬度提取工具

2026年05月29日17:21:34 发表评论 热度12 ℃

因为博主所从事的工作,需要对一些点位进行拍照,然后将这些点位输入到谷歌地球中留作记录,如果照片少的情况下还可以逐一输入,但是有时拍摄的照片很多,再一张一张输入就变的很麻烦,所以就用AI编写了这个软件-图片GPS经纬度提取工具,功能很简单就是从拍摄的照片中快速提取经纬度,方便快速导入谷歌地球中。图片GPS经纬度提取工具

使用说明

1、首先将照片导入到电脑中,不要用微信,微信会将GPS数据给抹除,推荐使用QQ传送文件或者数据线。

2、选择照片文件夹,然后点击「开始提取GPS」按钮即可。

工具会自动在当前目录生成一个CSV文件,里面包含了提取的经纬度。

本人因为需要导入到谷歌地球中,所以加入了「一键生成KML」功能。

图片GPS经纬度提取工具

谷歌地球直接导入CSV

如果你也有导入谷歌地球的需要,可以直接导入KML文件,当然生成的CSV文件也可以导入,步骤如下:

1、打开谷歌地球→ 点击顶部 文件 → 导入,文件类型选 CSV,选中你要导入的csv文件。

2、导入向导设置:

分隔符:逗号

字段映射:

纬度 → 选 纬度 列

经度 → 选 经度 列

名称 → 选 图片文件名 列(方便识别)

3、点完成,所有 GPS 点位一键显示在地球中。

图片GPS经纬度提取工具

进制问题:

这里提取的经纬度转换成了十进制,可以通过复制粘贴的方式快速搜索查找点位,如果以原始的度分秒形式搜索会出现问题。

你可以自行将十进制转换为度分秒的格式,不懂就问AI。

下面提供提取度分秒形式的原代码,需要的自取。

  1. import os
  2. import csv
  3. import threading
  4. from PIL import Image
  5. from PIL.ExifTags import TAGS, GPSTAGS
  6. import ttkbootstrap as ttk
  7. from ttkbootstrap.constants import *
  8. from tkinter import scrolledtext
  9. from tkinter import filedialog, messagebox
  10. # ====================== EXIF与GPS原始数据提取(不转十进制) ======================
  11. def get_exif_data(image_path):
  12.     """提取图片EXIF元数据,返回原始信息"""
  13.     exif_data = {}
  14.     try:
  15.         with Image.open(image_path) as img:
  16.             exif_info = img._getexif()
  17.             if exif_info is None:
  18.                 return exif_data
  19.             for tag_id, value in exif_info.items():
  20.                 tag = TAGS.get(tag_id, tag_id)
  21.                 if tag == "GPSInfo":
  22.                     gps_data = {}
  23.                     for gps_tag_id, gps_value in value.items():
  24.                         gps_tag = GPSTAGS.get(gps_tag_id, gps_tag_id)
  25.                         gps_data[gps_tag] = gps_value
  26.                     exif_data[tag] = gps_data
  27.                 else:
  28.                     exif_data[tag] = value
  29.     except Exception:
  30.         pass
  31.     return exif_data
  32. def get_original_gps(exif_data):
  33.     """直接提取原始GPS度分秒,不做十进制转换"""
  34.     gps_info = exif_data.get("GPSInfo", {})
  35.     if not gps_info:
  36.         return None, None, None, None
  37.     lat_dms = gps_info.get("GPSLatitude")
  38.     lat_ref = gps_info.get("GPSLatitudeRef")
  39.     lon_dms = gps_info.get("GPSLongitude")
  40.     lon_ref = gps_info.get("GPSLongitudeRef")
  41.     return lat_dms, lat_ref, lon_dms, lon_ref
  42. def format_dms(dms_data):
  43.     """格式化原始度分秒为可读字符串"""
  44.     if not dms_data or not isinstance(dms_data, (tuplelist)):
  45.         return "无"
  46.     try:
  47.         degrees = f"{dms_data[0][0]}/{dms_data[0][1]}" if isinstance(dms_data[0], tupleelse dms_data[0]
  48.         minutes = f"{dms_data[1][0]}/{dms_data[1][1]}" if isinstance(dms_data[1], tupleelse dms_data[1]
  49.         seconds = f"{dms_data[2][0]}/{dms_data[2][1]}" if isinstance(dms_data[2], tupleelse dms_data[2]
  50.         return f"{degrees}°{minutes}'{seconds}\""
  51.     except:
  52.         return "格式错误"
  53. # ====================== 可视化GUI主程序 ======================
  54. class GPSExtractorGUI:
  55.     def __init__(self, root):
  56.         self.root = root
  57.         self.root.title("图片GPS原始数据提取工具")
  58.         self.root.geometry("750x550")
  59.         self.root.resizable(TrueTrue)
  60.         self.folder_path = ttk.StringVar()
  61.         # 创建界面组件
  62.         self.create_frame_select()
  63.         self.create_frame_log()
  64.         self.create_frame_btn()
  65.     def create_frame_select(self):
  66.         """文件夹选择框架"""
  67.         frame = ttk.LabelFrame(self.root, text="文件夹选择")
  68.         # 修复:直接使用 X/LEFT 常量,不加 ttk. 前缀
  69.         frame.pack(fill=X, padx=20, pady=10)
  70.         ttk.Label(frame, text="图片目录:").pack(side=LEFT, padx=10, pady=8)
  71.         ttk.Entry(frame, textvariable=self.folder_path, width=50).pack(side=LEFT, padx=5, pady=8, fill=X, expand=YES)
  72.         ttk.Button(frame, text="浏览选择", command=self.select_folder, bootstyle=PRIMARY).pack(side=LEFT, padx=10, pady=8)
  73.     def create_frame_log(self):
  74.         """日志显示框架"""
  75.         frame = ttk.LabelFrame(self.root, text="提取日志")
  76.         frame.pack(fill=BOTH, expand=YES, padx=20, pady=10)
  77.         # 使用原生滚动文本框,全版本兼容
  78.         self.log_text = scrolledtext.ScrolledText(frame, height=20, font=("微软雅黑", 9))
  79.         self.log_text.pack(fill=BOTH, expand=YES, padx=8, pady=8)
  80.     def create_frame_btn(self):
  81.         """操作按钮框架"""
  82.         frame = ttk.Frame(self.root)
  83.         frame.pack(fill=X, padx=20, pady=10)
  84.         self.start_btn = ttk.Button(
  85.             frame, text="开始提取GPS原始数据", command=self.start_extract_thread, bootstyle=SUCCESS
  86.         )
  87.         self.start_btn.pack(side=RIGHT, padx=5)
  88.     def select_folder(self):
  89.         """选择图片文件夹(支持中文)"""
  90.         path = filedialog.askdirectory(title="选择图片文件夹")
  91.         if path:
  92.             self.folder_path.set(path)
  93.     def log(self, msg):
  94.         """实时输出日志"""
  95.         self.log_text.insert(END, msg + "\n")
  96.         self.log_text.see(END)
  97.         self.root.update_idletasks()
  98.     def save_to_csv(self, results):
  99.         """保存结果到CSV"""
  100.         csv_path = os.path.join(os.getcwd(), "图片GPS原始数据.csv")
  101.         headers = ["图片文件名", "文件完整路径", "纬度(DMS)", "纬度方向", "经度(DMS)", "经度方向", "状态"]
  102.         with open(csv_path, "w", newline="", encoding="utf-8-sig") as f:
  103.             writer = csv.writer(f)
  104.             writer.writerow(headers)
  105.             writer.writerows(results)
  106.         self.log(f"\n✅ 结果已保存至:{csv_path}")
  107.         messagebox.showinfo("完成", f"提取完成!\n结果已保存到:{csv_path}")
  108.     def batch_extract(self):
  109.         """批量提取核心逻辑"""
  110.         folder = self.folder_path.get().strip()
  111.         if not folder or not os.path.isdir(folder):
  112.             messagebox.showerror("错误", "请选择有效的图片文件夹!")
  113.             self.start_btn.config(state=NORMAL)
  114.             return
  115.         # 支持的图片格式
  116.         IMG_FORMATS = (".jpg", ".jpeg", ".JPG", ".JPEG", ".png", ".PNG")
  117.         results = []
  118.         self.log("===== 开始批量提取原始GPS数据 =====")
  119.         self.log(f"扫描目录:{folder}\n")
  120.         count = 0
  121.         for root_dir, _, files in os.walk(folder):
  122.             for file in files:
  123.                 if file.endswith(IMG_FORMATS):
  124.                     count += 1
  125.                     file_path = os.path.join(root_dir, file)
  126.                     exif = get_exif_data(file_path)
  127.                     lat_dms, lat_ref, lon_dms, lon_ref = get_original_gps(exif)
  128.                     lat_str = format_dms(lat_dms)
  129.                     lon_str = format_dms(lon_dms)
  130.                     lat_ref = lat_ref if lat_ref else "无"
  131.                     lon_ref = lon_ref if lon_ref else "无"
  132.                     if lat_dms and lon_dms:
  133.                         status = "提取成功"
  134.                         self.log(f"✅ {file} | 纬度:{lat_str}{lat_ref} | 经度:{lon_str}{lon_ref}")
  135.                     else:
  136.                         status = "无GPS信息"
  137.                         self.log(f"❌ {file} | 未找到GPS数据")
  138.                     results.append([file, file_path, lat_str, lat_ref, lon_str, lon_ref, status])
  139.         self.log(f"\n===== 提取完成 =====")
  140.         self.log(f"共处理图片:{count} 张")
  141.         self.save_to_csv(results)
  142.         self.start_btn.config(state=NORMAL)
  143.     def start_extract_thread(self):
  144.         """子线程运行,界面不卡顿"""
  145.         self.start_btn.config(state=DISABLED)
  146.         self.log_text.delete(1.0, END)
  147.         thread = threading.Thread(target=self.batch_extract, daemon=True)
  148.         thread.start()
  149. # ====================== 启动程序 ======================
  150. if __name__ == "__main__":
  151.     app = ttk.Window(themename="cosmo")
  152.     gui = GPSExtractorGUI(app)
  153.     app.mainloop()

 

 

文件下载 资源名称:图片GPS经纬度提取工具 应用平台:Windows 资源版本:v1.0 资源大小:28.1M
下载地址

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: