照片EXIF数据统计与可视化

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

依赖

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

安装依赖

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

sh 复制代码
pip install exifread matplotlib numpy

使用方法

  1. 将脚本保存为photo_statistic.py
  2. 修改脚本中的folder_path变量,设置为你要处理的文件夹路径。
  3. 运行脚本:
sh 复制代码
python photo_statistic.py

代码说明

导入依赖

python 复制代码
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、焦距、光圈和拍摄时间。

python 复制代码
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数据。

python 复制代码
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、焦距和光圈的分布图,并统计指定焦距的时间分布。

python 复制代码
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_folderplot_statistics函数。

python 复制代码
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数据,相关统计信息将无法获取。
相关推荐
lili-felicity34 分钟前
CANN模型量化详解:从FP32到INT8的精度与性能平衡
人工智能·python
数据知道37 分钟前
PostgreSQL实战:详解如何用Python优雅地从PG中存取处理JSON
python·postgresql·json
ZH15455891311 小时前
Flutter for OpenHarmony Python学习助手实战:面向对象编程实战的实现
python·学习·flutter
玄同7651 小时前
SQLite + LLM:大模型应用落地的轻量级数据存储方案
jvm·数据库·人工智能·python·语言模型·sqlite·知识图谱
User_芊芊君子1 小时前
CANN010:PyASC Python编程接口—简化AI算子开发的Python框架
开发语言·人工智能·python
白日做梦Q1 小时前
Anchor-free检测器全解析:CenterNet vs FCOS
python·深度学习·神经网络·目标检测·机器学习
喵手1 小时前
Python爬虫实战:公共自行车站点智能采集系统 - 从零构建生产级爬虫的完整实战(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·采集公共自行车站点·公共自行车站点智能采集系统·采集公共自行车站点导出csv
喵手1 小时前
Python爬虫实战:地图 POI + 行政区反查实战 - 商圈热力数据准备完整方案(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·地区poi·行政区反查·商圈热力数据采集
熊猫_豆豆2 小时前
YOLOP车道检测
人工智能·python·算法
nimadan122 小时前
**热门短剧小说扫榜工具2025推荐,精准捕捉爆款趋势与流量
人工智能·python