kopia lustrzana https://github.com/OpenDroneMap/ODM
Stability improvements, bug fixes, updated OpenMVS
rodzic
7c42409567
commit
92d05243b1
|
@ -20,7 +20,7 @@ ExternalProject_Add(${_proj_name}
|
||||||
#--Download step--------------
|
#--Download step--------------
|
||||||
DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}
|
DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}
|
||||||
GIT_REPOSITORY https://github.com/OpenDroneMap/openMVS
|
GIT_REPOSITORY https://github.com/OpenDroneMap/openMVS
|
||||||
GIT_TAG 210
|
GIT_TAG 230
|
||||||
#--Update/Patch step----------
|
#--Update/Patch step----------
|
||||||
UPDATE_COMMAND ""
|
UPDATE_COMMAND ""
|
||||||
#--Configure step-------------
|
#--Configure step-------------
|
||||||
|
|
|
@ -24,7 +24,7 @@ def get_max_memory_mb(minimum = 100, use_at_most = 0.5):
|
||||||
"""
|
"""
|
||||||
return max(minimum, (virtual_memory().available / 1024 / 1024) * use_at_most)
|
return max(minimum, (virtual_memory().available / 1024 / 1024) * use_at_most)
|
||||||
|
|
||||||
def parallel_map(func, items, max_workers=1):
|
def parallel_map(func, items, max_workers=1, single_thread_fallback=True):
|
||||||
"""
|
"""
|
||||||
Our own implementation for parallel processing
|
Our own implementation for parallel processing
|
||||||
which handles gracefully CTRL+C and reverts to
|
which handles gracefully CTRL+C and reverts to
|
||||||
|
@ -85,7 +85,7 @@ def parallel_map(func, items, max_workers=1):
|
||||||
|
|
||||||
stop_workers()
|
stop_workers()
|
||||||
|
|
||||||
if error is not None:
|
if error is not None and single_thread_fallback:
|
||||||
# Try to reprocess using a single thread
|
# Try to reprocess using a single thread
|
||||||
# in case this was a memory error
|
# in case this was a memory error
|
||||||
log.ODM_WARNING("Failed to run process in parallel, retrying with a single thread...")
|
log.ODM_WARNING("Failed to run process in parallel, retrying with a single thread...")
|
||||||
|
|
|
@ -5,6 +5,7 @@ import os
|
||||||
from opendm import dls
|
from opendm import dls
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from opendm import log
|
from opendm import log
|
||||||
|
from opendm.concurrency import parallel_map
|
||||||
from opensfm.io import imread
|
from opensfm.io import imread
|
||||||
|
|
||||||
from skimage import exposure
|
from skimage import exposure
|
||||||
|
@ -270,7 +271,7 @@ def compute_band_maps(multi_camera, primary_band):
|
||||||
|
|
||||||
return s2p, p2s
|
return s2p, p2s
|
||||||
|
|
||||||
def compute_alignment_matrices(multi_camera, primary_band_name, images_path, s2p, p2s, max_samples=9999):
|
def compute_alignment_matrices(multi_camera, primary_band_name, images_path, s2p, p2s, max_concurrency=1, max_samples=30):
|
||||||
log.ODM_INFO("Computing band alignment")
|
log.ODM_INFO("Computing band alignment")
|
||||||
|
|
||||||
alignment_info = {}
|
alignment_info = {}
|
||||||
|
@ -280,93 +281,129 @@ def compute_alignment_matrices(multi_camera, primary_band_name, images_path, s2p
|
||||||
if band['name'] != primary_band_name:
|
if band['name'] != primary_band_name:
|
||||||
matrices = []
|
matrices = []
|
||||||
|
|
||||||
# if band['name'] != "NIR":
|
def parallel_compute_homography(p):
|
||||||
# continue # TODO REMOVE
|
try:
|
||||||
|
if len(matrices) >= max_samples:
|
||||||
|
log.ODM_INFO("Got enough samples for %s (%s)" % (band['name'], max_samples))
|
||||||
|
return
|
||||||
|
|
||||||
# Find good matrix candidates for alignment
|
# Find good matrix candidates for alignment
|
||||||
for p in band['photos']:
|
|
||||||
primary_band_photo = s2p.get(p.filename)
|
|
||||||
if primary_band_photo is None:
|
|
||||||
log.ODM_WARNING("Cannot find primary band photo for %s" % p.filename)
|
|
||||||
continue
|
|
||||||
|
|
||||||
warp_matrix, score, dimension = compute_homography(os.path.join(images_path, p.filename),
|
primary_band_photo = s2p.get(p['filename'])
|
||||||
os.path.join(images_path, primary_band_photo.filename))
|
if primary_band_photo is None:
|
||||||
|
log.ODM_WARNING("Cannot find primary band photo for %s" % p['filename'])
|
||||||
|
return
|
||||||
|
|
||||||
if warp_matrix is not None:
|
warp_matrix, dimension, algo = compute_homography(os.path.join(images_path, p['filename']),
|
||||||
log.ODM_INFO("%s --> %s good match (score: %s)" % (p.filename, primary_band_photo.filename, score))
|
os.path.join(images_path, primary_band_photo.filename))
|
||||||
matrices.append({
|
|
||||||
'warp_matrix': warp_matrix,
|
|
||||||
'score': score,
|
|
||||||
'dimension': dimension
|
|
||||||
})
|
|
||||||
else:
|
|
||||||
log.ODM_INFO("%s --> %s cannot be matched" % (p.filename, primary_band_photo.filename))
|
|
||||||
|
|
||||||
if len(matrices) >= max_samples:
|
if warp_matrix is not None:
|
||||||
log.ODM_INFO("Got enough samples for %s (%s)" % (band['name'], max_samples))
|
log.ODM_INFO("%s --> %s good match" % (p['filename'], primary_band_photo.filename))
|
||||||
break
|
|
||||||
|
matrices.append({
|
||||||
|
'warp_matrix': warp_matrix,
|
||||||
|
'eigvals': np.linalg.eigvals(warp_matrix),
|
||||||
|
'dimension': dimension,
|
||||||
|
'algo': algo
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
log.ODM_INFO("%s --> %s cannot be matched" % (p['filename'], primary_band_photo.filename))
|
||||||
|
except Exception as e:
|
||||||
|
log.ODM_WARNING("Failed to compute homography for %s: %s" % (p['filename'], str(e)))
|
||||||
|
|
||||||
|
parallel_map(parallel_compute_homography, [{'filename': p.filename} for p in band['photos']], max_concurrency, single_thread_fallback=False)
|
||||||
|
|
||||||
|
# Choose winning algorithm (doesn't seem to yield improvements)
|
||||||
|
# feat_count = 0
|
||||||
|
# ecc_count = 0
|
||||||
|
# for m in matrices:
|
||||||
|
# if m['algo'] == 'feat':
|
||||||
|
# feat_count += 1
|
||||||
|
# if m['algo'] == 'ecc':
|
||||||
|
# ecc_count += 1
|
||||||
|
|
||||||
|
# algo = 'feat' if feat_count >= ecc_count else 'ecc'
|
||||||
|
|
||||||
|
# log.ODM_INFO("Feat: %s | ECC: %s | Winner: %s" % (feat_count, ecc_count, algo))
|
||||||
|
# matrices = [m for m in matrices if m['algo'] == algo]
|
||||||
|
|
||||||
|
# Find the matrix that has the most common eigvals
|
||||||
|
# among all matrices. That should be the "best" alignment.
|
||||||
|
for m1 in matrices:
|
||||||
|
acc = np.array([0.0,0.0,0.0])
|
||||||
|
e = m1['eigvals']
|
||||||
|
|
||||||
|
for m2 in matrices:
|
||||||
|
acc += abs(e - m2['eigvals'])
|
||||||
|
|
||||||
|
m1['score'] = acc.sum()
|
||||||
|
|
||||||
# Sort
|
# Sort
|
||||||
matrices.sort(key=lambda x: x['score'], reverse=False)
|
matrices.sort(key=lambda x: x['score'], reverse=False)
|
||||||
|
|
||||||
if len(matrices) > 0:
|
if len(matrices) > 0:
|
||||||
alignment_info[band['name']] = matrices[0]
|
alignment_info[band['name']] = matrices[0]
|
||||||
print(matrices[0])
|
log.ODM_INFO("%s band will be aligned using warp matrix %s (score: %s)" % (band['name'], matrices[0]['warp_matrix'], matrices[0]['score']))
|
||||||
else:
|
else:
|
||||||
log.ODM_WARNING("Cannot find alignment matrix for band %s, The band will likely be misaligned!" % band['name'])
|
log.ODM_WARNING("Cannot find alignment matrix for band %s, The band will likely be misaligned!" % band['name'])
|
||||||
|
|
||||||
return alignment_info
|
return alignment_info
|
||||||
|
|
||||||
def compute_homography(image_filename, align_image_filename):
|
def compute_homography(image_filename, align_image_filename):
|
||||||
# try:
|
try:
|
||||||
# Convert images to grayscale if needed
|
# Convert images to grayscale if needed
|
||||||
image = imread(image_filename, unchanged=True, anydepth=True)
|
image = imread(image_filename, unchanged=True, anydepth=True)
|
||||||
if image.shape[2] == 3:
|
if image.shape[2] == 3:
|
||||||
image_gray = to_8bit(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY))
|
image_gray = to_8bit(cv2.cvtColor(image, cv2.COLOR_BGR2GRAY))
|
||||||
else:
|
else:
|
||||||
image_gray = to_8bit(image[:,:,0])
|
image_gray = to_8bit(image[:,:,0])
|
||||||
|
|
||||||
align_image = imread(align_image_filename, unchanged=True, anydepth=True)
|
align_image = imread(align_image_filename, unchanged=True, anydepth=True)
|
||||||
if align_image.shape[2] == 3:
|
if align_image.shape[2] == 3:
|
||||||
align_image_gray = to_8bit(cv2.cvtColor(align_image, cv2.COLOR_BGR2GRAY))
|
align_image_gray = to_8bit(cv2.cvtColor(align_image, cv2.COLOR_BGR2GRAY))
|
||||||
else:
|
else:
|
||||||
align_image_gray = to_8bit(align_image[:,:,0])
|
align_image_gray = to_8bit(align_image[:,:,0])
|
||||||
|
|
||||||
def compute_using(algorithm):
|
def compute_using(algorithm):
|
||||||
h = algorithm(image_gray, align_image_gray)
|
h = algorithm(image_gray, align_image_gray)
|
||||||
if h is None:
|
if h is None:
|
||||||
return None, None, (None, None)
|
return None, (None, None)
|
||||||
|
|
||||||
det = np.linalg.det(h)
|
det = np.linalg.det(h)
|
||||||
|
|
||||||
|
# Check #1 homography's determinant will not be close to zero
|
||||||
|
if abs(det) < 0.25:
|
||||||
|
return None, (None, None)
|
||||||
|
|
||||||
|
# Check #2 the ratio of the first-to-last singular value is sane (not too high)
|
||||||
|
svd = np.linalg.svd(h, compute_uv=False)
|
||||||
|
if svd[-1] == 0:
|
||||||
|
return None, (None, None)
|
||||||
|
|
||||||
|
ratio = svd[0] / svd[-1]
|
||||||
|
if ratio > 100000:
|
||||||
|
return None, (None, None)
|
||||||
|
|
||||||
|
return h, (align_image_gray.shape[1], align_image_gray.shape[0])
|
||||||
|
|
||||||
# Check #1 homography's determinant will not be close to zero
|
algo = 'feat'
|
||||||
if abs(det) < 0.25:
|
result = compute_using(find_features_homography)
|
||||||
return None, None, (None, None)
|
|
||||||
|
|
||||||
# Check #2 the ratio of the first-to-last singular value is sane (not too high)
|
if result[0] is None:
|
||||||
svd = np.linalg.svd(h, compute_uv=False)
|
algo = 'ecc'
|
||||||
if svd[-1] == 0:
|
log.ODM_INFO("Can't use features matching, will use ECC (this might take a bit)")
|
||||||
return None, None, (None, None)
|
result = compute_using(find_ecc_homography)
|
||||||
|
if result[0] is None:
|
||||||
|
algo = None
|
||||||
|
|
||||||
ratio = svd[0] / svd[-1]
|
warp_matrix, dimension = result
|
||||||
if ratio > 100000:
|
return warp_matrix, dimension, algo
|
||||||
return None, None, (None, None)
|
|
||||||
|
|
||||||
return h, compute_alignment_score(h, image_gray, align_image_gray), (align_image_gray.shape[1], align_image_gray.shape[0])
|
except Exception as e:
|
||||||
|
log.ODM_WARNING("Compute homography: %s" % str(e))
|
||||||
result = compute_using(find_features_homography)
|
return None, None, (None, None)
|
||||||
if result[0] is None:
|
|
||||||
log.ODM_INFO("Can't use features matching, will use ECC")
|
|
||||||
result = compute_using(find_ecc_homography)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
# except Exception as e:
|
def find_ecc_homography(image_gray, align_image_gray, number_of_iterations=2500, termination_eps=1e-9):
|
||||||
# log.ODM_WARNING("Compute homography: %s" % str(e))
|
|
||||||
# return None, None, (None, None)
|
|
||||||
|
|
||||||
def find_ecc_homography(image_gray, align_image_gray, number_of_iterations=5000, termination_eps=1e-8):
|
|
||||||
image_gray = to_8bit(gradient(gaussian(image_gray)))
|
image_gray = to_8bit(gradient(gaussian(image_gray)))
|
||||||
align_image_gray = to_8bit(gradient(gaussian(align_image_gray)))
|
align_image_gray = to_8bit(gradient(gaussian(align_image_gray)))
|
||||||
|
|
||||||
|
@ -377,10 +414,7 @@ def find_ecc_homography(image_gray, align_image_gray, number_of_iterations=5000,
|
||||||
criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT,
|
criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT,
|
||||||
number_of_iterations, termination_eps)
|
number_of_iterations, termination_eps)
|
||||||
|
|
||||||
try:
|
_, warp_matrix = cv2.findTransformECC (image_gray,align_image_gray,warp_matrix, cv2.MOTION_HOMOGRAPHY, criteria, inputMask=None, gaussFiltSize=9)
|
||||||
(cc, warp_matrix) = cv2.findTransformECC (image_gray,align_image_gray,warp_matrix, cv2.MOTION_HOMOGRAPHY, criteria, inputMask=None, gaussFiltSize=1)
|
|
||||||
except:
|
|
||||||
(cc, warp_matrix) = cv2.findTransformECC (image_gray,align_image_gray,warp_matrix, cv2.MOTION_HOMOGRAPHY, criteria)
|
|
||||||
|
|
||||||
return warp_matrix
|
return warp_matrix
|
||||||
|
|
||||||
|
@ -418,37 +452,6 @@ def find_features_homography(image_gray, align_image_gray, feature_retention=0.2
|
||||||
h, _ = cv2.findHomography(points_image, points_align_image, cv2.RANSAC)
|
h, _ = cv2.findHomography(points_image, points_align_image, cv2.RANSAC)
|
||||||
return h
|
return h
|
||||||
|
|
||||||
def compute_alignment_score(warp_matrix, image_gray, align_image_gray, apply_gradient=True):
|
|
||||||
projected = align_image(image_gray, warp_matrix, (align_image_gray.shape[1], align_image_gray.shape[0]))
|
|
||||||
borders = projected==0
|
|
||||||
|
|
||||||
if apply_gradient:
|
|
||||||
image_gray = to_8bit(gradient(gaussian(image_gray)))
|
|
||||||
align_image_gray = to_8bit(gradient(gaussian(align_image_gray)))
|
|
||||||
|
|
||||||
# cv2.imwrite("/datasets/micasense/opensfm/undistorted/align_image_gray.jpg", align_image_gray)
|
|
||||||
# cv2.imwrite("/datasets/micasense/opensfm/undistorted/projected.jpg", projected)
|
|
||||||
|
|
||||||
# Threshold
|
|
||||||
align_image_gray[align_image_gray > 128] = 255
|
|
||||||
projected[projected > 128] = 255
|
|
||||||
align_image_gray[align_image_gray <= 128] = 0
|
|
||||||
projected[projected <= 128] = 0
|
|
||||||
|
|
||||||
# Mark borders
|
|
||||||
align_image_gray[borders] = 0
|
|
||||||
projected[borders] = 255
|
|
||||||
|
|
||||||
|
|
||||||
# cv2.imwrite("/datasets/micasense/opensfm/undistorted/threshold_align_image_gray.jpg", align_image_gray)
|
|
||||||
# cv2.imwrite("/datasets/micasense/opensfm/undistorted/threshold_projected.jpg", projected)
|
|
||||||
|
|
||||||
# cv2.imwrite("/datasets/micasense/opensfm/undistorted/delta.jpg", projected - align_image_gray)
|
|
||||||
|
|
||||||
# Compute delta --> the more the images overlap perfectly, the lower the score
|
|
||||||
return (projected - align_image_gray).sum()
|
|
||||||
|
|
||||||
|
|
||||||
def gradient(im, ksize=5):
|
def gradient(im, ksize=5):
|
||||||
im = local_normalize(im)
|
im = local_normalize(im)
|
||||||
grad_x = cv2.Sobel(im,cv2.CV_32F,1,0,ksize=ksize)
|
grad_x = cv2.Sobel(im,cv2.CV_32F,1,0,ksize=ksize)
|
||||||
|
|
|
@ -315,11 +315,11 @@ class OSFMContext:
|
||||||
else:
|
else:
|
||||||
log.ODM_INFO("Already extracted cameras")
|
log.ODM_INFO("Already extracted cameras")
|
||||||
|
|
||||||
def convert_and_undistort(self, rerun=False, imageFilter=None, image_list=None):
|
def convert_and_undistort(self, rerun=False, imageFilter=None, image_list=None, runId="nominal"):
|
||||||
log.ODM_INFO("Undistorting %s ..." % self.opensfm_project_path)
|
log.ODM_INFO("Undistorting %s ..." % self.opensfm_project_path)
|
||||||
undistorted_images_path = self.path("undistorted", "images")
|
done_flag_file = self.path("undistorted", "%s_done.txt" % runId)
|
||||||
|
|
||||||
if not io.dir_exists(undistorted_images_path) or rerun:
|
if not io.file_exists(done_flag_file) or rerun:
|
||||||
ds = DataSet(self.opensfm_project_path)
|
ds = DataSet(self.opensfm_project_path)
|
||||||
|
|
||||||
if image_list is not None:
|
if image_list is not None:
|
||||||
|
@ -327,32 +327,35 @@ class OSFMContext:
|
||||||
|
|
||||||
undistort.run_dataset(ds, "reconstruction.json",
|
undistort.run_dataset(ds, "reconstruction.json",
|
||||||
0, None, "undistorted", imageFilter)
|
0, None, "undistorted", imageFilter)
|
||||||
|
|
||||||
|
self.touch(done_flag_file)
|
||||||
else:
|
else:
|
||||||
log.ODM_WARNING("Found an undistorted directory in %s" % undistorted_images_path)
|
log.ODM_WARNING("Already undistorted (%s)" % runId)
|
||||||
|
|
||||||
|
def restore_reconstruction_backup(self):
|
||||||
|
if os.path.exists(self.recon_backup_file()):
|
||||||
|
# This time export the actual reconstruction.json
|
||||||
|
# (containing only the primary band)
|
||||||
|
if os.path.exists(self.recon_file()):
|
||||||
|
os.remove(self.recon_file())
|
||||||
|
os.rename(self.recon_backup_file(), self.recon_file())
|
||||||
|
log.ODM_INFO("Restored reconstruction.json")
|
||||||
|
|
||||||
|
def backup_reconstruction(self):
|
||||||
|
if os.path.exists(self.recon_backup_file()):
|
||||||
|
os.remove(self.recon_backup_file())
|
||||||
|
|
||||||
|
log.ODM_INFO("Backing up reconstruction")
|
||||||
|
shutil.copyfile(self.recon_file(), self.recon_backup_file())
|
||||||
|
|
||||||
|
def recon_backup_file(self):
|
||||||
|
return self.path("reconstruction.backup.json")
|
||||||
|
|
||||||
|
def recon_file(self):
|
||||||
|
return self.path("reconstruction.json")
|
||||||
|
|
||||||
def add_shots_to_reconstruction(self, p2s):
|
def add_shots_to_reconstruction(self, p2s):
|
||||||
recon_file = self.path("reconstruction.json")
|
with open(self.recon_file()) as f:
|
||||||
recon_backup_file = self.path("reconstruction.backup.json")
|
|
||||||
# tracks_file = self.path("tracks.csv")
|
|
||||||
# tracks_backup_file = self.path("tracks.backup.csv")
|
|
||||||
# image_list_file = self.path("image_list.txt")
|
|
||||||
# image_list_backup_file = self.path("image_list.backup.txt")
|
|
||||||
|
|
||||||
log.ODM_INFO("Adding shots to reconstruction")
|
|
||||||
if os.path.exists(recon_backup_file):
|
|
||||||
os.remove(recon_backup_file)
|
|
||||||
# if os.path.exists(tracks_backup_file):
|
|
||||||
# os.remove(tracks_backup_file)
|
|
||||||
# if os.path.exists(image_list_backup_file):
|
|
||||||
# os.remove(image_list_backup_file)
|
|
||||||
|
|
||||||
log.ODM_INFO("Backing up reconstruction, tracks, image list")
|
|
||||||
shutil.copyfile(recon_file, recon_backup_file)
|
|
||||||
|
|
||||||
# shutil.copyfile(tracks_file, tracks_backup_file)
|
|
||||||
# shutil.copyfile(image_list_file, image_list_backup_file)
|
|
||||||
|
|
||||||
with open(recon_file) as f:
|
|
||||||
reconstruction = json.loads(f.read())
|
reconstruction = json.loads(f.read())
|
||||||
|
|
||||||
# Augment reconstruction.json
|
# Augment reconstruction.json
|
||||||
|
@ -369,13 +372,9 @@ class OSFMContext:
|
||||||
for p in secondary_photos:
|
for p in secondary_photos:
|
||||||
shots[p.filename] = shots[shot_id]
|
shots[p.filename] = shots[shot_id]
|
||||||
|
|
||||||
with open(recon_file, 'w') as f:
|
with open(self.recon_file(), 'w') as f:
|
||||||
f.write(json.dumps(reconstruction))
|
f.write(json.dumps(reconstruction))
|
||||||
|
|
||||||
return True #(recon_file, recon_backup_file)
|
|
||||||
# (tracks_file, tracks_backup_file),
|
|
||||||
# (image_list_file, image_list_backup_file)]
|
|
||||||
|
|
||||||
|
|
||||||
def update_config(self, cfg_dict):
|
def update_config(self, cfg_dict):
|
||||||
cfg_file = self.get_config_file_path()
|
cfg_file = self.get_config_file_path()
|
||||||
|
|
|
@ -23,6 +23,7 @@ PyYAML==5.1
|
||||||
rasterio==1.1.8
|
rasterio==1.1.8
|
||||||
repoze.lru==0.7
|
repoze.lru==0.7
|
||||||
scikit-learn==0.23.2
|
scikit-learn==0.23.2
|
||||||
|
scikit-image==0.17.2
|
||||||
scipy==1.5.4
|
scipy==1.5.4
|
||||||
xmltodict==0.12.0
|
xmltodict==0.12.0
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,6 @@ class ODMOpenSfMStage(types.ODM_Stage):
|
||||||
log.ODM_WARNING("Cannot align %s, no alignment matrix could be computed. Band alignment quality might be affected." % (shot_id))
|
log.ODM_WARNING("Cannot align %s, no alignment matrix could be computed. Band alignment quality might be affected." % (shot_id))
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
||||||
if args.radiometric_calibration != "none":
|
if args.radiometric_calibration != "none":
|
||||||
undistort_pipeline.append(radiometric_calibrate)
|
undistort_pipeline.append(radiometric_calibrate)
|
||||||
|
|
||||||
|
@ -109,16 +108,16 @@ class ODMOpenSfMStage(types.ODM_Stage):
|
||||||
# We finally restore the original files later
|
# We finally restore the original files later
|
||||||
|
|
||||||
added_shots_file = octx.path('added_shots_done.txt')
|
added_shots_file = octx.path('added_shots_done.txt')
|
||||||
|
|
||||||
if not io.file_exists(added_shots_file) or self.rerun():
|
if not io.file_exists(added_shots_file) or self.rerun():
|
||||||
primary_band_name = multispectral.get_primary_band_name(reconstruction.multi_camera, args.primary_band)
|
primary_band_name = multispectral.get_primary_band_name(reconstruction.multi_camera, args.primary_band)
|
||||||
s2p, p2s = multispectral.compute_band_maps(reconstruction.multi_camera, primary_band_name)
|
s2p, p2s = multispectral.compute_band_maps(reconstruction.multi_camera, primary_band_name)
|
||||||
alignment_info = multispectral.compute_alignment_matrices(reconstruction.multi_camera, primary_band_name, tree.dataset_raw, s2p, p2s)
|
alignment_info = multispectral.compute_alignment_matrices(reconstruction.multi_camera, primary_band_name, tree.dataset_raw, s2p, p2s, max_concurrency=args.max_concurrency)
|
||||||
|
|
||||||
|
log.ODM_INFO("Adding shots to reconstruction")
|
||||||
|
|
||||||
|
octx.backup_reconstruction()
|
||||||
octx.add_shots_to_reconstruction(p2s)
|
octx.add_shots_to_reconstruction(p2s)
|
||||||
|
|
||||||
# TODO: what happens to reconstruction.backup.json
|
|
||||||
# if the process fails here?
|
|
||||||
|
|
||||||
octx.touch(added_shots_file)
|
octx.touch(added_shots_file)
|
||||||
|
|
||||||
undistort_pipeline.append(align_to_primary_band)
|
undistort_pipeline.append(align_to_primary_band)
|
||||||
|
@ -148,16 +147,8 @@ class ODMOpenSfMStage(types.ODM_Stage):
|
||||||
else:
|
else:
|
||||||
log.ODM_WARNING("Found a valid NVM file in %s for %s band" % (nvm_file, band['name']))
|
log.ODM_WARNING("Found a valid NVM file in %s for %s band" % (nvm_file, band['name']))
|
||||||
|
|
||||||
recon_file = octx.path("reconstruction.json")
|
octx.restore_reconstruction_backup()
|
||||||
recon_backup_file = octx.path("reconstruction.backup.json")
|
octx.convert_and_undistort(self.rerun(), undistort_callback, runId='primary')
|
||||||
|
|
||||||
if os.path.exists(recon_backup_file):
|
|
||||||
# This time export the actual reconstruction.json
|
|
||||||
# (containing only the primary band)
|
|
||||||
if os.path.exists(recon_backup_file):
|
|
||||||
os.remove(recon_file)
|
|
||||||
os.rename(recon_backup_file, recon_file)
|
|
||||||
octx.convert_and_undistort(self.rerun(), undistort_callback)
|
|
||||||
|
|
||||||
if not io.file_exists(tree.opensfm_reconstruction_nvm) or self.rerun():
|
if not io.file_exists(tree.opensfm_reconstruction_nvm) or self.rerun():
|
||||||
octx.run('export_visualsfm --points')
|
octx.run('export_visualsfm --points')
|
||||||
|
@ -194,6 +185,9 @@ class ODMOpenSfMStage(types.ODM_Stage):
|
||||||
|
|
||||||
if args.optimize_disk_space:
|
if args.optimize_disk_space:
|
||||||
os.remove(octx.path("tracks.csv"))
|
os.remove(octx.path("tracks.csv"))
|
||||||
|
if io.file_exists(octx.recon_backup_file()):
|
||||||
|
os.remove(octx.recon_backup_file())
|
||||||
|
|
||||||
if io.dir_exists(octx.path("undistorted", "depthmaps")):
|
if io.dir_exists(octx.path("undistorted", "depthmaps")):
|
||||||
files = glob.glob(octx.path("undistorted", "depthmaps", "*.npz"))
|
files = glob.glob(octx.path("undistorted", "depthmaps", "*.npz"))
|
||||||
for f in files:
|
for f in files:
|
||||||
|
|
Ładowanie…
Reference in New Issue