diff --git a/opendm/multispectral.py b/opendm/multispectral.py index 0520bfd7..e1d530a3 100644 --- a/opendm/multispectral.py +++ b/opendm/multispectral.py @@ -421,6 +421,18 @@ def compute_homography(image_filename, align_image_filename): def find_ecc_homography(image_gray, align_image_gray, number_of_iterations=1000, termination_eps=1e-8, start_eps=1e-4): pyramid_levels = 0 h,w = image_gray.shape + max_dim = max(h, w) + + max_size = 1280 + + if max_dim > max_size: + if max_dim == w: + f = max_size / w + else: + f = max_size / h + image_gray = cv2.resize(image_gray, None, fx=f, fy=f, interpolation=cv2.INTER_AREA) + h,w = image_gray.shape + min_dim = min(h, w) while min_dim > 300: @@ -434,10 +446,10 @@ def find_ecc_homography(image_gray, align_image_gray, number_of_iterations=1000, align_image_gray = to_8bit(align_image_gray) image_gray = to_8bit(image_gray) - fx = align_image_gray.shape[1]/image_gray.shape[1] - fy = align_image_gray.shape[0]/image_gray.shape[0] + fx = image_gray.shape[1]/align_image_gray.shape[1] + fy = image_gray.shape[0]/align_image_gray.shape[0] - image_gray = cv2.resize(image_gray, None, + align_image_gray = cv2.resize(align_image_gray, None, fx=fx, fy=fy, interpolation=(cv2.INTER_AREA if (fx < 1.0 and fy < 1.0) else cv2.INTER_LANCZOS4)) diff --git a/opendm/photo.py b/opendm/photo.py index c4bc5a38..b8df4ebd 100644 --- a/opendm/photo.py +++ b/opendm/photo.py @@ -459,6 +459,21 @@ class ODM_Photo: # self.set_attr_from_xmp_tag('bandwidth', xtags, [ # 'Camera:WavelengthFWHM' # ], float) + + # Special case band handling for AeroVironment Quantix images + # for some reason, they don't store band information in EXIFs + if self.camera_make.lower() == 'aerovironment' and \ + self.camera_model.lower() == 'quantix': + matches = re.match("IMG_(\d+)_(\w+)\.\w+", self.filename, re.IGNORECASE) + if matches: + band_aliases = { + 'GRN': 'Green', + 'NIR': 'Nir', + 'RED': 'Red', + 'RGB': 'RedGreenBlue', + } + self.capture_uuid = matches.group(1) + self.band_name = band_aliases.get(matches.group(2), matches.group(2)) # Sanitize band name since we use it in folder paths self.band_name = re.sub('[^A-Za-z0-9]+', '', self.band_name) diff --git a/opendm/types.py b/opendm/types.py index 7c529faa..a6110126 100644 --- a/opendm/types.py +++ b/opendm/types.py @@ -76,17 +76,27 @@ class ODM_Reconstruction(object): bands = {} for b in self.multi_camera: bands[b['name'].lower()] = b['name'] + + bands_to_remove = [] - if ('rgb' in bands or 'redgreenblue' in bands) and \ - ('red' in bands and 'green' in bands and 'blue' in bands): - band_to_remove = bands['rgb'] if 'rgb' in bands else bands['redgreenblue'] + if 'rgb' in bands or 'redgreenblue' in bands: + if 'red' in bands and 'green' in bands and 'blue' in bands: + bands_to_remove.append(bands['rgb'] if 'rgb' in bands else bands['redgreenblue']) + else: + for b in ['red', 'green', 'blue']: + if b in bands: + bands_to_remove.append(bands[b]) - self.multi_camera = [b for b in self.multi_camera if b['name'] != band_to_remove] - photos_before = len(self.photos) - self.photos = [p for p in self.photos if p.band_name != band_to_remove] - photos_after = len(self.photos) + if len(bands_to_remove) > 0: + log.ODM_WARNING("Redundant bands detected, probably because RGB images are mixed with single band images. We will trim some bands as needed") - log.ODM_WARNING("RGB images detected alongside individual Red/Green/Blue images, we will use individual bands (skipping %s images)" % (photos_before - photos_after)) + for band_to_remove in bands_to_remove: + self.multi_camera = [b for b in self.multi_camera if b['name'] != band_to_remove] + photos_before = len(self.photos) + self.photos = [p for p in self.photos if p.band_name != band_to_remove] + photos_after = len(self.photos) + + log.ODM_WARNING("Skipping %s band (%s images)" % (band_to_remove, photos_before - photos_after)) def is_georeferenced(self): return self.georef is not None diff --git a/stages/run_opensfm.py b/stages/run_opensfm.py index 6a3dc4a6..5ef220c2 100644 --- a/stages/run_opensfm.py +++ b/stages/run_opensfm.py @@ -104,9 +104,9 @@ class ODMOpenSfMStage(types.ODM_Stage): image = func(shot_id, image) return image - def resize_thermal_images(shot_id, image): + def resize_secondary_images(shot_id, image): photo = reconstruction.get_photo(shot_id) - if photo.is_thermal(): + if photo.band_name != primary_band_name: return thermal.resize_to_match(image, largest_photo) else: return image @@ -138,8 +138,8 @@ class ODMOpenSfMStage(types.ODM_Stage): return image if reconstruction.multi_camera: - largest_photo = find_largest_photo(photos) - undistort_pipeline.append(resize_thermal_images) + largest_photo = find_largest_photo([p for p in photos if p.band_name == primary_band_name]) + undistort_pipeline.append(resize_secondary_images) if args.radiometric_calibration != "none": undistort_pipeline.append(radiometric_calibrate)