使用高德或者百度的逆地理编码API将照片根据拍摄地址进行分类

高德和百度地图都提供了逆地理编码的API来方便个人开发者进行开发,百度的API免费使用次数为300/天,高德为15000/月,照片多的话还是使用高德更方便:可以在对应的个人开发平台:高德开放平台百度开放平台 申请账号并使用API;

本文是在 ZXW_NUDT的相关文章的基础上进行修改的,侵删

以下代码使用python运行:

百度API
# -*- coding: utf-8 -*-
"""
Created on Tue May 27 15:36:57 2025

@author: F1_tsp6
"""
import exifread
import re
import json
import requests
import os
import shutil

# 转换经纬度格式
def latitude_and_longitude_convert_to_decimal_system(deg, min, sec):
    """
    经纬度转为小数
    :param deg: 度
    :param min: 分
    :param sec: 秒(可以是分数形式,如"30/1")
    :return: 十进制小数
    """
    try:
        sec = float(sec.split('/')[0]) / float(sec.split('/')[1]) if '/' in sec else float(sec)
        return float(deg) + (float(min) / 60.0) + (sec / 3600.0)
    except:
        return None

# 读取照片的GPS经纬度信息
def find_GPS_image(pic_path):
    GPS = {}
    date = ''
    with open(pic_path, 'rb') as f:
        tags = exifread.process_file(f)
        for tag, value in tags.items():
            # 纬度参考
            if tag == 'GPS GPSLatitudeRef':
                GPS['GPSLatitudeRef'] = str(value)
            # 经度参考
            elif tag == 'GPS GPSLongitudeRef':
                GPS['GPSLongitudeRef'] = str(value)
            # 海拔参考
            elif tag == 'GPS GPSAltitudeRef':
                GPS['GPSAltitudeRef'] = str(value)
            elif tag == 'GPS GPSLatitude':
                gps_latitude = value.values
                deg, min, sec = [str(x) for x in gps_latitude]
                GPS['GPSLatitude'] = latitude_and_longitude_convert_to_decimal_system(deg, min, sec)
            elif tag == 'GPS GPSLongitude':
                gps_longitude = value.values
                deg, min, sec = [str(x) for x in gps_longitude]
                GPS['GPSLongitude'] = latitude_and_longitude_convert_to_decimal_system(deg, min, sec)
            elif tag == 'GPS GPSAltitude':
                GPS['GPSAltitude'] = str(value)
            elif 'Date' in tag:
                date = str(value)
    return {'GPS_information': GPS, 'date_information': date}

# 输出经纬度(度、分、秒)
def Position(x, y):
    nsl = x
    ewl = y

    '''度'''
    angle1 = int(nsl)
    angle2 = int(ewl)

    '''分'''
    min1 = int((nsl - angle1) * 60)
    min2 = int((ewl - angle2) * 60)

    '''秒'''
    second1 = round((((nsl - angle1) * 60) - min1) * 60, 2)
    second2 = round((((ewl - angle2) * 60) - min2) * 60, 2)

    print("北纬:{}度{}分{}秒".format(angle1, min1, second1))
    print("东经:{}度{}分{}秒".format(angle2, min2, second2))

# 通过百度地图的API将GPS信息转换成地址
def find_address_from_GPS(GPS):
    """
    使用Geocoding API把经纬度坐标转换为结构化地址。
    :param GPS:
    :return:
    """
    secret_key = '使用自己的key'
    if not GPS['GPS_information']:
        return '该照片无GPS信息'
    
    lat = GPS['GPS_information'].get('GPSLatitude')
    lng = GPS['GPS_information'].get('GPSLongitude')
    
    if lat is None or lng is None:
        return '无效的GPS坐标'
    
    # 打印十进制度数的经纬度
    print("\n照片的经纬度(十进制度数):")
    print("纬度:{:.6f}".format(lat))
    print("经度:{:.6f}".format(lng))
    
    # 打印度分秒
    print("\n照片的经纬度(度分秒):")
    Position(lat, lng)

    baidu_map_api = f"https://api.map.baidu.com/reverse_geocoding/v3/?ak={secret_key}&location={lat},{lng}&output=json&pois=0"
    response = requests.get(baidu_map_api)
    
    try:
        content = response.json()
    except json.JSONDecodeError:
        return '无法解析百度地图API的响应'

    if content.get("status") != 0:
        return '百度地图API返回错误'

    result = content.get("result", {})
    formatted_address = result.get("formatted_address", "未知地址")
    address_component = result.get("addressComponent", {})
    province = address_component.get("province", "")
    city = address_component.get("city", "")
    district = address_component.get("district", "")
    location_desc = result.get("sematic_description", "")
    
    return formatted_address, province, city, district, location_desc

if __name__ == '__main__':
    pic_path = '输入自己的路径'#
    #image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp']
    files = os.listdir(pic_path)
    
    for file in files:
        source=pic_path +'/'+ file
        GPS_info = find_GPS_image(pic_path=source)
        address = find_address_from_GPS(GPS=GPS_info)
        #print("\n拍摄时间:" + GPS_info.get("date_information", "未知"))
        #print("照片拍摄地址:", end='')
        
        if isinstance(address, tuple) and address[2]!='':
            # address 为 (formatted_address, province, city, district, location_desc)
            # 打印详细地址信息
            print(f"城市:{address[2]}")
            folder_name = address[2]
            path = '输入自己的路径'+ folder_name
            os.makedirs(path, exist_ok=True)
            shutil.move(source, path)
            #print("\n详细地址信息:")
            #print(f"省份:{address[1]}")
            #print(f"区县:{address[3]}")
            #print(f"位置描述:{address[4]}")
        else:
            #path=pic_path +'/'+ '无地址'
            #shutil.move(source, path)
            print('移动失败:'+str(address))

也可以使用高德的API进行编码(两者的编码方式略有差异):

高德API
 # -*- coding: utf-8 -*-
"""
Created on Tue May 27 15:36:57 2025

@author: F1_tsp6
"""
import exifread
import re
import json
import requests

import os
import shutil

# 转换经纬度格式
def latitude_and_longitude_convert_to_decimal_system(deg, min, sec):
    """
    经纬度转为小数
    :param deg: 度
    :param min: 分
    :param sec: 秒(可以是分数形式,如"30/1")
    :return: 十进制小数
    """
    try:
        sec = float(sec.split('/')[0]) / float(sec.split('/')[1]) if '/' in sec else float(sec)
        return float(deg) + (float(min) / 60.0) + (sec / 3600.0)
    except:
        return None

# 读取照片的GPS经纬度信息
def find_GPS_image(pic_path):
    GPS = {}
    date = ''
    with open(pic_path, 'rb') as f:
        tags = exifread.process_file(f)
        for tag, value in tags.items():
            # 纬度参考
            if tag == 'GPS GPSLatitudeRef':
                GPS['GPSLatitudeRef'] = str(value)
            # 经度参考
            elif tag == 'GPS GPSLongitudeRef':
                GPS['GPSLongitudeRef'] = str(value)
            # 海拔参考
            elif tag == 'GPS GPSAltitudeRef':
                GPS['GPSAltitudeRef'] = str(value)
            elif tag == 'GPS GPSLatitude':
                gps_latitude = value.values
                deg, min, sec = [str(x) for x in gps_latitude]
                GPS['GPSLatitude'] = latitude_and_longitude_convert_to_decimal_system(deg, min, sec)
            elif tag == 'GPS GPSLongitude':
                gps_longitude = value.values
                deg, min, sec = [str(x) for x in gps_longitude]
                GPS['GPSLongitude'] = latitude_and_longitude_convert_to_decimal_system(deg, min, sec)
            elif tag == 'GPS GPSAltitude':
                GPS['GPSAltitude'] = str(value)
            elif 'Date' in tag:
                date = str(value)
    return {'GPS_information': GPS, 'date_information': date}

# 输出经纬度(度、分、秒)
def Position(x, y):
    nsl = x
    ewl = y

    '''度'''
    angle1 = int(nsl)
    angle2 = int(ewl)

    '''分'''
    min1 = int((nsl - angle1) * 60)
    min2 = int((ewl - angle2) * 60)

    '''秒'''
    second1 = round((((nsl - angle1) * 60) - min1) * 60, 2)
    second2 = round((((ewl - angle2) * 60) - min2) * 60, 2)

    print("北纬:{}度{}分{}秒".format(angle1, min1, second1))
    print("东经:{}度{}分{}秒".format(angle2, min2, second2))

# 通过百度地图的API将GPS信息转换成地址
def find_address_from_GPS(GPS):
    """
    使用Geocoding API把经纬度坐标转换为结构化地址。
    :param GPS:
    :return:
    """
    secret_key = '使用自己的key'
    if not GPS['GPS_information']:
        return '该照片无GPS信息'
    
    lat = GPS['GPS_information'].get('GPSLatitude')
    lng = GPS['GPS_information'].get('GPSLongitude')
    
    if lat is None or lng is None:
        return '无效的GPS坐标'
    
    # 打印十进制度数的经纬度
    print("\n照片的经纬度(十进制度数):")
    print("纬度:{:.6f}".format(lat))
    print("经度:{:.6f}".format(lng))
    
    # 打印度分秒
    print("\n照片的经纬度(度分秒):")
    Position(lat, lng)
    gaode_map_api = f"https://restapi.amap.com/v3/geocode/regeo?output=json&location={lng},{lat}&key={secret_key}&extensions=all"
    response = requests.get(gaode_map_api)
    
    try:
        content = response.json()
    except json.JSONDecodeError:
        return '无法解析高德地图API的响应'
    if content.get("status")!= '1':
        return '高德地图API返回错误'

    result = content.get("regeocode", {})
    formatted_address = result.get("formatted_address", "未知地址")
    address_component = result.get("addressComponent", {})
    province = address_component.get("province", "")
    city = address_component.get("city", "")
    district = address_component.get("district", "")
    #location_desc = result.get("sematic_description", "")
    
    return formatted_address, province, city, district

if __name__ == '__main__':
    pic_path = 'G:/2T内容/20230406备份_待完全恢复/图片/待GPS分地区'
    #image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp']
    files = os.listdir(pic_path)
    
    for file in files:
        source=pic_path +'/'+ file
        GPS_info = find_GPS_image(pic_path=source)
        address = find_address_from_GPS(GPS=GPS_info)
        #print("\n拍摄时间:" + GPS_info.get("date_information", "未知"))
        #print("照片拍摄地址:", end='')
        
        if isinstance(address, tuple) and str(address[2])!='[]':
            # address 为 (formatted_address, province, city, district)
            # 打印详细地址信息
            print(f"{file}城市:{address[2]}")
            folder_name = address[2]
            path = 'G:/2T内容/20230406备份_待完全恢复/图片/'+ folder_name
            os.makedirs(path, exist_ok=True)
            shutil.move(source, path)
            #print("\n详细地址信息:")
            #print(f"省份:{address[1]}")
            #print(f"区县:{address[3]}")
            #print(f"位置描述:{address[4]}")
        else:
            #path=pic_path +'/'+ '无地址'
            #shutil.move(source, path)
            print('移动失败:'+str(address))
posted @ 2025-05-30 09:42  color_bar  阅读(45)  评论(0)    收藏  举报