|
|
|
import numpy as np
|
|
|
|
from datetime import datetime, timedelta
|
|
|
|
import sys
|
|
|
|
from time import strptime
|
|
|
|
from PIL import Image, ImageFont
|
|
|
|
|
|
|
|
def divide_chunks(l, n):
|
|
|
|
"""
|
|
|
|
Splits a list into chunks of length n. Used to process the images in chunks.
|
|
|
|
"""
|
|
|
|
for i in range(0, len(l), n):
|
|
|
|
yield l[i : i + n]
|
|
|
|
|
|
|
|
# Sourced from https://gist.github.com/victorkristof/b9d794fe1ed12e708b9d
|
|
|
|
def datenum_to_datetime(datenum):
|
|
|
|
"""
|
|
|
|
Convert Matlab datenum into Python datetime.
|
|
|
|
:param datenum: Date in datenum format
|
|
|
|
:return: Datetime object corresponding to datenum.
|
|
|
|
"""
|
|
|
|
days = datenum % 1
|
|
|
|
hours = days % 1 * 24
|
|
|
|
minutes = hours % 1 * 60
|
|
|
|
seconds = np.round(minutes % 1 * 60)
|
|
|
|
return datetime.fromordinal(int(datenum)) \
|
|
|
|
+ timedelta(days=int(days)) \
|
|
|
|
+ timedelta(hours=int(hours)) \
|
|
|
|
+ timedelta(minutes=int(minutes)) \
|
|
|
|
+ timedelta(seconds=int(seconds)) \
|
|
|
|
- timedelta(days=366)
|
|
|
|
|
|
|
|
|
|
|
|
# Sourced from https://stackoverflow.com/questions/32237862/find-the-closest-date-to-a-given-date
|
|
|
|
def nearest(all_dates, target_date_raw):
|
|
|
|
abs_deltas_from_target_date = np.absolute(all_dates - target_date_raw)
|
|
|
|
index_of_min_delta_from_target_date = np.argmin(abs_deltas_from_target_date)
|
|
|
|
closest_date = all_dates[index_of_min_delta_from_target_date]
|
|
|
|
return closest_date
|
|
|
|
|
|
|
|
|
|
|
|
def progressbar(it, prefix="", size=60, out=sys.stdout): # Python3.3+
|
|
|
|
count = len(it)
|
|
|
|
def show(j):
|
|
|
|
x = int(size*j/count)
|
|
|
|
print("{}[{}{}] {}/{}".format(prefix, u"#"*x, "."*(size-x), j, count),
|
|
|
|
end='\r', file=out, flush=True)
|
|
|
|
show(0)
|
|
|
|
for i, item in enumerate(it):
|
|
|
|
yield item
|
|
|
|
show(i+1)
|
|
|
|
print("\n", flush=True, file=out)
|
|
|
|
|
|
|
|
|
|
|
|
class RegisteredImage():
|
|
|
|
|
|
|
|
def __init__(self, pathname, filename):
|
|
|
|
self.pathname = pathname
|
|
|
|
self.filename = filename
|
|
|
|
filename_list = filename.split(".")
|
|
|
|
date = filename_list[3].split("_")
|
|
|
|
if 'snap' in filename_list:
|
|
|
|
self.contributor = filename_list[8] # Mitch filename format
|
|
|
|
else:
|
|
|
|
self.contributor = filename_list[6] # Leaman filename format
|
|
|
|
self.site = filename_list[6]
|
|
|
|
self.posix_time = filename_list[0]
|
|
|
|
self.timezone = filename_list[4]
|
|
|
|
self.year = filename_list[5]
|
|
|
|
self.month = '{:02d}'.format(strptime(filename_list[2],'%b').tm_mon) # Ensure 2-digit format
|
|
|
|
self.day = date[0]
|
|
|
|
self.hour = date[1]
|
|
|
|
self.minute = date[2]
|
|
|
|
self.second = date[3]
|
|
|
|
|
|
|
|
self.tide = None
|
|
|
|
self.tag = None
|
|
|
|
self.width = None
|
|
|
|
self.height = None
|
|
|
|
self.font = None
|
|
|
|
|
|
|
|
def get_tide(self, tides_df):
|
|
|
|
|
|
|
|
# Account for daylight savings
|
|
|
|
# ASSUMPTION: All .mat tide files are either AEST or AEDT
|
|
|
|
if self.timezone == 'AEDT':
|
|
|
|
self.hour = str(int(self.hour) - 1)
|
|
|
|
date_string = self.year + '-' + self.month + '-' + self.day + ' ' + self.hour + ':' + self.minute + ':' + self.second
|
|
|
|
img_datetime = datetime.strptime(date_string, "%Y-%m-%d %H:%M:%S") # Image date/time as a datetime object
|
|
|
|
tide_date = nearest(tides_df['time'], img_datetime)
|
|
|
|
tide = tides_df.loc[tides_df['time'] == tide_date, 'tide level']
|
|
|
|
tide = tide.iloc[0]
|
|
|
|
|
|
|
|
self.tide = "{:.2f}".format(tide)
|
|
|
|
|
|
|
|
def create_tag(self):
|
|
|
|
# Create image tag
|
|
|
|
hour = self.hour.zfill(2)
|
|
|
|
minute = self.minute.zfill(2)
|
|
|
|
|
|
|
|
if self.tide:
|
|
|
|
tide = self.tide
|
|
|
|
if float(self.tide) >= 0:
|
|
|
|
tide = '+' + self.tide
|
|
|
|
self.tag = ('Date:' + self.year + '/' + self.month + '/' + self.day +
|
|
|
|
' Time:' + hour + ':' + minute +
|
|
|
|
' Tide:' + tide + 'm AHD' +
|
|
|
|
' Contributor:' + self.contributor)
|
|
|
|
else:
|
|
|
|
self.tag = ('Date:' + self.year + '/' + self.month + '/' + self.day +
|
|
|
|
' Time:' + hour + ':' + minute +
|
|
|
|
' Contributor:' + self.contributor)
|
|
|
|
|
|
|
|
def get_dimensions(self):
|
|
|
|
image = Image.open(self.pathname)
|
|
|
|
# White Text Box
|
|
|
|
self.width, self.height = image.size
|
|
|
|
|
|
|
|
|
|
|
|
def get_font(self):
|
|
|
|
|
|
|
|
image = Image.open(self.pathname)
|
|
|
|
fontsize = 1
|
|
|
|
if self.tide:
|
|
|
|
img_fraction = 0.95
|
|
|
|
else:
|
|
|
|
img_fraction = 0.85
|
|
|
|
font = ImageFont.truetype("fonts/Courier New Bold.ttf", fontsize)
|
|
|
|
generic_large_tag = "1641775682.Mon.Jan.10_11_48_02.AEDT.2022.byron.snap.KateThornborough123"
|
|
|
|
|
|
|
|
while font.getsize(generic_large_tag)[0] < img_fraction*image.size[0]:
|
|
|
|
# iterate until the text size is just larger than the criteria
|
|
|
|
fontsize += 1
|
|
|
|
font = ImageFont.truetype("fonts/Courier New Bold.ttf", fontsize)
|
|
|
|
self.font = ImageFont.truetype("fonts/Courier New Bold.ttf", fontsize)
|