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_DIR      ${SB_DOWNLOAD_DIR}
 | 
			
		||||
  GIT_REPOSITORY    https://github.com/OpenDroneMap/openMVS
 | 
			
		||||
  GIT_TAG           210
 | 
			
		||||
  GIT_TAG           230
 | 
			
		||||
  #--Update/Patch step----------
 | 
			
		||||
  UPDATE_COMMAND    ""
 | 
			
		||||
  #--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)
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
    which handles gracefully CTRL+C and reverts to 
 | 
			
		||||
| 
						 | 
				
			
			@ -85,7 +85,7 @@ def parallel_map(func, items, max_workers=1):
 | 
			
		|||
 | 
			
		||||
        stop_workers()
 | 
			
		||||
 | 
			
		||||
        if error is not None:
 | 
			
		||||
        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...")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ import os
 | 
			
		|||
from opendm import dls
 | 
			
		||||
import numpy as np
 | 
			
		||||
from opendm import log
 | 
			
		||||
from opendm.concurrency import parallel_map
 | 
			
		||||
from opensfm.io import imread
 | 
			
		||||
 | 
			
		||||
from skimage import exposure
 | 
			
		||||
| 
						 | 
				
			
			@ -270,7 +271,7 @@ def compute_band_maps(multi_camera, primary_band):
 | 
			
		|||
 | 
			
		||||
        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")
 | 
			
		||||
 | 
			
		||||
    alignment_info = {}
 | 
			
		||||
| 
						 | 
				
			
			@ -280,46 +281,76 @@ def compute_alignment_matrices(multi_camera, primary_band_name, images_path, s2p
 | 
			
		|||
        if band['name'] != primary_band_name:
 | 
			
		||||
            matrices = []
 | 
			
		||||
 | 
			
		||||
            # if band['name'] != "NIR":
 | 
			
		||||
            #     continue # TODO REMOVE
 | 
			
		||||
            def parallel_compute_homography(p):
 | 
			
		||||
                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
 | 
			
		||||
            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'])
 | 
			
		||||
                    if primary_band_photo is None:
 | 
			
		||||
                        log.ODM_WARNING("Cannot find primary band photo for %s" % p['filename'])
 | 
			
		||||
                        return
 | 
			
		||||
 | 
			
		||||
                    warp_matrix, dimension, algo = compute_homography(os.path.join(images_path, p['filename']),
 | 
			
		||||
                                                                os.path.join(images_path, primary_band_photo.filename))
 | 
			
		||||
                    
 | 
			
		||||
                    if warp_matrix is not None:
 | 
			
		||||
                    log.ODM_INFO("%s --> %s good match (score: %s)" % (p.filename, primary_band_photo.filename, score))
 | 
			
		||||
                        log.ODM_INFO("%s --> %s good match" % (p['filename'], primary_band_photo.filename))
 | 
			
		||||
 | 
			
		||||
                        matrices.append({
 | 
			
		||||
                            'warp_matrix': warp_matrix,
 | 
			
		||||
                        'score': score,
 | 
			
		||||
                        'dimension': dimension
 | 
			
		||||
                            '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))
 | 
			
		||||
                        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)))
 | 
			
		||||
 | 
			
		||||
                if len(matrices) >= max_samples:
 | 
			
		||||
                    log.ODM_INFO("Got enough samples for %s (%s)" % (band['name'], max_samples))
 | 
			
		||||
                    break
 | 
			
		||||
            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
 | 
			
		||||
            matrices.sort(key=lambda x: x['score'], reverse=False)
 | 
			
		||||
            
 | 
			
		||||
            if len(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:
 | 
			
		||||
                log.ODM_WARNING("Cannot find alignment matrix for band %s, The band will likely be misaligned!" % band['name'])
 | 
			
		||||
 | 
			
		||||
    return alignment_info
 | 
			
		||||
 | 
			
		||||
def compute_homography(image_filename, align_image_filename):
 | 
			
		||||
    # try:
 | 
			
		||||
    try:
 | 
			
		||||
        # Convert images to grayscale if needed
 | 
			
		||||
        image = imread(image_filename, unchanged=True, anydepth=True)
 | 
			
		||||
        if image.shape[2] == 3:
 | 
			
		||||
| 
						 | 
				
			
			@ -336,37 +367,43 @@ def compute_homography(image_filename, align_image_filename):
 | 
			
		|||
        def compute_using(algorithm):
 | 
			
		||||
            h = algorithm(image_gray, align_image_gray)
 | 
			
		||||
            if h is None:
 | 
			
		||||
            return None, None, (None, None)
 | 
			
		||||
                return None, (None, None)
 | 
			
		||||
 | 
			
		||||
            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, None)
 | 
			
		||||
                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, None)
 | 
			
		||||
                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])
 | 
			
		||||
        
 | 
			
		||||
        algo = 'feat'
 | 
			
		||||
        result = compute_using(find_features_homography)
 | 
			
		||||
 | 
			
		||||
        if result[0] is None:
 | 
			
		||||
            algo = 'ecc'
 | 
			
		||||
            log.ODM_INFO("Can't use features matching, will use ECC (this might take a bit)")
 | 
			
		||||
            result = compute_using(find_ecc_homography)
 | 
			
		||||
            if result[0] is None:
 | 
			
		||||
                algo = None
 | 
			
		||||
        
 | 
			
		||||
        warp_matrix, dimension = result
 | 
			
		||||
        return warp_matrix, dimension, algo
 | 
			
		||||
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        log.ODM_WARNING("Compute homography: %s" % str(e))
 | 
			
		||||
        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])
 | 
			
		||||
    
 | 
			
		||||
    result = compute_using(find_features_homography)
 | 
			
		||||
    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:
 | 
			
		||||
    #     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):
 | 
			
		||||
def find_ecc_homography(image_gray, align_image_gray, number_of_iterations=2500, termination_eps=1e-9):
 | 
			
		||||
    image_gray = to_8bit(gradient(gaussian(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,
 | 
			
		||||
     number_of_iterations, termination_eps)
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
      (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)
 | 
			
		||||
    _, warp_matrix = cv2.findTransformECC (image_gray,align_image_gray,warp_matrix, cv2.MOTION_HOMOGRAPHY, criteria, inputMask=None, gaussFiltSize=9)
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
    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):
 | 
			
		||||
    im = local_normalize(im)
 | 
			
		||||
    grad_x = cv2.Sobel(im,cv2.CV_32F,1,0,ksize=ksize)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -315,11 +315,11 @@ class OSFMContext:
 | 
			
		|||
        else:
 | 
			
		||||
            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)
 | 
			
		||||
        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)
 | 
			
		||||
 | 
			
		||||
            if image_list is not None:
 | 
			
		||||
| 
						 | 
				
			
			@ -327,32 +327,35 @@ class OSFMContext:
 | 
			
		|||
 | 
			
		||||
            undistort.run_dataset(ds, "reconstruction.json", 
 | 
			
		||||
                                  0, None, "undistorted", imageFilter)
 | 
			
		||||
            
 | 
			
		||||
            self.touch(done_flag_file)
 | 
			
		||||
        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):
 | 
			
		||||
        recon_file = self.path("reconstruction.json")
 | 
			
		||||
        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:
 | 
			
		||||
        with open(self.recon_file()) as f:
 | 
			
		||||
            reconstruction = json.loads(f.read())
 | 
			
		||||
 | 
			
		||||
        # Augment reconstruction.json
 | 
			
		||||
| 
						 | 
				
			
			@ -369,13 +372,9 @@ class OSFMContext:
 | 
			
		|||
                for p in secondary_photos:
 | 
			
		||||
                    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))
 | 
			
		||||
 | 
			
		||||
        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):
 | 
			
		||||
        cfg_file = self.get_config_file_path()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ PyYAML==5.1
 | 
			
		|||
rasterio==1.1.8
 | 
			
		||||
repoze.lru==0.7
 | 
			
		||||
scikit-learn==0.23.2
 | 
			
		||||
scikit-image==0.17.2
 | 
			
		||||
scipy==1.5.4
 | 
			
		||||
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))
 | 
			
		||||
                return image
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        if args.radiometric_calibration != "none":
 | 
			
		||||
            undistort_pipeline.append(radiometric_calibrate)
 | 
			
		||||
        
 | 
			
		||||
| 
						 | 
				
			
			@ -113,12 +112,12 @@ class ODMOpenSfMStage(types.ODM_Stage):
 | 
			
		|||
            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)
 | 
			
		||||
                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)
 | 
			
		||||
 | 
			
		||||
                # TODO: what happens to reconstruction.backup.json
 | 
			
		||||
                # if the process fails here?
 | 
			
		||||
 | 
			
		||||
                octx.touch(added_shots_file)
 | 
			
		||||
 | 
			
		||||
            undistort_pipeline.append(align_to_primary_band)
 | 
			
		||||
| 
						 | 
				
			
			@ -148,16 +147,8 @@ class ODMOpenSfMStage(types.ODM_Stage):
 | 
			
		|||
                else:
 | 
			
		||||
                    log.ODM_WARNING("Found a valid NVM file in %s for %s band" % (nvm_file, band['name']))
 | 
			
		||||
 | 
			
		||||
            recon_file = octx.path("reconstruction.json")
 | 
			
		||||
            recon_backup_file = octx.path("reconstruction.backup.json")
 | 
			
		||||
 | 
			
		||||
            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)
 | 
			
		||||
            octx.restore_reconstruction_backup()
 | 
			
		||||
            octx.convert_and_undistort(self.rerun(), undistort_callback, runId='primary')
 | 
			
		||||
 | 
			
		||||
        if not io.file_exists(tree.opensfm_reconstruction_nvm) or self.rerun():
 | 
			
		||||
            octx.run('export_visualsfm --points')
 | 
			
		||||
| 
						 | 
				
			
			@ -194,6 +185,9 @@ class ODMOpenSfMStage(types.ODM_Stage):
 | 
			
		|||
        
 | 
			
		||||
        if args.optimize_disk_space:
 | 
			
		||||
            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")):
 | 
			
		||||
                files = glob.glob(octx.path("undistorted", "depthmaps", "*.npz"))
 | 
			
		||||
                for f in files:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue