Skip to content
Draft
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
10 changes: 7 additions & 3 deletions SuperBuild/cmake/External-OpenSfM.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ if(DEFINED ENV{CONDA_PREFIX})
# propagated via the glog::glog cmake target, but OpenSfM links Ceres with
# the old-style ${CERES_LIBRARIES} variable and misses the transitive define.
set(OPENSFM_EXTRA_CXX_FLAGS "$ENV{CXXFLAGS} -DGLOG_USE_GLOG_EXPORT -DGLOG_USE_GFLAGS")
if(WIN32)
set(OPENSFM_EXTRA_CXX_FLAGS "${OPENSFM_EXTRA_CXX_FLAGS} /EHsc /GR")
endif()
endif()

ExternalProject_Add(${_proj_name}
Expand All @@ -40,10 +43,9 @@ ExternalProject_Add(${_proj_name}
#--Download step--------------
DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}
GIT_REPOSITORY https://github.com/OpenDroneMap/OpenSfM/
GIT_TAG c5328439465e6ace011f39077d1077d7b1cdd65d
GIT_TAG eebd2e7d2b76be5cff8d4cc218449dc8151665d9
#--Update/Patch step----------
UPDATE_COMMAND git submodule update --init --recursive
PATCH_COMMAND ${CMAKE_COMMAND} -P ${SB_ROOT_DIR}/cmake/apply-patch.cmake ${SB_ROOT_DIR}/cmake/opensfm-aarch64-abs.patch
#--Configure step-------------
SOURCE_DIR ${SB_INSTALL_DIR}/bin/${_proj_name}
CONFIGURE_COMMAND ${CMAKE_COMMAND} <SOURCE_DIR>/${_proj_name}/src
Expand All @@ -53,6 +55,7 @@ ExternalProject_Add(${_proj_name}
-DADDITIONAL_INCLUDE_DIRS=${OPENSFM_ADDITIONAL_INCLUDE_DIRS}
-DYET_ADDITIONAL_INCLUDE_DIRS=${EXTRA_INCLUDE_DIRS}
-DOPENSFM_BUILD_TESTS=off
-DOPENSFM_LINK_TCMALLOC=OFF
-DPYTHON_EXECUTABLE=${PYTHON_EXE_PATH}
-DCMAKE_CXX_FLAGS=${OPENSFM_EXTRA_CXX_FLAGS}
"-DCMAKE_MODULE_LINKER_FLAGS=${OPENSFM_EXTRA_LINKER_FLAGS}"
Expand All @@ -63,7 +66,8 @@ ExternalProject_Add(${_proj_name}
#--Build step-----------------
BINARY_DIR ${_SB_BINARY_DIR}
#--Install step---------------
INSTALL_COMMAND ""
INSTALL_COMMAND ${CMAKE_COMMAND} --install <BINARY_DIR> --config ${CMAKE_BUILD_TYPE}
--prefix ${SB_INSTALL_DIR}/bin/${_proj_name}/opensfm
#--Output logging-------------
LOG_DOWNLOAD OFF
LOG_CONFIGURE OFF
Expand Down
13 changes: 0 additions & 13 deletions SuperBuild/cmake/opensfm-aarch64-abs.patch

This file was deleted.

26 changes: 17 additions & 9 deletions opendm/osfm.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from opendm.multispectral import get_photos_by_band
from opendm.gpu import has_popsift_and_can_handle_texsize, has_gpu
from opensfm import multiview, exif
from opensfm.actions.export_geocoords import _transform

class OSFMContext:
def __init__(self, opensfm_project_path):
Expand All @@ -49,10 +48,16 @@ def create_tracks(self, rerun=False):
else:
log.ODM_WARNING('Found a valid OpenSfM tracks file in: %s' % tracks_file)

def reconstruct(self, rolling_shutter_correct=False, merge_partial=False, rerun=False):
def reconstruct(self, algorithm='incremental', rolling_shutter_correct=False, merge_partial=False, rerun=False):
# Upstream OpenSfM supports 'incremental' and 'triangulation', so map anything
# else (e.g. the deprecated 'planar') to incremental
if algorithm not in ('incremental', 'triangulation'):
log.ODM_WARNING("Unsupported SfM algorithm '%s', using incremental instead" % algorithm)
algorithm = 'incremental'

reconstruction_file = os.path.join(self.opensfm_project_path, 'reconstruction.json')
if not io.file_exists(reconstruction_file) or rerun:
self.run('reconstruct')
self.run('reconstruct --algorithm %s' % algorithm)
if merge_partial:
self.check_merge_partial_reconstructions()
else:
Expand All @@ -70,13 +75,13 @@ def reconstruct(self, rolling_shutter_correct=False, merge_partial=False, rerun=
rs_file = self.path('rs_done.txt')

if not io.file_exists(rs_file) or rerun:
self.run('rs_correct')
self.run('correct_rolling_shutter')

log.ODM_INFO("Re-running the reconstruction pipeline")

self.match_features(True)
self.create_tracks(True)
self.reconstruct(rolling_shutter_correct=False, merge_partial=merge_partial, rerun=True)
self.reconstruct(algorithm=algorithm, rolling_shutter_correct=False, merge_partial=merge_partial, rerun=True)

self.touch(rs_file)
else:
Expand Down Expand Up @@ -256,7 +261,6 @@ def setup(self, args, images_path, reconstruction, append_config = [], rerun=Fal
"matching_gps_distance: 0",
"matching_graph_rounds: %s" % matcher_graph_rounds,
"optimize_camera_parameters: %s" % ('no' if args.use_fixed_camera_params else 'yes'),
"reconstruction_algorithm: %s" % (args.sfm_algorithm),
"undistorted_image_format: tif",
"bundle_outlier_filtering_type: AUTO",
"sift_peak_threshold: 0.066",
Expand Down Expand Up @@ -372,7 +376,7 @@ def extract_metadata(self, rerun=False):
if not io.dir_exists(metadata_dir) or rerun:
self.run('extract_metadata')

def photos_to_metadata(self, photos, rolling_shutter, rolling_shutter_readout, rerun=False):
def photos_to_metadata(self, photos, rolling_shutter, rolling_shutter_readout, gps_accuracy, rerun=False):
metadata_dir = self.path("exif")

if io.dir_exists(metadata_dir) and not rerun:
Expand All @@ -388,7 +392,7 @@ def photos_to_metadata(self, photos, rolling_shutter, rolling_shutter_readout, r
data = DataSet(self.opensfm_project_path)

for p in photos:
d = p.to_opensfm_exif(rolling_shutter, rolling_shutter_readout)
d = p.to_opensfm_exif(rolling_shutter, rolling_shutter_readout, gps_accuracy)
with open(os.path.join(metadata_dir, "%s.exif" % p.filename), 'w') as f:
f.write(json.dumps(d, indent=4))

Expand Down Expand Up @@ -623,7 +627,11 @@ def ground_control_points(self, proj4):

result = []
for gcp in gcps_stats:
geocoords = _transform(gcp['coordinates'], reference, projection)
# Local coords (XYZ /ENU) to WGS84 (lat/lon/alt)
coords = gcp['coordinates']
lat, lon, altitude = reference.to_lla(coords[0], coords[1], coords[2])
easting, northing = projection(lon, lat)
geocoords = [easting, northing, altitude]
result.append({
'id': gcp['id'],
'observations': gcp['observations'],
Expand Down
18 changes: 15 additions & 3 deletions opendm/photo.py
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ def camera_id(self):
]
).lower()

def to_opensfm_exif(self, rolling_shutter = False, rolling_shutter_readout = 0):
def to_opensfm_exif(self, rolling_shutter = False, rolling_shutter_readout = 0, gps_accuracy = None):
capture_time = 0.0
if self.utc_time is not None:
capture_time = self.utc_time / 1000.0
Expand All @@ -838,10 +838,22 @@ def to_opensfm_exif(self, rolling_shutter = False, rolling_shutter_readout = 0):

dop = self.get_gps_dop()
if dop is None:
dop = 10.0 # Default

dop = gps_accuracy if gps_accuracy is not None else 10.0 # Default

# dop is a single GPS accuracy value. Older OpenSfM code still reads
# it, so keep writing it.
gps['dop'] = dop

# Newer OpenSfM wants horizontal and vertical GPS accuracy separately.
# ODM stores them per axis when it has them (e.g. RTK), so use those.
# If a value is missing, use dop for horizontal and assume vertical is
# 3x less accurate (typical for GPS).
horizontal = self.gps_xy_stddev if self.gps_xy_stddev is not None else dop
vertical = self.gps_z_stddev if self.gps_z_stddev is not None else horizontal * 3.0
gps['latitude_std'] = horizontal
gps['longitude_std'] = horizontal
gps['altitude_std'] = vertical

d = {
"make": self.camera_make,
"model": self.camera_model,
Expand Down
5 changes: 3 additions & 2 deletions opendm/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ class LocalRemoteExecutor:
to use the processing power of the current machine as well as offloading tasks to a
network node.
"""
def __init__(self, nodeUrl, rolling_shutter = False, rerun = False):
def __init__(self, nodeUrl, rolling_shutter = False, sfm_algorithm = 'incremental', rerun = False):
self.node = Node.from_url(nodeUrl)
self.params = {
'tasks': [],
'threads': [],
'rolling_shutter': rolling_shutter,
'sfm_algorithm': sfm_algorithm,
'rerun': rerun
}
self.node_online = True
Expand Down Expand Up @@ -447,7 +448,7 @@ def process_local(self):
log.ODM_INFO("==================================")
octx.feature_matching(self.params['rerun'])
octx.create_tracks(self.params['rerun'])
octx.reconstruct(self.params['rolling_shutter'], True, self.params['rerun'])
octx.reconstruct(self.params['sfm_algorithm'], self.params['rolling_shutter'], True, self.params['rerun'])

def process_remote(self, done):
octx = OSFMContext(self.path("opensfm"))
Expand Down
Loading
Loading