Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,10 @@ def vcpkg_export():
exit(1)

pkgs = vcpkg_requirements()
out = "vcpkg-export-%s" % odm_version().replace(".", "")
out = "vcpkg-export-%s" % get_version().replace(".", "")
run("vcpkg\\vcpkg export %s --output=%s --zip" % (" ".join(pkgs), out))

def odm_version():
def get_version():
with open("VERSION") as f:
return f.read().split("\n")[0].strip()

Expand Down
10 changes: 5 additions & 5 deletions opendm/ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def get_model(namespace, url, version, name = "model.onnx"):
# Check if we need to download it
model_file = os.path.join(versioned_dir, name)
if not os.path.isfile(model_file):
log.ODM_INFO("Downloading AI model from %s ..." % url)
log.INFO("Downloading AI model from %s ..." % url)

last_update = 0

Expand All @@ -51,23 +51,23 @@ def callback(progress):
time_has_elapsed = time.time() - last_update >= 2

if time_has_elapsed or int(progress) == 100:
log.ODM_INFO("Downloading: %s%%" % int(progress))
log.INFO("Downloading: %s%%" % int(progress))
last_update = time.time()

try:
downloaded_file = download(url, versioned_dir, progress_callback=callback)
except Exception as e:
log.ODM_WARNING("Cannot download %s: %s" % (url, str(e)))
log.WARNING("Cannot download %s: %s" % (url, str(e)))
return None

if os.path.basename(downloaded_file).lower().endswith(".zip"):
log.ODM_INFO("Extracting %s ..." % downloaded_file)
log.INFO("Extracting %s ..." % downloaded_file)
with zipfile.ZipFile(downloaded_file, 'r') as z:
z.extractall(versioned_dir)
os.remove(downloaded_file)

if not os.path.isfile(model_file):
log.ODM_WARNING("Cannot find %s (is the URL to the AI model correct?)" % model_file)
log.WARNING("Cannot find %s (is the URL to the AI model correct?)" % model_file)
return None
else:
return model_file
Expand Down
14 changes: 7 additions & 7 deletions opendm/align.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def compute_alignment_matrix(input_laz, align_file, stats_dir):

# Check if we need to reproject align file
input_crs = get_point_cloud_crs(input_laz)
log.ODM_INFO("Input CRS: %s" % input_crs)
log.INFO("Input CRS: %s" % input_crs)

_, ext = os.path.splitext(align_file)
repr_func = None
Expand All @@ -68,27 +68,27 @@ def compute_alignment_matrix(input_laz, align_file, stats_dir):
align_crs = get_point_cloud_crs(align_file)
repr_func = reproject_point_cloud
else:
log.ODM_WARNING("Unsupported alignment file: %s" % align_file)
log.WARNING("Unsupported alignment file: %s" % align_file)
return

to_delete = []

try:
log.ODM_INFO("Align CRS: %s" % align_crs)
log.INFO("Align CRS: %s" % align_crs)
if input_crs != align_crs:
# Reprojection needed
log.ODM_INFO("Reprojecting %s to %s" % (align_file, input_crs))
log.INFO("Reprojecting %s to %s" % (align_file, input_crs))
align_file = repr_func(align_file, input_crs)
to_delete.append(align_file)

conf = dataclasses.asdict(codem.CodemRunConfig(align_file, input_laz, OUTPUT_DIR=stats_dir))
fnd_obj, aoi_obj = codem.preprocess(conf)
fnd_obj.prep()
aoi_obj.prep()
log.ODM_INFO("Aligning reconstruction to %s" % align_file)
log.ODM_INFO("Coarse registration...")
log.INFO("Aligning reconstruction to %s" % align_file)
log.INFO("Coarse registration...")
dsm_reg = codem.coarse_registration(fnd_obj, aoi_obj, conf)
log.ODM_INFO("Fine registration...")
log.INFO("Fine registration...")
icp_reg = codem.fine_registration(fnd_obj, aoi_obj, dsm_reg, conf)

app_reg = codem.registration.ApplyRegistration(
Expand Down
2 changes: 1 addition & 1 deletion opendm/arghelpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def save_opts(opts_json, args):
with open(opts_json, "w", encoding='utf-8') as f:
f.write(json.dumps(args_to_dict(args)))
except Exception as e:
log.ODM_WARNING("Cannot save options to %s: %s" % (opts_json, str(e)))
log.WARNING("Cannot save options to %s: %s" % (opts_json, str(e)))

def compare_args(opts_json, args, rerun_stages):
if not os.path.isfile(opts_json):
Expand Down
4 changes: 2 additions & 2 deletions opendm/bgfilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ class BgFilter():
def __init__(self, model):
self.model = model

log.ODM_INFO(' ?> Using provider %s' % provider)
log.INFO(' ?> Using provider %s' % provider)
self.load_model()


def load_model(self):
log.ODM_INFO(' -> Loading the model')
log.INFO(' -> Loading the model')

self.session = ort.InferenceSession(self.model, providers=[provider])

Expand Down
2 changes: 1 addition & 1 deletion opendm/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def get_opensfm_camera_models(cameras):
for k in keys:
if not k in valid_fields:
camera.pop(k)
log.ODM_WARNING("Invalid camera key ignored: %s" % k)
log.WARNING("Invalid camera key ignored: %s" % k)

result[osfm_camera_id] = camera
return result
Expand Down
8 changes: 4 additions & 4 deletions opendm/cogeo.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ def convert_to_cogeo(src_path, blocksize=256, max_workers=1, compression="DEFLAT
"""

if not os.path.isfile(src_path):
log.ODM_WARNING("Cannot convert to cogeo: %s (file does not exist)" % src_path)
log.WARNING("Cannot convert to cogeo: %s (file does not exist)" % src_path)
return False

log.ODM_INFO("Optimizing %s as Cloud Optimized GeoTIFF" % src_path)
log.INFO("Optimizing %s as Cloud Optimized GeoTIFF" % src_path)


tmpfile = io.related_file_path(src_path, postfix='_cogeo')
Expand Down Expand Up @@ -47,15 +47,15 @@ def convert_to_cogeo(src_path, blocksize=256, max_workers=1, compression="DEFLAT
"--config GDAL_NUM_THREADS {threads} "
"\"{src_path}\" \"{tmpfile}\" ".format(**kwargs))
except Exception as e:
log.ODM_WARNING("Cannot create Cloud Optimized GeoTIFF: %s" % str(e))
log.WARNING("Cannot create Cloud Optimized GeoTIFF: %s" % str(e))

if os.path.isfile(tmpfile):
shutil.move(src_path, swapfile) # Move to swap location

try:
shutil.move(tmpfile, src_path)
except IOError as e:
log.ODM_WARNING("Cannot move %s to %s: %s" % (tmpfile, src_path, str(e)))
log.WARNING("Cannot move %s to %s: %s" % (tmpfile, src_path, str(e)))
shutil.move(swapfile, src_path) # Attempt to restore

if os.path.isfile(swapfile):
Expand Down
2 changes: 1 addition & 1 deletion opendm/concurrency.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def stop_workers():
if error is not None and single_thread_fallback:
# Try to reprocess using a single thread
# in case this was a memory error
log.ODM_WARNING("Failed to run process in parallel, retrying with a single thread...")
log.WARNING("Failed to run process in parallel, retrying with a single thread...")
use_single_thread = True
else:
use_single_thread = True
Expand Down
16 changes: 8 additions & 8 deletions opendm/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ def config(argv=None, parser=None):
yaml_defaults = {k.replace('-', '_'): v for k, v in yaml_defaults.items()}
parser.set_defaults(**yaml_defaults)
except Exception as e:
log.ODM_WARNING(f"Could not load settings from {context.settings_path}: {e}")
log.WARNING(f"Could not load settings from {context.settings_path}: {e}")

parser.add_argument('--project-path',
metavar='<path>',
Expand Down Expand Up @@ -902,37 +902,37 @@ def config(argv=None, parser=None):

for p in unknown:
if p in DEPRECATED:
log.ODM_WARNING("%s is no longer a valid argument and will be ignored!" % p)
log.WARNING("%s is no longer a valid argument and will be ignored!" % p)

# check that the project path setting has been set properly
if not args.project_path:
log.ODM_ERROR('You need to set the project path in the '
log.ERROR('You need to set the project path in the '
'settings.yaml file before you can run ODM, '
'or use `--project-path <path>`. Run `python3 '
'run.py --help` for more information. ')
sys.exit(1)

if args.fast_orthophoto:
log.ODM_INFO('Fast orthophoto is turned on, automatically setting --skip-3dmodel')
log.INFO('Fast orthophoto is turned on, automatically setting --skip-3dmodel')
args.skip_3dmodel = True

if args.dtm and not args.pc_classify:
log.ODM_INFO("DTM is turned on, automatically turning on point cloud classification")
log.INFO("DTM is turned on, automatically turning on point cloud classification")
args.pc_classify = True

if args.skip_3dmodel and args.use_3dmesh:
log.ODM_WARNING('--skip-3dmodel is set, but so is --use-3dmesh. --skip-3dmodel will be ignored.')
log.WARNING('--skip-3dmodel is set, but so is --use-3dmesh. --skip-3dmodel will be ignored.')
args.skip_3dmodel = False

if args.orthophoto_cutline and not args.crop:
log.ODM_WARNING("--orthophoto-cutline is set, but --crop is not. --crop will be set to 0.01")
log.WARNING("--orthophoto-cutline is set, but --crop is not. --crop will be set to 0.01")
args.crop = 0.01

if args.sm_cluster:
try:
Node.from_url(args.sm_cluster).info()
except exceptions.NodeConnectionError as e:
log.ODM_ERROR("Cluster node seems to be offline: %s" % str(e))
log.ERROR("Cluster node seems to be offline: %s" % str(e))
sys.exit(1)

return args
14 changes: 7 additions & 7 deletions opendm/cropper.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ def path(self, suffix):
@staticmethod
def crop(gpkg_path, geotiff_path, gdal_options, keep_original=True, warp_options=[]):
if not os.path.exists(gpkg_path) or not os.path.exists(geotiff_path):
log.ODM_WARNING("Either {} or {} does not exist, will skip cropping.".format(gpkg_path, geotiff_path))
log.WARNING("Either {} or {} does not exist, will skip cropping.".format(gpkg_path, geotiff_path))
return geotiff_path

log.ODM_INFO("Cropping %s" % geotiff_path)
log.INFO("Cropping %s" % geotiff_path)

# Rename original file
# path/to/odm_orthophoto.tif --> path/to/odm_orthophoto.original.tif
Expand Down Expand Up @@ -64,7 +64,7 @@ def crop(gpkg_path, geotiff_path, gdal_options, keep_original=True, warp_options
os.remove(original_geotiff)

except Exception as e:
log.ODM_WARNING('Something went wrong while cropping: {}'.format(e))
log.WARNING('Something went wrong while cropping: {}'.format(e))

# Revert rename
os.replace(original_geotiff, geotiff_path)
Expand Down Expand Up @@ -131,7 +131,7 @@ def create_bounds_geojson(self, pointcloud_path, buffer_distance = 0, decimation
@return filename to GeoJSON containing the polygon
"""
if not os.path.exists(pointcloud_path):
log.ODM_WARNING('Point cloud does not exist, cannot generate bounds {}'.format(pointcloud_path))
log.WARNING('Point cloud does not exist, cannot generate bounds {}'.format(pointcloud_path))
return ''

# Do decimation prior to extracting boundary information
Expand All @@ -143,7 +143,7 @@ def create_bounds_geojson(self, pointcloud_path, buffer_distance = 0, decimation
"--filters.decimation.step={} ".format(pointcloud_path, decimated_pointcloud_path, decimation_step))

if not os.path.exists(decimated_pointcloud_path):
log.ODM_WARNING('Could not decimate point cloud, thus cannot generate GPKG bounds {}'.format(decimated_pointcloud_path))
log.WARNING('Could not decimate point cloud, thus cannot generate GPKG bounds {}'.format(decimated_pointcloud_path))
return ''

# Use PDAL to dump boundary information
Expand Down Expand Up @@ -188,7 +188,7 @@ def create_bounds_geojson(self, pointcloud_path, buffer_distance = 0, decimation
if tmp.Area() > 0:
convexhull = tmp
else:
log.ODM_WARNING("Very small crop area detected, we will not smooth it.")
log.WARNING("Very small crop area detected, we will not smooth it.")

# Save to a new file
bounds_geojson_path = self.path('bounds.geojson')
Expand Down Expand Up @@ -228,7 +228,7 @@ def create_bounds_gpkg(self, pointcloud_path, buffer_distance = 0, decimation_st
@return filename to Geopackage containing the polygon
"""
if not os.path.exists(pointcloud_path):
log.ODM_WARNING('Point cloud does not exist, cannot generate GPKG bounds {}'.format(pointcloud_path))
log.WARNING('Point cloud does not exist, cannot generate GPKG bounds {}'.format(pointcloud_path))
return ''


Expand Down
22 changes: 11 additions & 11 deletions opendm/cutline.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ def write_raster(data, file):

def compute_cutline(orthophoto_file, crop_area_file, destination, max_concurrency=1, scale=1):
if io.file_exists(orthophoto_file) and io.file_exists(crop_area_file):
log.ODM_INFO("Computing cutline")
log.INFO("Computing cutline")

scale = max(0.0001, min(1, scale))
scaled_orthophoto = None
if scale < 1:
log.ODM_INFO("Scaling orthophoto to %s%% to compute cutline" % (scale * 100))
log.INFO("Scaling orthophoto to %s%% to compute cutline" % (scale * 100))

scaled_orthophoto = io.related_file_path(orthophoto_file, postfix=".scaled")
# Scale orthophoto before computing cutline
Expand All @@ -65,12 +65,12 @@ def compute_cutline(orthophoto_file, crop_area_file, destination, max_concurrenc
line_ver_offset = int(height / number_lines)

if line_hor_offset <= 2 or line_ver_offset <= 2:
log.ODM_WARNING("Cannot compute cutline, orthophoto is too small (%sx%spx)" % (width, height))
log.WARNING("Cannot compute cutline, orthophoto is too small (%sx%spx)" % (width, height))
return

crop_f = fiona.open(crop_area_file, 'r')
if len(crop_f) == 0:
log.ODM_WARNING("Crop area is empty, cannot compute cutline")
log.WARNING("Crop area is empty, cannot compute cutline")
return

crop_poly = shape(crop_f[1]['geometry'])
Expand All @@ -82,7 +82,7 @@ def compute_cutline(orthophoto_file, crop_area_file, destination, max_concurrenc
edges = canny(rast)

def compute_linestrings(direction):
log.ODM_INFO("Computing %s cutlines" % direction)
log.INFO("Computing %s cutlines" % direction)
# Initialize cost map
cost_map = np.full((height, width), 1, dtype=np.float32)

Expand Down Expand Up @@ -129,18 +129,18 @@ def compute_linestrings(direction):


# Generate polygons and keep only those inside the crop area
log.ODM_INFO("Generating polygons... this could take a bit.")
log.INFO("Generating polygons... this could take a bit.")
polygons = []
for p in polygonize(unary_union(linestrings)):
if crop_poly.contains(p):
polygons.append(p)

# This should never happen
if len(polygons) == 0:
log.ODM_WARNING("No polygons, cannot compute cutline")
log.WARNING("No polygons, cannot compute cutline")
return

log.ODM_INFO("Merging polygons")
log.INFO("Merging polygons")
cutline_polygons = unary_union(polygons)

if not hasattr(cutline_polygons, 'geoms'):
Expand All @@ -154,7 +154,7 @@ def compute_linestrings(direction):
max_area = p.area
largest_cutline = p

log.ODM_INFO("Largest cutline found: %s m^2" % max_area)
log.INFO("Largest cutline found: %s m^2" % max_area)

meta = {
'crs': fiona.crs.CRS.from_wkt(f.crs.to_wkt()),
Expand All @@ -175,10 +175,10 @@ def compute_linestrings(direction):
'properties': {}
})
f.close()
log.ODM_INFO("Wrote %s" % destination)
log.INFO("Wrote %s" % destination)

# Cleanup
if scaled_orthophoto is not None and os.path.exists(scaled_orthophoto):
os.remove(scaled_orthophoto)
else:
log.ODM_WARNING("We've been asked to compute cutline, but either %s or %s is missing. Skipping..." % (orthophoto_file, crop_area_file))
log.WARNING("We've been asked to compute cutline, but either %s or %s is missing. Skipping..." % (orthophoto_file, crop_area_file))
Loading
Loading