From ce65eb4ceee7ae32cd8bcd6a487814c0bfd52127 Mon Sep 17 00:00:00 2001 From: Commander1024 Date: Sat, 14 Mar 2020 17:32:29 +0100 Subject: [PATCH] Revert "Enriched class comments with arguments and return values." This reverts commit 8ea6524238cc771a9b0165361075695818adadf1. I'm stupid, and deleted the wrong file. Fixed it. --- exif_rad.py | 141 --------------------------------------------------- functions.py | 53 +++++-------------- rad_tag.py | 103 +++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 180 deletions(-) delete mode 100755 exif_rad.py create mode 100644 rad_tag.py diff --git a/exif_rad.py b/exif_rad.py deleted file mode 100755 index 046ae64..0000000 --- a/exif_rad.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# This file is now obsolete and is going to disappear. - -"""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, timedelta -import os -import shutil -import csv -import argparse -import pytz -import pyexiv2 -import gpxpy - -# 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 unix-tyle tool that - extracts GPS and/or radiation data from GPX/CSV files and writes - them into the Exif tags of given photos.''') -parser.add_argument('-si', '--sifactor', type=float, default=0.0065, - help='Factor to multiply recorded CPM with.') -parser.add_argument('-tz', '--timezone', type=str, metavar='Timezone', default='utc', - help='''Manually set timezone of CSV / and Photo timestamp, - defaults to UTC if omitted. This is useful, if the GPS-Logger - saves the time incl. timezone''') -parser.add_argument('-d', '--dry', action='store_true', - help='Dry-run, do not actually write anything.') -parser.add_argument('csv', metavar='CSV', type=str, - help='Geiger counter history file in CSV format.') -parser.add_argument('-g', '--gpx', metavar='GPX', type=str, - help='GPS track in GPX 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() - -# Create timezone datetime object -localtz = pytz.timezone(args.timezone) - -# Inform the user about what is going to happen -if args.dry is not None: - if args.outdir == ".": - print('Modifying photos in place (overwrite)') - else: - print('Modifying photos in', str(args.outdir), '(copy)') -else: - print('Not modifying anything. Just print what would happen without --dry') - -# Print table header -print('{:<15} {:<25} {:<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) - # Don't copy image if in dry-run mode - if args.dry == 'True': - shutil.copy(srcphoto, dstphoto) - photo = dstphoto - else: - photo = srcphoto - - # Load Exif data from image - metadata = pyexiv2.ImageMetadata(photo) - metadata.read() - tag = metadata['Exif.Photo.DateTimeOriginal'] - # tag.value creates datetime object in pictime - picnaivetime = tag.value - # Set timezone - pictime = picnaivetime.astimezone(localtz) - - # Import GeigerCounter log - with open(args.csv, "r") as f: - csvreader = csv.reader(filter(lambda row: row[0] != '#', f), - delimiter=',', skipinitialspace=True) - - for _, csvrawtime, csvrawcpm, _ in csvreader: - csvnaivetime = datetime.fromisoformat(csvrawtime) - # Set timezone - csvtime = csvnaivetime.astimezone(localtz) - # 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} {:<25} {:<22}'.format(photo_basename, str(pictime), new_comment)) - # Write Exif tags to file, if not in dry-run mode - if args.dry == 'True': - metadata.write() - break - else: - print('{:<15} {:<25} {:<22}'.format(photo_basename, str(pictime), 'NOT FOUND!')) - # close CSV file - f.close() - - # Import GPX track(s) - if args.gpx is not None: - gpx_file = open(args.gpx, 'r') - gpxreader = gpxpy.parse(gpx_file) - - for waypoint in gpxreader.waypoints: - for track in gpxreader.tracks: - for segment in track.segments: - for point in segment.points: - # datetimes match with 1 minute precision - delta = timedelta(seconds=10) - if abs(point.time - pictime) < delta: - valuelist = [] - row = [point.time, point.latitude, point.longitude] - valuelist.append(row) - print(valuelist) - #print(pictime, 'vs.', point.time, 'Delta:', pictime - point.time) -# print('Point at ({0},{1}) -> {2}'.format(point.latitude, point.longitude, point.time)) diff --git a/functions.py b/functions.py index cc2d28b..3b65f81 100644 --- a/functions.py +++ b/functions.py @@ -10,20 +10,7 @@ from fractions import Fraction import pyexiv2 class Radiation: - ''' - Reiceives Values vom CSV file and creates a list of the relevant data - - Arguments: - timestamp: Date/time string from CSV as string - radiation: Radiation from CSV in CP/M as float - local_timezone: timezone for timezone-unware CSV / Photo, if GPX is timezone aware - si_factor: CP/M to (µS/h) conversion factor - specific to GMC-tube - - Returns: - timestamp: timestamp of CSV value als datetime object - radiation: radiation in µS/h as str (for Exif comment, UTF-8) - ''' - + ''' Handles CSV processing. ''' def __init__(self, timestamp, radiation, local_timezone, si_factor): self.timestamp = self._time_conversion(timestamp, local_timezone) self.radiation = self._radiation_conversion(radiation, si_factor) @@ -43,20 +30,7 @@ class Radiation: return radiation class Photo: - ''' - Reads Exif metadata. - - Arguments: - photo: source photo () - local_timezone: timezone for timezone-unware CSV / Photo, if GPX is timezone aware - dest_dir: destination directory where the photo is going to be copied to. - dry_run: whether to acutally write (True / False) - - Returns: - self.get_date: timestamp of photo als datetime object - self.get_target_photo: full path to photo file to work on - ''' - + ''' Reads and writes Exif metadata. ''' def __init__(self, photo, local_timezone, dest_dir, dry_run): self.get_date = self._get_creation_date(photo, local_timezone) self.get_target_photo = self._copy_photo(photo, dest_dir, dry_run) @@ -83,6 +57,7 @@ class Photo: # Load Exif data from photo metadata = pyexiv2.ImageMetadata(photo) metadata.read() + print(metadata) date = metadata['Exif.Photo.DateTimeOriginal'] # date.value creates datetime object in pic_naive_time pic_naive_time = date.value @@ -91,8 +66,7 @@ class Photo: return pic_aware_time class Exif: - ''' - Converts, compiles and writes Exif-Tags from given arguemnts. + ''' Converts, compiles and writes Exif-Tags from given values. Arguments: photo: file name of photo to modify @@ -101,18 +75,14 @@ class Exif: longitude: longitude as float elevation: elevation as float dry_run: whether to acutally write (True / False) - - Returns: - Latitude / Longitude in degrees - Exif-Comment that has been written (incl. radiation) ''' def __init__(self, photo, radiation, latitude, longitude, elevation, dry_run): - self.write_exif = self._write_exif(photo, radiation, latitude, - longitude, elevation, dry_run) + # self.get_degree = self._to_degree(value, loc) + self.write_exif = self._write_exif(photo, radiation, latitude, longitude, elevation, dry_run) - def __repr__(self): - return 'Position: %s, %s: %s ' % self.write_exif +# def __repr__(self): +# return 'Photo: %s Creation Date: %s' % (str(self.get_target_photo), str(self.get_date)) def _to_degree(self, value, loc): if value < 0: @@ -136,6 +106,9 @@ class Exif: latitude_degree = self._to_degree(latitude, ["S", "N"]) longitude_degree = self._to_degree(longitude, ["W", "E"]) + print(latitude_degree) + print(longitude_degree) + # convert decimal coordinates into fractions required for pyexiv2 exiv2_latitude = (Fraction(latitude_degree[0] * 60 + latitude_degree[1], 60), Fraction(int(round(latitude_degree[2] * 100, 0)), 6000), @@ -159,8 +132,10 @@ class Exif: metadata['Exif.GPSInfo.GPSVersionID'] = '2 0 0 0' metadata['Exif.Photo.UserComment'] = new_comment + print(new_comment) + # Write Exif tags to file, if not in dry-run mode if dry_run is not True: metadata.write() - return latitude_degree, longitude_degree, new_comment + return new_comment diff --git a/rad_tag.py b/rad_tag.py new file mode 100644 index 0000000..26efd2d --- /dev/null +++ b/rad_tag.py @@ -0,0 +1,103 @@ +#!/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 ''' + +import csv +import argparse +import pytz +import gpxpy +from functions import Radiation, Photo, Exif + +# 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 unix-tyle tool that + extracts GPS and/or radiation data from GPX/CSV files and writes + them into the Exif tags of given photos.''') +parser.add_argument('-si', '--sifactor', type=float, default=0.0065, + help='Factor to multiply recorded CPM with.') +parser.add_argument('-tz', '--timezone', type=str, metavar='Timezone', default='utc', + help='''Manually set timezone of CSV / and Photo timestamp, + defaults to UTC if omitted. This is useful, if the GPS-Logger + saves the time incl. timezone''') +parser.add_argument('-d', '--dry', action='store_true', + help='Dry-run, do not actually write anything.') +parser.add_argument('csv', metavar='CSV', type=str, + help='Geiger counter history file in CSV format.') +parser.add_argument('-g', '--gpx', metavar='GPX', type=str, + help='GPS track in GPX 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() + +# Create timezone datetime object +local_timezone = pytz.timezone(args.timezone) + +# Initialize two empty lists for comparison +radiation_list = [] +position_list = [] + +# Import GeigerCounter log +with open(args.csv, "r") as f: + csv = csv.reader(filter(lambda row: row[0] != '#', f), + delimiter=',', skipinitialspace=True) + + for _, csv_raw_time, csv_raw_cpm, _ in csv: + radiation = Radiation(csv_raw_time, csv_raw_cpm, local_timezone, args.sifactor) + radiation_list.append(radiation) + + # close CSV file + f.close() + +# Import GPX track(s) +if args.gpx is not None: + gpx_file = open(args.gpx, 'r') + gpx_reader = gpxpy.parse(gpx_file) + + for waypoint in gpx_reader.waypoints: + for track in gpx_reader.tracks: + for segment in track.segments: + for point in segment.points: + position = [point.time, point.latitude, point.longitude, point.elevation] + position_list.append(position) + +# Inform the user about what is going to happen +if args.dry is True: + print('Not modifying anything. Just print what would happen without --dry') +else: + if args.outdir == ".": + print('Modifying photos in place (overwrite)') + else: + print('Modifying photos in', str(args.outdir), '(copy)') + +for src_photo in args.photos: + photo = Photo(src_photo, local_timezone, args.outdir, args.dry) + print(photo.get_target_photo, photo.get_date) + + # Here the matching magic has to happen + latitude = 51.0234024 + longitude = 7.248347 + radiation = 9001.15 + elevation = 56.079345703125 + + # Write exif data + exif_tags = Exif(photo.get_target_photo, radiation, latitude, longitude, elevation, args.dry) + print(exif_tags) + +# Print table header +print('{:<15} {:<25} {:<22}'.format('filename', 'date / time', 'Exif UserComment')) \ No newline at end of file