惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 三生石上(FineUI控件)
大猫的无限游戏
大猫的无限游戏
Hugging Face - Blog
Hugging Face - Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Vercel News
Vercel News
人人都是产品经理
人人都是产品经理
G
Google Developers Blog
WordPress大学
WordPress大学
S
SegmentFault 最新的问题
雷峰网
雷峰网
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Jina AI
Jina AI
博客园 - 叶小钗
D
DataBreaches.Net
D
Docker
月光博客
月光博客
博客园 - 司徒正美
Last Week in AI
Last Week in AI
有赞技术团队
有赞技术团队
腾讯CDC
酷 壳 – CoolShell
酷 壳 – CoolShell

又见苍岚

COLMAP PatchMatch Stereo 算法详解 事件驱动的状态机框架:从理论到工程实践 Git 在国内网络环境下无法 Push 的排查与修复 —— 配置 Clash 代理 分段五次多项式插值原理详解 路径插值方法深度对比研究 Claude Code 使用指南 OpenClaw 记忆管理与技能创建指南 CBS(Conflict-Based Search)算法详解 A* 算法及其变种详解 OpenClaw 配置多 Agents Windows Powershell 无法加载文件,因为在此系统上禁止运行脚本问题的解决方案 MaxClaw 安装流程 大模型 AI 名词介绍 AList 网盘聚合工具简介 Protobuf 简介与测试 Claude Code 简介以及 GLM 4.7 模型接入 Github 歌词下载工具 163MusicLyrics Python __getattr__ 懒加载 Python TypedDict 机器人仿真平台 Gazebo 安装记录 机器人仿真平台 Gazebo 简介 多机器人路径规划问题(Multi-Agent Path Finding, MAPF)简介 3D 坐标系变换的理解 3D 旋转矩阵基本概念 MongoDB Compass 介绍 Python 环境管理工具 uv Flutter 开发指南 Snipaste 安装下载与黑屏问题解决方案 全局路径规划算法记录 2025 Python 版本性能测试
Python exifread 读取修改过的 jpeg 信息错误问题修复
Yiwei Zhang · 2025-12-08 · via 又见苍岚
from pyexiv2 import Image as xmpImage
from pyexiv2 import ImageData
import vvdutils as vv

# def phase_all_exif_info(image_path):
# img = xmpImage(image_path)
# total_info = dict()

# xmp_data = img.read_xmp()
# total_info.update(xmp_data)

# exif_info = img.read_exif()
# total_info.update(exif_info)

# return total_info

def signed_str_to_float(s):
try:
# 去除前后空格后直接转换
return float(s.strip())
except ValueError as e:
print(f"转换失败: 输入 '{s}' 不是有效的浮点数字符串")
return None

def phase_all_exif_info(image_path):
img = xmpImage(image_path)
total_info = dict()

xmp_data = img.read_xmp()
total_info.update(xmp_data)

exif_info = img.read_exif()
total_info.update(exif_info)

return total_info

'''
修改图像中EXIF和XMP数据, 原地操作,直接修改存储到当前图像
数据示例如下:
changes = { 'Xmp.drone-dji.AbsoluteAltitude': '+10000' }
'''
def modify_xmp_and_exif(image_path, xmp_changes=None, exif_changes=None):
"""
只修改 XMP 元数据,不操作像素数据
"""
try:
# 1. 打开图片读取元数据(仅加载元数据,不加载完整像素)
with xmpImage(image_path) as img:
# 如果提供了 EXIF 修改,应用它
if exif_changes:
img.modify_exif(exif_changes)
else:
img.modify_exif({})

# 如果提供了 XMP 修改,应用它
if xmp_changes:
img.modify_xmp(xmp_changes)

# 3. 获取修改后的完整元数据(包括 EXIF、XMP)
exif = img.read_exif()
xmp = img.read_xmp()

# 4. 用原始图片创建 ImageData 对象(承载像素和原始元数据)
with open(image_path, 'rb') as f:
img_data = ImageData(f.read())

# 5. 将修改后的元数据写入 ImageData(仅更新元数据区)
img_data.modify_exif(exif)
img_data.modify_xmp(xmp)

except FileNotFoundError:
print(f"错误:找不到文件 '{image_path}'")
except Exception as e:
print(f"处理图片时发生错误: {e}")

if __name__ == '__main__':
utm_zone = "WGS84 UTM 45N"
ariport_offset_lon = 1000 # cur_pos - airport_pos
ariport_offset_lat = 1000
ariport_offset_alt = 1000

image_file = 'ori.JPG'

exif_info = phase_all_exif_info(image_file)

lon = exif_info['Xmp.drone-dji.GpsLongitude']
lon = signed_str_to_float(lon)
lat = exif_info['Xmp.drone-dji.GpsLatitude']
lat = signed_str_to_float(lat)
alt = exif_info['Xmp.drone-dji.AbsoluteAltitude']
alt = signed_str_to_float(alt)
pt = [lon, lat]
point_image = vv.Point(pt[1], pt[0], utm_zone=utm_zone)
print(f'1:lon:{lon}, lat:{lat}')
point_image_x_utm = point_image.x_utm - ariport_offset_lon
point_image_y_utm = point_image.y_utm - ariport_offset_lat
new_point = vv.Point.from_xy_utm(utm_zone, point_image_x_utm, point_image_y_utm)

print(f'2:lon:{new_point.lon}, lat:{new_point.lat}')

update_lon = f'+{new_point.lon}' if new_point.lon > 0 else f'-{new_point.lon}'
update_lat = f'+{new_point.lat}' if new_point.lat > 0 else f'-{new_point.lat}'
changes = {
'Xmp.drone-dji.AbsoluteAltitude': '+10000',
'Xmp.drone-dji.GpsLongitude': update_lon,
'Xmp.drone-dji.GpsLatitude': update_lat
}
modify_xmp_and_exif(image_file, changes)
out_exif_info = phase_all_exif_info(image_file)
pass