def process_sequence_properties(import_path, cutoff_distance=600.0, cutoff_time=60.0, interpolate_directions=False, flag_duplicates=False, duplicate_distance=0.1, duplicate_angle=5, offset_angle=0.0, verbose=False, rerun=False, skip_subfolders=False, video_import_path=None): # sanity check if video file is passed if video_import_path and not os.path.isdir(video_import_path): print("Error, video path " + video_import_path + " does not exist, exiting...") sys.exit(1) # in case of video processing, adjust the import path if video_import_path: # set sampling path video_sampling_path = "mapillary_sampled_video_frames" import_path = os.path.join( os.path.abspath(import_path), video_sampling_path) if import_path else os.path.join( os.path.abspath(video_import_path), video_sampling_path) # basic check for all if not import_path or not os.path.isdir(import_path): print("Error, import directory " + import_path + " does not exist, exiting...") sys.exit(1) sequences = [] if skip_subfolders: process_file_list = processing.get_process_file_list( import_path, "sequence_process", rerun, verbose, True, import_path) if not len(process_file_list): if verbose: print("No images to run sequence process in root " + import_path) print( "If the images have already been processed and not yet uploaded, they can be processed again, by passing the argument --rerun" ) else: # LOAD TIME AND GPS POINTS ------------------------------------ file_list, capture_times, lats, lons, directions = processing.load_geotag_points( process_file_list, verbose) # --------------------------------------- # SPLIT SEQUENCES -------------------------------------- if len(capture_times) and len(lats) and len(lons): sequences.extend( processing.split_sequences(capture_times, lats, lons, file_list, directions, cutoff_time, cutoff_distance, verbose)) # --------------------------------------- else: # sequence limited to the root of the files for root, dirs, files in os.walk(import_path): if os.path.join(".mapillary", "logs") in root: continue if len(files): process_file_list = processing.get_process_file_list( import_path, "sequence_process", rerun, verbose, True, root) if not len(process_file_list): if verbose: print("No images to run sequence process in root " + root) print( "If the images have already been processed and not yet uploaded, they can be processed again, by passing the argument --rerun" ) continue # LOAD TIME AND GPS POINTS ------------------------------------ file_list, capture_times, lats, lons, directions = processing.load_geotag_points( process_file_list, verbose) # --------------------------------------- # SPLIT SEQUENCES -------------------------------------- if len(capture_times) and len(lats) and len(lons): sequences.extend( processing.split_sequences(capture_times, lats, lons, file_list, directions, cutoff_time, cutoff_distance, verbose)) # --------------------------------------- if flag_duplicates: if verbose: print( "Flagging images as duplicates if consecutive distance difference less than {} and angle difference less than {}" .format(duplicate_distance, duplicate_angle)) # process for each sequence for sequence in sequences: file_list = sequence["file_list"] directions = sequence["directions"] latlons = sequence["latlons"] capture_times = sequence["capture_times"] # COMPUTE DIRECTIONS -------------------------------------- interpolated_directions = [ compute_bearing(ll1[0], ll1[1], ll2[0], ll2[1]) for ll1, ll2 in zip(latlons[:-1], latlons[1:]) ] if len(interpolated_directions): interpolated_directions.append(interpolated_directions[-1]) else: interpolated_directions.append(directions[-1]) # use interpolated directions if direction not available or if flag for # interpolate_directions for i, d in enumerate(directions): directions[i] = d if ( d is not None and not interpolate_directions ) else (interpolated_directions[i] + offset_angle) % 360.0 # --------------------------------------- # INTERPOLATE TIMESTAMPS, in case of identical timestamps capture_times = processing.interpolate_timestamp(capture_times) final_file_list = file_list[:] final_directions = directions[:] final_capture_times = capture_times[:] # FLAG DUPLICATES -------------------------------------- if flag_duplicates: final_file_list = [file_list[0]] final_directions = [directions[0]] final_capture_times = [capture_times[0]] prev_latlon = latlons[0] prev_direction = directions[0] for i, filename in enumerate(file_list[1:]): log_root = uploader.log_rootpath(filename) duplicate_flag_path = os.path.join(log_root, "duplicate") sequence_process_success_path = os.path.join( log_root, "sequence_process_success") k = i + 1 distance = gps_distance(latlons[k], prev_latlon) if directions[k] is not None and prev_direction is not None: direction_diff = diff_bearing(directions[k], prev_direction) else: # dont use bearing difference if no bearings are # available direction_diff = 360 if distance < duplicate_distance and direction_diff < duplicate_angle: open(duplicate_flag_path, "w").close() open(sequence_process_success_path, "w").close() open( sequence_process_success_path + "_" + str(time.strftime("%Y_%m_%d_%H_%M_%S", time.gmtime())), "w").close() else: prev_latlon = latlons[k] prev_direction = directions[k] final_file_list.append(filename) final_directions.append(directions[k]) final_capture_times.append(capture_times[k]) # --------------------------------------- # FINALIZE ------------------------------------ for i in range(0, len(final_file_list), MAX_SEQUENCE_LENGTH): finalize_sequence_processing( str(uuid.uuid4()), final_file_list[i:i + MAX_SEQUENCE_LENGTH], final_directions[i:i + MAX_SEQUENCE_LENGTH], final_capture_times[i:i + MAX_SEQUENCE_LENGTH], import_path, verbose) print("Sub process ended")
def interpolation(data, file_in_path=None, file_format="csv", time_column=0, delimiter=",", time_utc=False, time_format="%Y-%m-%dT%H:%M:%SZ", header=False, keep_original=False, import_path=None, max_time_delta=1, verbose=False): if not data: print("Error, you must specify the data for interpolation.") print('Choose between "missing_gps" or "identical_timestamps"') sys.exit(1) if not import_path and not file_in_path: print( "Error, you must specify a path to data, either path to directory with images or path to an external log file." ) sys.exit(1) if file_in_path: if not os.path.isfile(file_in_path): print("Error, specified input file does not exist, exiting...") sys.exit(1) if file_format != "csv": print( "Only csv file format is supported at the moment, exiting...") sys.exit(1) csv_data = process_csv.read_csv(file_in_path, delimiter=delimiter, header=header) if data == "identical_timestamps": timestamps = csv_data[time_column] timestamps_datetime = [ process_csv.format_time(timestamp, time_utc, time_format) for timestamp in timestamps ] timestamps_interpolated = processing.interpolate_timestamp( timestamps_datetime) csv_data[time_column] = format_datetime(timestamps_interpolated, time_utc, time_format) file_out = file_in_path if not keep_original else file_in_path[: -4] + "_processed." + file_format with open(file_out, "w") as csvfile: csvwriter = csv.writer(csvfile, delimiter=delimiter) for row in zip(*csv_data): csvwriter.writerow(row) sys.exit() elif data == "missing_gps": print( "Error, missing gps interpolation in an external log file not supported yet, exiting..." ) sys.exit(1) else: print("Error unsupported data for interpolation, exiting...") sys.exit(1) if import_path: if not os.path.isdir(import_path): print("Error, specified import path does not exist, exiting...") sys.exit(1) # get list of files to process process_file_list = uploader.get_total_file_list(import_path) if not len(process_file_list): print("No images found in the import path " + import_path) sys.exit(1) if data == "missing_gps": # get geotags from images and a list of tuples with images missing geotags # and their timestamp geotags, missing_geotags = processing.get_images_geotags( process_file_list) if not len(missing_geotags): print("No images in directory {} missing geotags, exiting...". format(import_path)) sys.exit(1) if not len(geotags): print("No images in directory {} with geotags.".format( import_path)) sys.exit(1) sys.stdout.write( "Interpolating gps for {} images missing geotags.".format( len(missing_geotags))) for image, timestamp in tqdm(missing_geotags, desc="Interpolating missing gps"): # interpolate try: lat, lon, bearing, elevation = interpolate_lat_lon( geotags, timestamp, max_time_delta) except Exception as e: print( "Error, {}, interpolation of latitude and longitude failed for image {}" .format(e, image)) continue # insert into exif exif_edit = ExifEdit(image) if lat and lon: exif_edit.add_lat_lon(lat, lon) else: print("Error, lat and lon not interpolated for image {}.". format(image)) if bearing: exif_edit.add_direction(bearing) else: if verbose: print( "Warning, bearing not interpolated for image {}.". format(image)) if elevation: exif_edit.add_altitude(elevation) else: if verbose: print( "Warning, altitude not interpolated for image {}.". format(image)) meta = {} add_meta_tag(meta, "booleans", "interpolated_gps", True) exif_edit.add_image_history(meta["MAPMetaTags"]) file_out = image if not keep_original else image[:-4] + "_processed." exif_edit.write(filename=file_out) elif data == "identical_timestamps": sys.stdout.write("Loading image timestamps.") # read timestamps timestamps = [] for image in tqdm(process_file_list, desc="Interpolating identical timestamps"): # load exif exif = ExifRead(image) timestamp = exif.extract_capture_time() if timestamp: timestamps.append(timestamp) else: print( "Capture could not be extracted for image {}.".format( image)) # interpolate timestamps_interpolated = processing.interpolate_timestamp( timestamps) print("") sys.stdout.write("Interpolating identical timestamps.") counter = 0 # write back for image, timestamp in tqdm( zip(process_file_list, timestamps_interpolated), desc="Writing capture time in image EXIF"): # print progress counter += 1 sys.stdout.write('.') if (counter % 100) == 0: print("") # load exif exif_edit = ExifEdit(image) exif_edit.add_date_time_original(timestamp) # write to exif file_out = image if not keep_original else image[:-4] + "_processed." exif_edit.write(filename=file_out) sys.exit() else: print("Error unsupported data for interpolation, exiting...") sys.exit(1) print("")
def interpolation(data, file_in_path=None, file_format="csv", time_column=0, delimiter=",", time_utc=False, time_format="%Y-%m-%dT%H:%M:%SZ", header=False, keep_original=False, import_path=None, max_time_delta=1, verbose=False): if not data: print_error("Error, you must specify the data for interpolation." + 'Choose between "missing_gps" or "identical_timestamps"') sys.exit(1) if not import_path and not file_in_path: print_error("Error, you must specify a path to data, either path to directory with images or path to an external log file.") sys.exit(1) if file_in_path: if not os.path.isfile(file_in_path): print_error("Error, specified input file does not exist, exiting...") sys.exit(1) if file_format != "csv": print_error("Only csv file format is supported at the moment, exiting...") sys.exit(1) csv_data = process_csv.read_csv( file_in_path, delimiter=delimiter, header=header) if data == "identical_timestamps": timestamps = csv_data[time_column] timestamps_datetime = [process_csv.format_time( timestamp, time_utc, time_format) for timestamp in timestamps] timestamps_interpolated = processing.interpolate_timestamp( timestamps_datetime) csv_data[time_column] = format_datetime( timestamps_interpolated, time_utc, time_format) file_out = file_in_path if not keep_original else file_in_path[ :-4] + "_processed." + file_format with open(file_out, "w") as csvfile: csvwriter = csv.writer(csvfile, delimiter=delimiter) for row in zip(*csv_data): csvwriter.writerow(row) sys.exit() elif data == "missing_gps": print_error( "Error, missing gps interpolation in an external log file not supported yet, exiting...") sys.exit(1) else: print_error("Error unsupported data for interpolation, exiting...") sys.exit(1) if import_path: if not os.path.isdir(import_path): print_error("Error, specified import path does not exist, exiting...") sys.exit(1) # get list of files to process process_file_list = uploader.get_total_file_list(import_path) if not len(process_file_list): print("No images found in the import path " + import_path) sys.exit(1) if data == "missing_gps": # get geotags from images and a list of tuples with images missing geotags # and their timestamp geotags, missing_geotags = processing.get_images_geotags( process_file_list) if not len(missing_geotags): print("No images in directory {} missing geotags, exiting...".format( import_path)) sys.exit(1) if not len(geotags): print("No images in directory {} with geotags.".format(import_path)) sys.exit(1) sys.stdout.write("Interpolating gps for {} images missing geotags.".format( len(missing_geotags))) for image, timestamp in tqdm(missing_geotags, desc="Interpolating missing gps"): # interpolate try: lat, lon, bearing, elevation = interpolate_lat_lon( geotags, timestamp, max_time_delta) except Exception as e: print_error("Error, {}, interpolation of latitude and longitude failed for image {}".format( e, image)) continue # insert into exif exif_edit = ExifEdit(image) if lat and lon: exif_edit.add_lat_lon(lat, lon) else: print_error( "Error, lat and lon not interpolated for image {}.".format(image)) if bearing: exif_edit.add_direction(bearing) else: if verbose: print( "Warning, bearing not interpolated for image {}.".format(image)) if elevation: exif_edit.add_altitude(elevation) else: if verbose: print( "Warning, altitude not interpolated for image {}.".format(image)) meta = {} add_meta_tag(meta, "booleans", "interpolated_gps", True) exif_edit.add_image_history(meta["MAPMetaTags"]) file_out = image if not keep_original else image[:- 4] + "_processed." exif_edit.write(filename=file_out) elif data == "identical_timestamps": sys.stdout.write("Loading image timestamps.") # read timestamps timestamps = [] for image in tqdm(process_file_list, desc="Interpolating identical timestamps"): # load exif exif = ExifRead(image) timestamp = exif.extract_capture_time() if timestamp: timestamps.append(timestamp) else: print("Capture could not be extracted for image {}.".format(image)) # interpolate timestamps_interpolated = processing.interpolate_timestamp( timestamps) print("") sys.stdout.write("Interpolating identical timestamps.") counter = 0 # write back for image, timestamp in tqdm(zip(process_file_list, timestamps_interpolated), desc="Writing capture time in image EXIF"): # print progress counter += 1 sys.stdout.write('.') if (counter % 100) == 0: print("") # load exif exif_edit = ExifEdit(image) exif_edit.add_date_time_original(timestamp) # write to exif file_out = image if not keep_original else image[ :-4] + "_processed." exif_edit.write(filename=file_out) sys.exit() else: print_error("Error unsupported data for interpolation, exiting...") sys.exit(1) print("")
def process_sequence_properties(import_path, cutoff_distance=600.0, cutoff_time=60.0, interpolate_directions=False, keep_duplicates=False, duplicate_distance=0.1, duplicate_angle=5, offset_angle=0.0, verbose=False, rerun=False, skip_subfolders=False, video_import_path=None): # sanity check if video file is passed if video_import_path and not os.path.isdir(video_import_path) and not os.path.isfile(video_import_path): print("Error, video path " + video_import_path + " does not exist, exiting...") sys.exit(1) # in case of video processing, adjust the import path if video_import_path: # set sampling path video_sampling_path = "mapillary_sampled_video_frames" video_dirname = video_import_path if os.path.isdir( video_import_path) else os.path.dirname(video_import_path) import_path = os.path.join(os.path.abspath(import_path), video_sampling_path) if import_path else os.path.join( os.path.abspath(video_dirname), video_sampling_path) # basic check for all if not import_path or not os.path.isdir(import_path): print_error("Error, import directory " + import_path + " does not exist, exiting...") sys.exit(1) sequences = [] if skip_subfolders: process_file_list = processing.get_process_file_list(import_path, "sequence_process", rerun, verbose, True, import_path) if not len(process_file_list): if verbose: print("No images to run sequence process in root " + import_path) print( "If the images have already been processed and not yet uploaded, they can be processed again, by passing the argument --rerun") else: # LOAD TIME AND GPS POINTS ------------------------------------ file_list, capture_times, lats, lons, directions = processing.load_geotag_points( process_file_list, verbose) # --------------------------------------- # SPLIT SEQUENCES -------------------------------------- if len(capture_times) and len(lats) and len(lons): sequences.extend(processing.split_sequences( capture_times, lats, lons, file_list, directions, cutoff_time, cutoff_distance, verbose)) # --------------------------------------- else: # sequence limited to the root of the files for root, dirs, files in os.walk(import_path): if os.path.join(".mapillary", "logs") in root: continue if len(files): process_file_list = processing.get_process_file_list(import_path, "sequence_process", rerun, verbose, True, root) if not len(process_file_list): if verbose: print("No images to run sequence process in root " + root) print( "If the images have already been processed and not yet uploaded, they can be processed again, by passing the argument --rerun") continue # LOAD TIME AND GPS POINTS ------------------------------------ file_list, capture_times, lats, lons, directions = processing.load_geotag_points( process_file_list, verbose) # --------------------------------------- # SPLIT SEQUENCES -------------------------------------- if len(capture_times) and len(lats) and len(lons): sequences.extend(processing.split_sequences( capture_times, lats, lons, file_list, directions, cutoff_time, cutoff_distance, verbose)) # --------------------------------------- if not keep_duplicates: if verbose: print("Flagging images as duplicates if consecutive distance difference less than {} and angle difference less than {}".format( duplicate_distance, duplicate_angle)) # process for each sequence for sequence in sequences: file_list = sequence["file_list"] directions = sequence["directions"] latlons = sequence["latlons"] capture_times = sequence["capture_times"] # COMPUTE DIRECTIONS -------------------------------------- interpolated_directions = [compute_bearing(ll1[0], ll1[1], ll2[0], ll2[1]) for ll1, ll2 in zip(latlons[:-1], latlons[1:])] if len(interpolated_directions): interpolated_directions.append(interpolated_directions[-1]) else: interpolated_directions.append(directions[-1]) # use interpolated directions if direction not available or if flag for # interpolate_directions for i, d in enumerate(directions): directions[i] = d if ( d is not None and not interpolate_directions) else (interpolated_directions[i] + offset_angle) % 360.0 # --------------------------------------- # COMPUTE SPEED ------------------------------------------- computed_delta_ts = [(t1 - t0).total_seconds() for t0, t1 in zip(capture_times[:-1], capture_times[1:])] computed_distances = [gps_distance(l1, l0) for l0, l1 in zip(latlons[:-1], latlons[1:])] computed_speed = gps_speed( computed_distances, computed_delta_ts) # in meters/second if len([x for x in computed_speed if x > MAX_CAPTURE_SPEED]) > 0: print("Warning: The distance in sequence including images\n{}\nto\n{}\nis too large for the time difference (very high apparent capture speed). Are you sure timestamps and locations are correct?".format( file_list[0], file_list[-1])) # INTERPOLATE TIMESTAMPS, in case of identical timestamps capture_times = processing.interpolate_timestamp(capture_times) final_file_list = file_list[:] final_directions = directions[:] final_capture_times = capture_times[:] # FLAG DUPLICATES -------------------------------------- if not keep_duplicates: final_file_list = [file_list[0]] final_directions = [directions[0]] final_capture_times = [capture_times[0]] prev_latlon = latlons[0] prev_direction = directions[0] for i, filename in enumerate(file_list[1:]): log_root = uploader.log_rootpath(filename) duplicate_flag_path = os.path.join(log_root, "duplicate") sequence_process_success_path = os.path.join(log_root, "sequence_process_success") k = i + 1 distance = gps_distance(latlons[k], prev_latlon) if directions[k] is not None and prev_direction is not None: direction_diff = diff_bearing(directions[k], prev_direction) else: # dont use bearing difference if no bearings are # available direction_diff = 360 if distance < duplicate_distance and direction_diff < duplicate_angle: open(duplicate_flag_path, "w").close() open(sequence_process_success_path, "w").close() open(sequence_process_success_path + "_" + str(time.strftime("%Y_%m_%d_%H_%M_%S", time.gmtime())), "w").close() else: prev_latlon = latlons[k] prev_direction = directions[k] final_file_list.append(filename) final_directions.append(directions[k]) final_capture_times.append(capture_times[k]) # --------------------------------------- # FINALIZE ------------------------------------ for i in range(0, len(final_file_list), MAX_SEQUENCE_LENGTH): finalize_sequence_processing(str(uuid.uuid4()), final_file_list[i:i + MAX_SEQUENCE_LENGTH], final_directions[i:i + MAX_SEQUENCE_LENGTH], final_capture_times[i:i + MAX_SEQUENCE_LENGTH], import_path, verbose) print("Sub process ended")
def process_sequence_properties(import_path, cutoff_distance=600.0, cutoff_time=60.0, interpolate_directions=False, flag_duplicates=False, duplicate_distance=0.1, duplicate_angle=5, offset_angle=0.0, verbose=False, rerun=False, skip_subfolders=False): # basic check for all import_path = os.path.abspath(import_path) if not os.path.isdir(import_path): print("Error, import directory " + import_path + " doesnt not exist, exiting...") sys.exit() sequences = [] if skip_subfolders: process_file_list = processing.get_process_file_list(import_path, "sequence_process", rerun, verbose, True, import_path) if not len(process_file_list): if verbose: print("No images to run sequence process in root " + import_path) print( "If the images have already been processed and not yet uploaded, they can be processed again, by passing the argument --rerun") else: # LOAD TIME AND GPS POINTS ------------------------------------ file_list, capture_times, lats, lons, directions = processing.load_geotag_points( process_file_list, import_path, verbose) # --------------------------------------- # SPLIT SEQUENCES -------------------------------------- if len(capture_times) and len(lats) and len(lons): sequences.extend(processing.split_sequences( capture_times, lats, lons, file_list, directions, cutoff_time, cutoff_distance, verbose)) # --------------------------------------- else: # sequence limited to the root of the files for root, dirs, files in os.walk(import_path): if ".mapillary" in root: continue if len(files): process_file_list = processing.get_process_file_list(import_path, "sequence_process", rerun, verbose, True, root) if not len(process_file_list): if verbose: print("No images to run sequence process in root " + root) print( "If the images have already been processed and not yet uploaded, they can be processed again, by passing the argument --rerun") continue # LOAD TIME AND GPS POINTS ------------------------------------ file_list, capture_times, lats, lons, directions = processing.load_geotag_points( process_file_list, import_path, verbose) # --------------------------------------- # SPLIT SEQUENCES -------------------------------------- if len(capture_times) and len(lats) and len(lons): sequences.extend(processing.split_sequences( capture_times, lats, lons, file_list, directions, cutoff_time, cutoff_distance, verbose)) # --------------------------------------- # process for each sequence for sequence in sequences: file_list = sequence["file_list"] directions = sequence["directions"] latlons = sequence["latlons"] capture_times = sequence["capture_times"] # COMPUTE DIRECTIONS -------------------------------------- interpolated_directions = [compute_bearing(ll1[0], ll1[1], ll2[0], ll2[1]) for ll1, ll2 in zip(latlons, latlons[1:])] interpolated_directions.append(directions[-1]) # use interpolated directions if direction not available or if flag for # interpolate_directions for i, d in enumerate(directions): directions[i] = d if ( d is not None and not interpolate_directions) else (interpolated_directions[i] + offset_angle) % 360.0 # --------------------------------------- # INTERPOLATE TIMESTAMPS, incase of identical timestamps capture_times, file_list = processing.interpolate_timestamp(capture_times, file_list) final_file_list = file_list[:] final_directions = directions[:] final_capture_times = capture_times[:] # FLAG DUPLICATES -------------------------------------- if flag_duplicates: final_file_list = [file_list[0]] final_directions = [directions[0]] prev_latlon = latlons[0] prev_direction = directions[0] for i, filename in enumerate(file_list[1:]): log_root = uploader.log_rootpath(import_path, filename) duplicate_flag_path = os.path.join(log_root, "duplicate") sequence_process_success_path = os.path.join(log_root, "sequence_process_success") k = i + 1 distance = gps_distance(latlons[k], prev_latlon) if directions[k] is not None and prev_direction is not None: direction_diff = diff_bearing(directions[k], prev_direction) else: # dont use bearing difference if no bearings are # available direction_diff = 360 if distance < duplicate_distance and direction_diff < duplicate_angle: open(duplicate_flag_path, "w").close() open(sequence_process_success_path, "w").close() open(sequence_process_success_path + "_" + str(time.strftime("%Y_%m_%d_%H_%M_%S", time.gmtime())), "w").close() else: prev_latlon = latlons[k] prev_direction = directions[k] final_file_list.append(filename) final_directions.append(directions[k]) # --------------------------------------- # FINALIZE ------------------------------------ for i in range(0, len(final_file_list), MAX_SEQUENCE_LENGTH): finalize_sequence_processing(str(uuid.uuid4()), final_file_list[i:i + MAX_SEQUENCE_LENGTH], final_directions[i:i + MAX_SEQUENCE_LENGTH], final_capture_times[i:i + MAX_SEQUENCE_LENGTH], import_path, verbose)