当前位置: 首页 > news >正文

照片EXIF数据统计与可视化

拍的照片越来越多,想要了解一下日常拍摄的习惯,便于后面换镜头、调整参数等操作,所以写了这个脚本来统计照片的EXIF数据。该脚本用于统计指定文件夹下所有JPG图片的EXIF数据,包括快门速度、ISO、焦距、光圈和拍摄时间,并生成相应的分布图。在使用时,需要将文中的代码段都粘贴到同一个文件中,然后修改folder_path变量为你要处理的文件夹路径,运行脚本即可。以下是脚本的详细说明。

依赖

  • Python 3.x
  • exifread库:用于读取图片的EXIF数据
  • matplotlib库:用于绘制分布图
  • numpy库:用于处理数值数据
  • pathlib库:用于处理文件路径
  • collections.Counter:用于统计频率

安装依赖

使用以下命令安装所需的Python库:

pip install exifread matplotlib numpy

使用方法

  1. 将脚本保存为photo_statistic.py
  2. 修改脚本中的folder_path变量,设置为你要处理的文件夹路径。
  3. 运行脚本:
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.1shutter_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 = 6focal_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 = 50focal_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_folderplot_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数据,相关统计信息将无法获取。

http://www.mrgr.cn/news/33289.html

相关文章:

  • 使用 PyTorch 实现 AlexNet 进行 MNIST 图像分类
  • C# 实现对指定句柄的窗口进行键盘输入的实现
  • 河南省测绘资质管理制度解析
  • 反向代理模块
  • 服务器集群的作用有什么?
  • Linux apt 命令
  • [数据结构与算法·C++] 笔记 1.5类与对象
  • 力扣之183.从不订购的客户
  • 软件测试APP测试过程中的关键步骤、工具使用及常见问题处理方法。
  • MySQL篇(事务 - 基础)
  • 【LLM】Ollama:本地大模型使用
  • 从编辑器到自动化脚本,提高编程效率的必备工具秘籍
  • 【C语言】const char*强制类型转换 (type cast)的告警问题
  • Qt 每日面试题 -2
  • react:React Hook函数
  • 华为OD机试真题-IPv4地址转换成整数-2024年OD统一考试(E卷)
  • 打开C嘎嘎的大门:你好,C嘎嘎!(2)
  • 语言RPA流程组件介绍--获取网页信息
  • 上位机图像处理和嵌入式模块部署(linux小系统开发)
  • 字符串 下【KMP再续】
  • GitHub每日最火火火项目(9.22)
  • 【Elasticsearch系列十八】Ik 分词器
  • 解锁电商新视野:京东商品详情API——您的精准商品信息探索利器
  • Java后端中的延迟队列实现:使用Redis与RabbitMQ的不同策略
  • AI学习指南深度学习篇-Adadelta简介
  • JavaScript(二)