radiation-tagger/exif_rad.py
Commander1024 5404ae6437 Finalized v0.2
Added copy function to be able to place files to outdir before modification.
Added verbose output about what it going to happen.
Added table header for output.
Removed obsolete "Processing..." message, as it was never visible.
2020-03-05 16:34:35 +01:00

96 lines
3.7 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Iterates over a bunch of .jpg or .cr2 files and matches
DateTimeOriginal from Exif tag to DateTime in a csv log
of a GeigerMuellerCounter and writes its value to the UserComment
Exif tag in µS/h"""
from datetime import datetime
import os
import shutil
import csv
import argparse
import pyexiv2
# SIFACTOR for GQ Geiger counters
# 300 series: 0.0065 µSv/h / CPM
# 320 series: 0.0065 µSv/h / CPM
# 500 series: 0.0065 µSv/h / CPM
# 500+ series: 0.0065 µSv/h / CPM for the first tube
# 600 series: 0.0065 µSv/h / CPM
# 600+ series: 0.002637 µSv/h / CPM
# Configure argument parser for cli options
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description='''A tool that writes
radiation levels (and optionally geocoordinates) to image files
and extracts the infos from external sources.''')
parser.add_argument('-si', '--sifactor', type=float, default=0.0065,
help='Factor to multiply recorded CPM with.')
parser.add_argument('csv', metavar='CSV', type=str,
help='Geiger counter history file in CSV format.')
parser.add_argument('photos', metavar='Photo', type=str, nargs='+',
help='One or multiple photo image files to process.')
parser.add_argument('-o', '--outdir', type=str, default='.',
help='Directory to output processed photos')
args = parser.parse_args()
# Inform the user about what is going to happen
if args.outdir == ".":
print('Modifying photos in place (overwrite)')
else:
print('Modifying photos in', str(args.outdir), '(copy)')
# Print table header
print('{:<15} {:<20} {:<22}'.format('filename', 'date / time', 'Exif UserComment'))
for srcphoto in args.photos:
# Get image file name out of path
photo_basename = os.path.basename(srcphoto)
# Decide whether to modify photo in place or to copy it to outdir first
# Then set the destination file as 'photo' to work on
if args.outdir == ".":
photo = srcphoto
else:
# be os aware and use the correct directory delimiter for destfile
dstphoto = os.path.join(args.outdir, photo_basename)
shutil.copy(srcphoto, dstphoto)
photo = dstphoto
# Load Exif data from image
metadata = pyexiv2.ImageMetadata(photo)
metadata.read()
tag = metadata['Exif.Photo.DateTimeOriginal']
# tag.value creates datetime object in pictime
pictime = tag.value
# Import GeigerCounter log
with open(args.csv, "r") as f:
csvreader = csv.reader(filter(lambda row: row[0] != '#', f),
delimiter=',', skipinitialspace=True)
print('Processing file:', photo_basename, end='\r')
for _, csvrawtime, csvrawcpm, _ in csvreader:
csvtime = datetime.fromisoformat(csvrawtime)
# Process image if its timestamp is found in CSV log (compares 2 datetime objects)
if csvtime == pictime:
rad = round(float(csvrawcpm) * args.sifactor, 2)
# Set key, value for new UserComment
key = 'Exif.Photo.UserComment'
new_comment = 'Radiation ☢ ' + str(rad) + ' µS/h'
metadata[key] = pyexiv2.ExifTag(key, new_comment)
# print found radiation levels
print('{:<15} {:<20} {:<22}'.format(photo_basename, str(pictime), new_comment))
# Write Exif tags to file
metadata.write()
break
else:
print('{:<15} {:<20} {:<22}'.format(photo_basename, str(pictime), 'NOT FOUND!'))
# close CSV file
f.close()