照片EXIF数据统计与可视化
创作时间:
作者:
@小白创作中心
照片EXIF数据统计与可视化
引用
CSDN
1.
https://blog.csdn.net/qq_42688495/article/details/142433222
随着数码摄影的普及,越来越多的人开始关注照片的拍摄参数和拍摄习惯。本文将介绍如何使用Python脚本统计和可视化照片的EXIF数据,包括快门速度、ISO、焦距、光圈和拍摄时间,并生成相应的分布图。
依赖
- Python 3.x
- exifread库:用于读取图片的EXIF数据
- matplotlib库:用于绘制分布图
- numpy库:用于处理数值数据
- pathlib库:用于处理文件路径
- collections.Counter:用于统计频率
安装依赖
使用以下命令安装所需的Python库:
pip install exifread matplotlib numpy
使用方法
- 将脚本保存为
photo_statistic.py。 - 修改脚本中的
folder_path变量,设置为你要处理的文件夹路径。 - 运行脚本:
python photo_statistic.py
代码说明
导入依赖
from pathlib import Path
import exifread
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import numpy as np
from collections import Counter
获取EXIF数据
get_exif_data函数用于读取图片的EXIF数据,并提取快门速度、ISO、焦距、光圈和拍摄时间。
def get_exif_data(image_path):
with open(image_path, 'rb') as f:
tags = exifread.process_file(f)
shutter_speed = tags.get('EXIF ExposureTime') or tags.get('EXIF ShutterSpeedValue')
iso = tags.get('EXIF ISOSpeedRatings')
focal_length = tags.get('EXIF FocalLength')
aperture = tags.get('EXIF FNumber') or tags.get('EXIF ApertureValue')
datetime = tags.get('EXIF DateTimeOriginal') or tags.get('Image DateTime')
return {
'file': image_path,
'shutter_speed': shutter_speed,
'iso': iso,
'focal_length': focal_length,
'aperture': aperture,
'datetime': datetime
}
处理文件夹中的图片
process_images_in_folder函数遍历指定文件夹下的所有JPG图片,并调用get_exif_data函数获取每张图片的EXIF数据。
def process_images_in_folder(folder_path):
results = []
folder = Path(folder_path)
for image_path in folder.rglob('*.jpg'):
results.append(get_exif_data(image_path))
return results
绘制统计图
plot_statistics函数用于绘制快门速度、ISO、焦距和光圈的分布图,并统计指定焦距的时间分布。
def plot_statistics(results):
shutter_speeds = [float(result['shutter_speed'].values[0]) for result in results if result['shutter_speed']]
isos = [int(result['iso'].values[0]) for result in results if result['iso']]
focal_lengths = [float(result['focal_length'].values[0].num) / float(result['focal_length'].values[0].den) for result in results if result['focal_length']]
apertures = [float(result['aperture'].values[0].num) / float(result['aperture'].values[0].den) for result in results if result['aperture']]
dates = [result['datetime'].values.split(' ')[0].replace(':', '.') for result in results if result['datetime']]
# 删除快门速度大于阈值的数据
shutter_speeds_thres = 0.1
shutter_speeds = [speed for speed in shutter_speeds if speed <= shutter_speeds_thres]
fig, axs = plt.subplots(2, 1)
# 将快门速度转换为分数格式
def format_shutter_speed(speed):
return (f"1/{(1/speed):.0f}" if speed != 0 else "0") if speed < 1 else str(speed)
# 绘制快门速度分布图并将x轴刻度标签设置为分数格式
axs[0].hist(shutter_speeds, bins=100, color='blue', edgecolor='black')
axs[0].set_title('Shutter Speed Distribution' + f' (Threshold: {shutter_speeds_thres}s)')
axs[0].set_xlabel('Shutter Speed (s)')
# 使用分数表示快门速度
axs[0].xaxis.set_major_formatter(ticker.FuncFormatter(lambda x, _: format_shutter_speed(x)))
axs[0].set_ylabel('Frequency')
axs[1].hist(focal_lengths, bins=100, color='red', edgecolor='black')
axs[1].set_title('Focal Length Distribution')
axs[1].set_xlabel('Focal Length (mm)')
axs[1].set_ylabel('Frequency')
plt.tight_layout()
# 标出频率最高的N个焦距
N = 6
focal_length_counts = np.bincount(focal_lengths)
most_common_focal_lengths = np.argsort(focal_length_counts)[-N:][::-1]
for focal_length in most_common_focal_lengths:
axs[1].text(focal_length, focal_length_counts[focal_length], str(focal_length), color='black')
# 统计所有时间的频率
dates_freq = Counter(dates)
# 统计指定焦距的时间分布
def get_focal_length_time_distribution(results, focal_length):
date_of_focal_length = []
for result in results:
if result['focal_length'] and result['focal_length'].values[0].num / result['focal_length'].values[0].den == focal_length:
date_of_focal_length.append(result['datetime'].values)
date_of_focal_length.sort()
# 以空格分隔时间字符串,只保留日期部分
date_of_focal_length = [time.split(' ')[0].replace(':', '.') for time in date_of_focal_length]
# 统计相同时间的频率
return Counter(date_of_focal_length)
prefix_focal_length = 50
focal_length_200mm_freq = get_focal_length_time_distribution(results, prefix_focal_length)
fig, ax = plt.subplots()
# dates_freq排序
dates_freq = dict(sorted(dates_freq.items()))
ax.barh(list(dates_freq.keys()), list(dates_freq.values()), alpha=0.5, label='All')
ax.barh(list(focal_length_200mm_freq.keys()), list(focal_length_200mm_freq.values()), label='Focal Length ' + str(prefix_focal_length) + 'mm')
ax.legend()
ax.set_xlabel('Frequency')
ax.set_ylabel('Date')
plt.show()
主函数
main函数设置文件夹路径,并调用process_images_in_folder和plot_statistics函数。
def main():
folder_path = 'c:/Users/25503/Desktop/照片合集'
results = process_images_in_folder(folder_path)
plot_statistics(results)
if __name__ == "__main__":
main()
运行结果
注意事项
- 确保文件夹路径正确,并且文件夹中包含JPG格式的图片。
- 脚本会读取图片的EXIF数据,如果图片没有EXIF数据,相关统计信息将无法获取。
热门推荐
几何建模Brep边界表达法
重拾生活的“钥匙”:脑卒中后的康复功能训练
中风的前兆与急救:关键时刻的救命指南
荆棘冠的象征意义
水经注名言名句
著名歌手方大同去世,什么是气胸,怎样预防气胸发作
研究发现气溶胶对雾霾有减轻作用
【青图云荐读】丁玲的《太阳照在桑干河上》
是时候说再见了,单踏板模式正式出局?
孔雀鱼性别分辨技巧:轻松识别公母鱼的外观特征
如今的PC游戏需要多大显存的显卡才够用?8GB、12GB还是16GB?
超级痒!手指缝的水泡是湿疹、汗疱还是癣?小心得了……
什么东西都舍不得扔的人,往往是这三种人,相当准!
驱动直流电机程序怎么写
房间有老鼠怎么驱除?让家居更安全舒适
汉字到底有多少个?收字最多的字典是哪一部?
临时加价、额外收费、退款困难,乱象频出的网约车平台,如何加强管理?
开学季| 高一新生如何快速适应高中学习生活?(建议高一学生与家长阅读与收藏)
看看人家吃什么:各国早餐大比拼
重磅!个税扣除范围扩大!(2025最新最全个税税率表)
长期咳嗽有痰要警惕三种病咳嗽严重
小儿发热的各种测温方法!
吃得过多后喝水能加速代谢吗?医生为你解答
宋代点茶文化中的“斗茶”与“茶百戏”探究
什么是斗彩:从明代到清代的瓷器艺术瑰宝
报交警的流程是什么?如何合法处理交通事故?
LED灯管分正负极吗?接线方法与技巧详解
心脏支架病人可以吃南瓜籽吗?医生的专业解答来了
狗狗晚上一直叫?原因大揭秘与应对之策
美国航母炸不沉,为何东风导弹能一击致命?