Commander1024
5404ae6437
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.
96 lines
3.7 KiB
Python
Executable File
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()
|