opensfm/large/metadataset.py (169 lines of code) (raw):

import os import os.path import shutil import sys import glob import numpy as np from opensfm import config from opensfm import io from opensfm.dataset import DataSet class MetaDataSet: def __init__(self, data_path): """ Create meta dataset instance for large scale reconstruction. :param data_path: Path to directory containing meta dataset """ self.data_path = os.path.abspath(data_path) config_file = os.path.join(self.data_path, "config.yaml") self.config = config.load_config(config_file) self._image_list_file_name = "image_list_with_gps.tsv" self._clusters_file_name = "clusters.npz" self._clusters_with_neighbors_file_name = "clusters_with_neighbors.npz" self._clusters_with_neighbors_geojson_file_name = ( "clusters_with_neighbors.geojson" ) self._clusters_geojson_file_name = "clusters.geojson" io.mkdir_p(self._submodels_path()) def _submodels_path(self): return os.path.join(self.data_path, self.config["submodels_relpath"]) def _submodel_path(self, i): """Path to submodel i folder.""" template = self.config["submodel_relpath_template"] return os.path.join(self.data_path, template % i) def _submodel_images_path(self, i): """Path to submodel i images folder.""" template = self.config["submodel_images_relpath_template"] return os.path.join(self.data_path, template % i) def _image_groups_path(self): return os.path.join(self.data_path, "image_groups.txt") def _image_list_path(self): return os.path.join(self._submodels_path(), self._image_list_file_name) def _clusters_path(self): return os.path.join(self._submodels_path(), self._clusters_file_name) def _clusters_with_neighbors_path(self): return os.path.join( self._submodels_path(), self._clusters_with_neighbors_file_name ) def _clusters_with_neighbors_geojson_path(self): return os.path.join( self._submodels_path(), self._clusters_with_neighbors_geojson_file_name ) def _clusters_geojson_path(self): return os.path.join(self._submodels_path(), self._clusters_geojson_file_name) def _create_symlink(self, base_path, file_path): src = os.path.join(self.data_path, file_path) dst = os.path.join(base_path, file_path) if not os.path.exists(src): return # Symlinks on Windows require admin privileges, # so we use hard links instead if sys.platform == 'win32': if os.path.isdir(dst): shutil.rmtree(dst) elif os.path.isfile(dst): os.remove(dst) else: if os.path.islink(dst): os.unlink(dst) subfolders = len(file_path.split(os.path.sep)) - 1 if sys.platform == 'win32': if os.path.isdir(src): # Create directory in destination, then make hard links # to files os.mkdir(dst) for f in glob.glob(os.path.join(src, "*")): filename = os.path.basename(f) os.link(f, os.path.join(dst, filename)) else: # Just make hard link os.link(src, dst) else: os.symlink(os.path.join(*[".."] * subfolders, os.path.relpath(src, base_path)), dst) def image_groups_exists(self): return os.path.isfile(self._image_groups_path()) def load_image_groups(self): with open(self._image_groups_path()) as fin: for line in fin: yield line.split() def image_list_exists(self): return os.path.isfile(self._image_list_path()) def create_image_list(self, ills): with io.open_wt(self._image_list_path()) as csvfile: for image, lat, lon in ills: csvfile.write(u"{}\t{}\t{}\n".format(image, lat, lon)) def images_with_gps(self): with io.open_rt(self._image_list_path()) as csvfile: for line in csvfile: image, lat, lon = line.split(u"\t") yield image, float(lat), float(lon) def save_clusters(self, images, positions, labels, centers): filepath = self._clusters_path() np.savez_compressed( filepath, images=images, positions=positions, labels=labels, centers=centers ) def load_clusters(self): c = np.load(self._clusters_path()) images = c["images"].ravel() labels = c["labels"].ravel() return images, c["positions"], labels, c["centers"] def save_clusters_with_neighbors(self, clusters): filepath = self._clusters_with_neighbors_path() np.savez_compressed(filepath, clusters=np.array(clusters, dtype=object)) def load_clusters_with_neighbors(self): c = np.load(self._clusters_with_neighbors_path(), allow_pickle=True) return c["clusters"] def save_cluster_with_neighbors_geojson(self, geojson): filepath = self._clusters_with_neighbors_geojson_path() with io.open_wt(filepath) as fout: io.json_dump(geojson, fout) def save_clusters_geojson(self, geojson): filepath = self._clusters_geojson_path() with io.open_wt(filepath) as fout: io.json_dump(geojson, fout) def remove_submodels(self): sm = self._submodels_path() paths = [ os.path.join(sm, o) for o in os.listdir(sm) if os.path.isdir(os.path.join(sm, o)) ] for path in paths: shutil.rmtree(path) def create_submodels(self, clusters): data = DataSet(self.data_path) for i, cluster in enumerate(clusters): # create sub model dirs submodel_path = self._submodel_path(i) submodel_images_path = self._submodel_images_path(i) io.mkdir_p(submodel_path) io.mkdir_p(submodel_images_path) # create image list file image_list_path = os.path.join(submodel_path, "image_list.txt") with io.open_wt(image_list_path) as txtfile: for image in cluster: src = data.image_files[image] dst = os.path.join(submodel_images_path, image) if not os.path.isfile(dst): if sys.platform == 'win32': os.link(src, dst) else: os.symlink(os.path.relpath(src, submodel_images_path), dst) dst_relpath = os.path.relpath(dst, submodel_path) txtfile.write(dst_relpath + "\n") # copy config.yaml if exists config_file_path = os.path.join(self.data_path, "config.yaml") if os.path.exists(config_file_path): shutil.copyfile( config_file_path, os.path.join(submodel_path, "config.yaml") ) # Create reports folder io.mkdir_p(os.path.join(submodel_path, "reports")) # create symlinks to additional files filepaths = [ "camera_models.json", "reference_lla.json", "exif", "features", "matches", "masks", "mask_list.txt", "segmentations", os.path.join("reports", "features"), os.path.join("reports", "features.json"), os.path.join("reports", "matches.json"), ] for filepath in filepaths: self._create_symlink(submodel_path, filepath) def get_submodel_paths(self): submodel_paths = [] for i in range(999999): submodel_path = self._submodel_path(i) if os.path.isdir(submodel_path): submodel_paths.append(submodel_path) else: break return submodel_paths