7 Commits

4 changed files with 347 additions and 275 deletions

View File

@@ -1,7 +1,7 @@
# Localization file for video2geoframes.py script # Localization file for video2geoframes.py
# English (US / World) # English (US / World)
# #
# Last edition : 2024-06-22 # Last edition : 2024-06-23
[ui] [ui]
@@ -12,6 +12,7 @@ This script is designed to create geotagged frames from video and GPX track."""
end = "End of program, press Enter to quit." end = "End of program, press Enter to quit."
paths_title = "## Paths" paths_title = "## Paths"
parameters_title = "## Process parameters" parameters_title = "## Process parameters"
tags_title = "## Additional tags"
metadata = """{} ({} {}B)\n metadata = """{} ({} {}B)\n
- Duration : {} s\n - Duration : {} s\n
- Start time : {}.{}\n - Start time : {}.{}\n
@@ -21,16 +22,16 @@ metadata = """{} ({} {}B)\n
cv2_tqdm = 'frame(s)' cv2_tqdm = 'frame(s)'
[ui.parameters] [ui.parameters]
toml_setting² = "Setting with TOML file ({}/{}) ? " toml_setting = "Setting with TOML file ({}/{}) ? "
timelapse = "Timelapse video ({}/{}) ? " timelapse = "Timelapse video ({}/{}) ? "
timelapse_fps = "Timelapse framerate (frame/s) [{}-{}] : " timelapse_fps = "Timelapse framerate (frame/s) [{}-{}] : "
timelapse_fps_err = "Error... please enter a decimal between {} et {}." timelapse_fps_err = "Error... please enter a decimal between {} et {}."
frame_samp = "Enter the frame sampling in seconds [{}-{}] : " frame_samp = "Enter frame sampling in seconds [{}-{}] : "
frame_samp_err = "Error... please enter a decimal between {} and {}." frame_samp_err = "Error... please enter a decimal between {} and {}."
frame_height = "Enter frame height in pixels (ratio unchanged) [{}-{}] : " frame_height = "Enter output frame height in pixels (ratio unchanged) [{}-{}] : "
frame_height_err = "Error... please enter an integer between {} and {}." frame_height_err = "Error... please enter an integer between {} and {}."
video_start_datetime = "Enter video start datetime following ISO format (exemple : 2023-09-18T22:00:02.000) : " video_start_datetime = "Enter video start datetime following ISO format (exemple : 2023-09-18T22:00:02.000) : "
@@ -38,7 +39,7 @@ video_start_datetime_err = "Error... entered datetime is not valid."
rec_timezone = "Enter time offset related to UTC (example for CEST : +02:00) : " rec_timezone = "Enter time offset related to UTC (example for CEST : +02:00) : "
time_offset = "Enter time offset between video and GPX in seconds [{}-{}] : " time_offset = "Enter time offset with GPS track in seconds [{}-{}] : "
time_offset_err = "Error... please enter a decimal between {} and {}." time_offset_err = "Error... please enter a decimal between {} and {}."
[ui.paths] [ui.paths]

View File

@@ -1,7 +1,7 @@
# Localization file for video2geoframes.py script # Localization file for video2geoframes.py
# French (France) # French (France)
# #
# Last edition : 2024-06-22 # Last edition : 2024-06-23
[ui] [ui]
@@ -11,6 +11,7 @@ intro = """Bienvenue dans le script video2geoframes.py !
Ce script permet, à partir d'une vidéo et d'une trace GPS, de créer un ensemble de photos géotaguées.""" Ce script permet, à partir d'une vidéo et d'une trace GPS, de créer un ensemble de photos géotaguées."""
end = "Fin du programme, appuyez sur Entrée pour fermer." end = "Fin du programme, appuyez sur Entrée pour fermer."
paths_title = "## Chemins" paths_title = "## Chemins"
tags_title = "## Tags additionnels"
parameters_title = "## Paramètres du traitement" parameters_title = "## Paramètres du traitement"
metadatas = """{} ({} {}B) metadatas = """{} ({} {}B)
- Durée : {} s - Durée : {} s
@@ -27,10 +28,10 @@ timelapse = "Vidéo timelapse ({}/{}) ? "
timelapse_fps = "Débit d'image du timelapse (image/s) [{}-{}] : " timelapse_fps = "Débit d'image du timelapse (image/s) [{}-{}] : "
timelapse_fps_err = "Erreur... entrez un entier entre {} et {}." timelapse_fps_err = "Erreur... entrez un entier entre {} et {}."
frame_samp = "Entrez l'espacement temporel des images en secondes [{}-{}] : " frame_samp = "Entrez l'espacement temporel en secondes entre les images [{}-{}] : "
frame_samp_err = "'Erreur... veuillez entrer un nombre décimal entre {} et {}." frame_samp_err = "'Erreur... veuillez entrer un nombre décimal entre {} et {}."
frame_height = "Entrez la hauteur des images en pixels (ratio inchangé) [{}-{}] : " frame_height = "Entrez la hauteur en pixels des images en sortie (ratio inchangé) [{}-{}] : "
frame_height_err = "Erreur... veuillez entrer un nombre entier entre {} et {}." frame_height_err = "Erreur... veuillez entrer un nombre entier entre {} et {}."
video_start_datetime = "Entrez l'horodatage du début de la vidéo au format ISO (exemple : 2023-09-18T22:00:02.000) : " video_start_datetime = "Entrez l'horodatage du début de la vidéo au format ISO (exemple : 2023-09-18T22:00:02.000) : "
@@ -38,7 +39,7 @@ video_start_datetime_err = "Erreur... l'horodatage entré est invalide."
rec_timezone = "Entrez le décalage horaire par rapport à UTC (exemple pour CEST : +02:00) : " rec_timezone = "Entrez le décalage horaire par rapport à UTC (exemple pour CEST : +02:00) : "
time_offset = "Entrez le décalage temporel entre la vidéo et le GPX en secondes [{}-{}] : " time_offset = "Entrez le décalage temporel avec la trace GPS en secondes [{}-{}] : "
time_offset_err = "Erreur... veuillez entrer un nombre décimal entre {} et {}." time_offset_err = "Erreur... veuillez entrer un nombre décimal entre {} et {}."
[ui.paths] [ui.paths]

View File

@@ -8,7 +8,7 @@ Designed for contribution to street-level imagery projects like Mapillary or Pan
__author__ = "Lucas MATHIEU (@campanu)" __author__ = "Lucas MATHIEU (@campanu)"
__license__ = "AGPL-3.0-or-later" __license__ = "AGPL-3.0-or-later"
__version__ = "2.0-alpha3" __version__ = "2.0-alpha8"
__maintainer__ = "Lucas MATHIEU (@campanu)" __maintainer__ = "Lucas MATHIEU (@campanu)"
__email__ = "campanu@luc-geo.fr" __email__ = "campanu@luc-geo.fr"
@@ -19,9 +19,9 @@ from datetime import datetime, timedelta
import cv2 import cv2
import piexif import piexif
from tomlkit import dumps, loads from tomlkit import loads
from tqdm import tqdm from tqdm import tqdm
from exif import Image, GpsAltitudeRef
# Functions # Functions
def unix_path(path): def unix_path(path):
@@ -45,52 +45,106 @@ def byte_multiple(size):
size = size / 1024 size = size / 1024
multiple = multiples[i] multiple = multiples[i]
return size, multiple return size, multiple
def existing_items(expected_items: list, items: list):
presents_items = []
duplicated_items = []
missing_items = []
for eit in expected_items:
i = 0
for it in items:
if it == eit:
i += 1
if i == 0:
missing_items.append(eit)
elif i == 1:
presents_items.append(eit)
else:
duplicated_items.append(eit)
return {'presents': presents_items, 'duplicated': duplicated_items, 'missing': missing_items}
def list_enumerator(item_list: list, intermediate_separator: str, last_separator: str):
i = 1
for it in item_list:
if i == 1:
enumerated_list = it
elif 1 < i < len(item_list):
enumerated_list = '{}{}{}'.format(enumerated_list, intermediate_separator, it)
else:
enumerated_list = '{}{}{}'.format(enumerated_list, last_separator, it)
i += 1
return enumerated_list
# Start # Start
print('# video2geoframes.py') print("# video2geoframes.py (v{})\n".format(__version__))
# Configuration settings # Configuration settings
base_path = unix_path(os.path.dirname(__file__)) base_path = unix_path(os.path.dirname(__file__))
ini_file_path = '{}/video2geoframes.ini'.format(base_path) conf_file_path = '{}/video2geoframes_conf.toml'.format(base_path)
ini_file_err = False conf_file_err = False
## Default values # Default values
mandatory_parameters = ['locale', 'exiftool_path']
locale = 'en_us' locale = 'en_us'
min_frame_samp = 0.5 min_frame_samp = 0.5
max_frame_samp = float(60) max_frame_samp = 60.0
min_timelapse_fps = 1 min_timelapse_fps = 1
max_timelapse_fps = 15 max_timelapse_fps = 15
min_frame_height = 480
max_frame_height = 9000
min_time_offset = -10.0
max_time_offset = 10.0
## Platform-dependent commands # Platform-dependent default paths
if platform.system() == 'Windows': if platform.system() == 'Windows':
ffmpeg_path = '{}/dependencies/ffmpeg-essentials/bin/ffmpeg.exe'.format(base_path)
exiftool_path = '{}/dependencies/exiftool.exe'.format(base_path) exiftool_path = '{}/dependencies/exiftool.exe'.format(base_path)
else: else:
ffmpeg_path = 'ffmpeg'
exiftool_path = 'exiftool' exiftool_path = 'exiftool'
## ini file reading
if os.path.exists(ini_file_path):
configuration = {}
try: try:
with open(ini_file_path, 'r') as file: # Configuration file reading
for line in file: try:
if line[0] == '#': if os.path.exists(conf_file_path):
continue with codecs.open(conf_file_path, mode='r', encoding='utf-8') as f:
conf_toml = loads(f.read())
f.close()
else: else:
(key, value) = line.split() raise FileNotFoundError
configuration[key] = value.replace('"', '')
locale = configuration.get('ui_language') # Configuration check
max_frame_samp = float(configuration.get('max_frame_sample')) reading_parameters = conf_toml['system'].keys()
ffmpeg_path = configuration.get('ffmpeg_path').replace('./', '{}/'.format(base_path)) check_result = existing_items(mandatory_parameters, reading_parameters)
exiftool_path = configuration.get('exiftool_path').replace('./', '{}/'.format(base_path))
except: if len(check_result['missing']) != 0:
print('\nError... not readable or incomplete ini file. Default configuration will be used.') missing_parameters_list = list_enumerator(check_result['missing'], ', ', ' and ')
if len(missing_parameters_list) > 1:
verb = 'is'
else:
verb = 'are'
print("(!) {} {} missing in configuration file.".format(missing_parameters_list, verb))
raise ValueError
# Configuration assignment
locale = conf_toml['system']['locale']
exiftool_path = unix_path(conf_toml['system']['exiftool_path'])
except (FileNotFoundError, ValueError):
print("\nError... configuration file doesn't exists or invalid.")
default_conf = str(input("Use default configuration instead (Y/N) ? ").upper())
if default_conf != 'Y':
raise InterruptedError
# Localization # Localization
locale_file_path = '{}/locales/{}.toml'.format(base_path, locale) locale_file_path = '{}/locales/{}.toml'.format(base_path, locale)
@@ -100,8 +154,8 @@ if os.path.exists(locale_file_path):
locale_toml = loads(f.read()) locale_toml = loads(f.read())
f.close() f.close()
else: else:
print("Error.... file for locale \"{}\" doesn't exists or invalid.".format(locale)) print("\nError.... file for locale \"{}\" doesn't exists or invalid.".format(locale))
ValueError raise InterruptedError
user_agree = locale_toml['user']['agree'][0].upper() user_agree = locale_toml['user']['agree'][0].upper()
user_disagree = locale_toml['user']['disagree'][0].upper() user_disagree = locale_toml['user']['disagree'][0].upper()
@@ -111,7 +165,7 @@ path_error = locale_toml['ui']['paths']['path_err']
print(locale_toml['ui']['info']['intro']) print(locale_toml['ui']['info']['intro'])
# User input # User input
## TOML setting file # TOML setting file
toml_setting = input('\n{}'.format(locale_toml['ui']['parameters']['toml_setting'].format(user_agree, user_disagree))) toml_setting = input('\n{}'.format(locale_toml['ui']['parameters']['toml_setting'].format(user_agree, user_disagree)))
i = 0 i = 0
@@ -122,26 +176,24 @@ if toml_setting.upper() == 'O':
toml_file_path = unix_path(input('{}'.format(locale_toml['ui']['paths']['toml_file']))).strip() toml_file_path = unix_path(input('{}'.format(locale_toml['ui']['paths']['toml_file']))).strip()
if os.path.exists(toml_file_path): if os.path.exists(toml_file_path):
break
else:
print('{}\n'.format(locale_toml['ui']['paths']['path_err']))
True
except:
print('{}\n'.format(locale_toml['ui']['paths']['path_err']))
with codecs.open(toml_file_path, mode='r', encoding='utf-8') as f: with codecs.open(toml_file_path, mode='r', encoding='utf-8') as f:
setting_toml = loads(f.read()) setting_toml = loads(f.read())
f.close() f.close()
break
else:
raise FileNotFoundError
except (FileNotFoundError, ValueError):
print('{}\n'.format(locale_toml['ui']['paths']['path_err']))
True
# <--coding in progress--> # <--coding in progress-->
video_path = '' raise NotImplementedError
gps_track_path = ''
## Paths # Paths
else: else:
print('\n{}'.format(locale_toml['ui']['info']['paths_title'])) print('\n{}'.format(locale_toml['ui']['info']['paths_title']))
### Video file # Video file
while True: while True:
try: try:
video_path = unix_path(input('{}'.format(locale_toml['ui']['paths']['video_file']))).strip() video_path = unix_path(input('{}'.format(locale_toml['ui']['paths']['video_file']))).strip()
@@ -154,7 +206,14 @@ else:
print('{}\n'.format(locale_toml['ui']['paths']['path_err'])) print('{}\n'.format(locale_toml['ui']['paths']['path_err']))
True True
### GPS track file # Video metadatas extraction
video = cv2.VideoCapture(video_path)
video_fps = video.get(cv2.CAP_PROP_FPS)
video_width = video.get(cv2.CAP_PROP_FRAME_WIDTH)
video_height = video.get(cv2.CAP_PROP_FRAME_HEIGHT)
video_total_frames = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
# GPS track file
while True: while True:
try: try:
gps_track_path = unix_path(input('{}'.format(locale_toml['ui']['paths']['gps_track']))).strip() gps_track_path = unix_path(input('{}'.format(locale_toml['ui']['paths']['gps_track']))).strip()
@@ -167,35 +226,34 @@ else:
print('{}\n'.format(locale_toml['ui']['paths']['path_err'])) print('{}\n'.format(locale_toml['ui']['paths']['path_err']))
True True
### Output folder # Output folder
output_folder = unix_path(input(locale_toml['ui']['paths']['output_folder'])) output_folder = unix_path(input(locale_toml['ui']['paths']['output_folder']))
## Parameters # Parameters
print('\n{}'.format(locale_toml['ui']['info']['parameters_title'])) print('\n{}'.format(locale_toml['ui']['info']['parameters_title']))
### Timelapse video # Timelapse video
timelapse = input(locale_toml['ui']['parameters']['timelapse'].format(user_agree, user_disagree)) timelapse = input(locale_toml['ui']['parameters']['timelapse'].format(user_agree, user_disagree)).upper()
if timelapse.upper() == user_agree: if timelapse == user_agree:
### Timelapse framerate parameter # Timelapse framerate parameter
while True: while True:
try: try:
timelapse_fps = int(input(locale_toml['ui']['parameters']['timelapse_fps'].format(min_timelapse_fps, timelapse_fps = int(input(locale_toml['ui']['parameters']['timelapse_fps'].format(min_timelapse_fps,
max_timelapse_fps))) max_timelapse_fps)))
if max_timelapse_fps >= timelapse_fps >= min_timelapse_fps: if max_timelapse_fps >= timelapse_fps >= min_timelapse_fps:
frame_sampling = 1 / timelapse_fps frame_sampling = float(1 / timelapse_fps)
break break
else: else:
print(locale_toml['ui']['parameters']['timelapse_fps_err'].format(min_timelapse_fps, print('\n{}'.format(locale_toml['ui']['parameters']['timelapse_fps_err'].format(min_timelapse_fps,
max_timelapse_fps)) max_timelapse_fps)))
True True
except ValueError: except ValueError:
print(locale_toml['ui']['parameters']['timelapse_fps_err'].format(min_timelapse_fps, max_timelapse_fps)) print('\n{}'.format(locale_toml['ui']['parameters']['timelapse_fps_err'].format(min_timelapse_fps, max_timelapse_fps)))
True True
else: else:
### Frame sampling parameter # Frame sampling parameter
while True: while True:
try: try:
frame_sampling = float(input(locale_toml['ui']['parameters']['frame_samp'].format(min_frame_samp, frame_sampling = float(input(locale_toml['ui']['parameters']['frame_samp'].format(min_frame_samp,
@@ -204,15 +262,15 @@ else:
if max_frame_samp >= frame_sampling >= min_frame_samp: if max_frame_samp >= frame_sampling >= min_frame_samp:
break break
else: else:
print(locale_toml['ui']['parameters']['frame_samp_err'].format(min_frame_samp, max_frame_samp)) print('\n{}'.format(locale_toml['ui']['parameters']['frame_samp_err'].format(min_frame_samp, max_frame_samp)))
True True
except ValueError: except ValueError:
print(locale_toml['ui']['parameters']['frame_samp_err'].format(min_frame_samp, max_frame_samp)) print('\n{}'.format(locale_toml['ui']['parameters']['frame_samp_err'].format(min_frame_samp, max_frame_samp)))
True True
## Frame height parameter # Frame height parameter
min_frame_height = 480 if video_height <= max_frame_height:
max_frame_height = 6000 max_frame_height = int(round(video_height, 0))
while True: while True:
try: try:
@@ -221,70 +279,66 @@ else:
if max_frame_height >= frame_height >= min_frame_height: if max_frame_height >= frame_height >= min_frame_height:
break break
elif frame_height == 0:
break
else: else:
print(locale_toml['ui']['parameters']['frame_height_err'].format(min_frame_height, max_frame_height)) print('\n{}'.format(locale_toml['ui']['parameters']['frame_height_err'].format(min_frame_height, max_frame_height)))
True True
except ValueError: except ValueError:
print(locale_toml['ui']['parameters']['frame_height_err'].format(min_frame_height, max_frame_height)) print('\n{}'.format(locale_toml['ui']['parameters']['frame_height_err'].format(min_frame_height, max_frame_height)))
True True
### Video start datetime parameter # Video start datetime parameter
while True: while True:
try: try:
video_start_datetime = input(locale_toml['ui']['parameters']['video_start_datetime']) video_start_datetime = input(locale_toml['ui']['parameters']['video_start_datetime'])
video_start_datetime_obj = datetime.strptime(video_start_datetime, '%Y-%m-%dT%H:%M:%S.%f') video_start_datetime_obj = datetime.strptime(video_start_datetime, '%Y-%m-%dT%H:%M:%S.%f')
break break
except ValueError: except ValueError:
print(locale_toml['ui']['parameters']['video_start_datetime_err']) print('\n{}'.format(locale_toml['ui']['parameters']['video_start_datetime_err']))
True True
### Video recording timezone # Video recording timezone
video_rec_timezone = input(locale_toml['ui']['parameters']['rec_timezone']) video_rec_timezone = input(locale_toml['ui']['parameters']['rec_timezone'])
### Time offset parameter # Time offset parameter
min_time_offset = -10.0
max_time_offset = 10.0
while True: while True:
try: try:
time_offset = float(input(locale_toml['ui']['parameters']['time_offset'].format(min_time_offset, max_time_offset))) time_offset = float(input(locale_toml['ui']['parameters']['time_offset'].format(min_time_offset,
max_time_offset)))
if max_time_offset >= frame_sampling >= min_time_offset: if max_time_offset >= frame_sampling >= min_time_offset:
break break
else: else:
print(locale_toml['ui']['parameters']['time_offset_err'].format(min_time_offset, max_time_offset)) print('\n{}'.format(locale_toml['ui']['parameters']['time_offset_err'].format(min_time_offset, max_time_offset)))
True True
except ValueError: except ValueError:
print(locale_toml['ui']['parameters']['time_offset_err'].format(min_time_offset, max_time_offset)) print('\n{}'.format(locale_toml['ui']['parameters']['time_offset_err'].format(min_time_offset, max_time_offset)))
True True
### User-defined metadata # User-defined metadata
print('\n{}'.format(locale_toml['ui']['info']['tags_title']))
make = input(locale_toml['ui']['metadatas']['make']) make = input(locale_toml['ui']['metadatas']['make'])
model = input(locale_toml['ui']['metadatas']['model']) model = input(locale_toml['ui']['metadatas']['model'])
author = input(locale_toml['ui']['metadatas']['author']) author = input(locale_toml['ui']['metadatas']['author'])
# Video metadatas extraction # Video metadatas formatting
print('\n{}'.format(locale_toml['processing']['reading_metadatas'])) print('\n{}'.format(locale_toml['processing']['reading_metadatas']))
video = cv2.VideoCapture(video_path)
video_fps = video.get(cv2.CAP_PROP_FPS)
video_width = video.get(cv2.CAP_PROP_FRAME_WIDTH)
video_height = video.get(cv2.CAP_PROP_FRAME_HEIGHT)
video_total_frames = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
video_file_name = os.path.basename(video_path) video_file_name = os.path.basename(video_path)
video_file_size = byte_multiple(os.stat(video_path).st_size) video_file_size = byte_multiple(os.stat(video_path).st_size)
video_duration = video_total_frames / video_fps video_duration = video_total_frames / video_fps
video_start_datetime_obj = video_start_datetime_obj + timedelta(seconds=time_offset) video_start_datetime_obj = video_start_datetime_obj + timedelta(seconds=time_offset)
video_start_datetime = video_start_datetime_obj.strftime('%Y:%m:%d %H:%M:%S') video_start_datetime = video_start_datetime_obj.strftime('%Y-%m-%d %H:%M:%S')
video_start_subsectime = video_start_datetime_obj.strftime('%f') video_start_subsectime = int(int(video_start_datetime_obj.strftime('%f')) / 1000)
# Metadata recap # Metadatas recap
print('\n{}'.format(locale_toml['ui']['info']['metadatas'].format(video_file_name, print('\n{}'.format(locale_toml['ui']['info']['metadatas'].format(video_file_name,
round(video_file_size[0], 3), video_file_size[1], round(video_file_size[0], 3), video_file_size[1],
video_duration, video_start_datetime, video_duration, video_start_datetime,
int(int(video_start_subsectime) / 1000), '{:03d}'.format(video_start_subsectime),
video_rec_timezone))) video_rec_timezone)))
# Output folder creation # Output folder creation
@@ -292,7 +346,7 @@ output_folder = '{}/{}'.format(output_folder, video_file_name)
existing_path(output_folder) existing_path(output_folder)
# Processes # Processes
## Frame sampling + tagging (OpenCV + piexif) # Frame sampling + tagging (OpenCV + piexif)
print('\n{}'.format(locale_toml['processing']['sampling'])) print('\n{}'.format(locale_toml['processing']['sampling']))
i = 0 i = 0
@@ -302,7 +356,7 @@ if timelapse == user_agree:
else: else:
frame_interval = frame_sampling frame_interval = frame_sampling
cv2_tqdm_unit = " {}".format(locale_toml['ui']['units']['cv2_tqdm']) cv2_tqdm_unit = locale_toml['ui']['units']['cv2_tqdm']
cv2_tqdm_range = int(video_duration / frame_interval) cv2_tqdm_range = int(video_duration / frame_interval)
for i in tqdm(range(cv2_tqdm_range), unit=cv2_tqdm_unit): for i in tqdm(range(cv2_tqdm_range), unit=cv2_tqdm_unit):
@@ -310,34 +364,26 @@ for i in tqdm(range(cv2_tqdm_range), unit=cv2_tqdm_unit):
video.set(cv2.CAP_PROP_POS_MSEC, t) video.set(cv2.CAP_PROP_POS_MSEC, t)
ret, frame = video.read() ret, frame = video.read()
# Image resizing
if frame_height != 0:
resize_factor = video_height / frame_height
image_height = frame_height
image_width = int(round(video_height * resize_factor, 0))
frame = cv2.resize(frame, (image_width, image_height), interpolation=cv2.INTER_LANCZOS4)
frame_name = '{:05d}'.format(i) frame_name = '{:05d}'.format(i)
image_name = "{}_f{}.jpg".format(video_file_name.split('.')[0], frame_name) image_name = "{}_f{}.jpg".format(video_file_name.split('.')[0], frame_name)
image_path = "{}/{}".format(output_folder, image_name) image_path = "{}/{}".format(output_folder, image_name)
cv2.imwrite(image_path, frame, [cv2.IMWRITE_JPEG_QUALITY, 88, cv2.IMWRITE_JPEG_PROGRESSIVE, 1, cv2.IMWRITE_JPEG_SAMPLING_FACTOR, 0x411111]) cv2.imwrite(image_path, frame, [cv2.IMWRITE_JPEG_QUALITY, 88, cv2.IMWRITE_JPEG_PROGRESSIVE, 1, cv2.IMWRITE_JPEG_SAMPLING_FACTOR, 0x411111])
## Time tags preparation # Time tags formatting
time_shift = i * frame_sampling time_shift = i * frame_sampling
current_datetime_obj = video_start_datetime_obj + timedelta(seconds=time_shift) current_datetime_obj = video_start_datetime_obj + timedelta(seconds=time_shift)
current_datetime = current_datetime_obj.strftime('%Y:%m:%d %H:%M:%S') current_datetime = current_datetime_obj.strftime('%Y:%m:%d %H:%M:%S')
current_subsec_time = int(int(current_datetime_obj.strftime('%f')) / 1000) current_subsec_time = int(int(current_datetime_obj.strftime('%f')) / 1000)
# exif code
# with open(image_path, 'rb') as image_file:
# image = Image(image_file)
# image.make = make
# image.model = model
# image.author = author
# image.copyright = "{}, {}".format(author, video_start_datetime_obj.strftime('%Y'))
# image.datetime_original = current_datetime
# #image.offset_time_original = video_rec_timezone
#
# if current_subsec_time > 0 :
# image.subsec_time_original = str(current_subsec_time)
#
# with open(image_path, 'wb') as tagged_image_file:
# tagged_image_file.write(image.get_file())
# piexif code # piexif code
image_exif = piexif.load(image_path) image_exif = piexif.load(image_path)
@@ -346,7 +392,7 @@ for i in tqdm(range(cv2_tqdm_range), unit=cv2_tqdm_unit):
piexif.ImageIFD.Model: model, piexif.ImageIFD.Model: model,
piexif.ImageIFD.Artist: author, piexif.ImageIFD.Artist: author,
piexif.ImageIFD.Copyright: "{}, {}".format(author, video_start_datetime_obj.strftime('%Y')), piexif.ImageIFD.Copyright: "{}, {}".format(author, video_start_datetime_obj.strftime('%Y')),
piexif.ImageIFD.Software : 'video2geoframes.py' piexif.ImageIFD.Software: 'video2geoframes.py (v{})'.format(__version__)
} }
exif_tags = { exif_tags = {
@@ -374,3 +420,8 @@ geotagging = os.system(geotagging_cmd)
# End # End
input('\n{}'.format(locale_toml['ui']['info']['end'])) input('\n{}'.format(locale_toml['ui']['info']['end']))
except NotImplementedError:
print("\nSorry, this function is not implemented, work in progress ;)")
except InterruptedError:
input("\nEnd of program, press Enter to quit.")

19
video2geoframes_conf.toml Normal file
View File

@@ -0,0 +1,19 @@
# Default configuration file for video2geoframes.py
# See documentation for more information
#
# Last edition : 2024-06-23
# Mandatory section
[system]
# See documentation for supported locales
locale = "en_us"
exiftool_path = "./dependencies/exiftool.exe"
[default]
# Optional section to avoid manual input
# Tags can be overwrited if presents in TOML setting file
[default.tags]
author = "Campanu"
make = "Camera maker"
camera = "Camera model"