Extract band indexes

Former-commit-id: 446b5338f3
pull/1161/head
Piero Toffanin 2019-12-13 10:58:37 -05:00
rodzic 494a441ef9
commit 5ec1b58a70
3 zmienionych plików z 57 dodań i 33 usunięć

Wyświetl plik

@ -17,7 +17,8 @@ class OSFMContext:
self.opensfm_project_path = opensfm_project_path self.opensfm_project_path = opensfm_project_path
def run(self, command): def run(self, command):
system.run('%s/bin/opensfm %s "%s"' % # Use Python 2.x by default, otherwise OpenSfM uses Python 3.x
system.run('/usr/bin/env python2 %s/bin/opensfm %s "%s"' %
(context.opensfm_path, command, self.opensfm_project_path)) (context.opensfm_path, command, self.opensfm_project_path))
def is_reconstruction_done(self): def is_reconstruction_done(self):

Wyświetl plik

@ -32,6 +32,7 @@ class ODM_Photo:
self.longitude = None self.longitude = None
self.altitude = None self.altitude = None
self.band_name = 'RGB' self.band_name = 'RGB'
self.band_index = 0
# parse values from metadata # parse values from metadata
self.parse_exif_values(path_file) self.parse_exif_values(path_file)
@ -41,9 +42,9 @@ class ODM_Photo:
def __str__(self): def __str__(self):
return '{} | camera: {} {} | dimensions: {} x {} | lat: {} | lon: {} | alt: {} | band: {}'.format( return '{} | camera: {} {} | dimensions: {} x {} | lat: {} | lon: {} | alt: {} | band: {} ({})'.format(
self.filename, self.camera_make, self.camera_model, self.width, self.height, self.filename, self.camera_make, self.camera_model, self.width, self.height,
self.latitude, self.longitude, self.altitude, self.band_name) self.latitude, self.longitude, self.altitude, self.band_name, self.band_index)
def parse_exif_values(self, _path_file): def parse_exif_values(self, _path_file):
# Disable exifread log # Disable exifread log
@ -72,13 +73,21 @@ class ODM_Photo:
f.seek(0) f.seek(0)
xmp = self.get_xmp(f) xmp = self.get_xmp(f)
# Find band name (if available) # Find band name and camera index (if available)
camera_index_tags = [
'DLS:SensorId', # Micasense
'@Camera:RigCameraIndex' # Parrot Sequoia
]
for tags in xmp: for tags in xmp:
if 'Camera:BandName' in tags: if 'Camera:BandName' in tags:
self.band_name = str(tags['Camera:BandName']).replace(" ", "") self.band_name = str(tags['Camera:BandName']).replace(" ", "")
break else:
for cit in camera_index_tags:
if cit in tags:
self.band_index = int(tags[cit])
self.width, self.height = get_image_size.get_image_size(_path_file) self.width, self.height = get_image_size.get_image_size(_path_file)
print(self)
# From https://github.com/mapillary/OpenSfM/blob/master/opensfm/exif.py # From https://github.com/mapillary/OpenSfM/blob/master/opensfm/exif.py
def get_xmp(self, file): def get_xmp(self, file):
@ -128,24 +137,36 @@ class ODM_Reconstruction(object):
Looks at the reconstruction photos and determines if this Looks at the reconstruction photos and determines if this
is a single or multi-camera setup. is a single or multi-camera setup.
""" """
mc = {} band_photos = {}
band_indexes = {}
for p in self.photos: for p in self.photos:
if not p.band_name in mc: if not p.band_name in band_photos:
mc[p.band_name] = [] band_photos[p.band_name] = []
mc[p.band_name].append(p) if not p.band_name in band_indexes:
band_indexes[p.band_name] = p.band_index
band_photos[p.band_name].append(p)
bands_count = len(mc) bands_count = len(band_photos)
if bands_count >= 2 and bands_count <= 8: if bands_count >= 2 and bands_count <= 8:
# Validate that all bands have the same number of images, # Validate that all bands have the same number of images,
# otherwise this is not a multi-camera setup # otherwise this is not a multi-camera setup
img_per_band = len(mc[p.band_name]) img_per_band = len(band_photos[p.band_name])
for band in mc: for band in band_photos:
if len(mc[band]) != img_per_band: if len(band_photos[band]) != img_per_band:
log.ODM_ERROR("Multi-camera setup detected, but band \"%s\" (identified from \"%s\") has only %s images (instead of %s), perhaps images are missing or are corrupted. Please include all necessary files to process all bands and try again." % (band, mc[band][0].filename, len(mc[band]), img_per_band)) log.ODM_ERROR("Multi-camera setup detected, but band \"%s\" (identified from \"%s\") has only %s images (instead of %s), perhaps images are missing or are corrupted. Please include all necessary files to process all bands and try again." % (band, band_photos[band][0].filename, len(band_photos[band]), img_per_band))
raise RuntimeError("Invalid multi-camera images") raise RuntimeError("Invalid multi-camera images")
mc = []
for band_name in band_indexes:
mc.append({'name': band_name, 'photos': band_photos[band_name]})
# Sort by band index
mc.sort(key=lambda x: band_indexes[x['name']])
return mc return mc
return None return None
def is_georeferenced(self): def is_georeferenced(self):
@ -187,7 +208,7 @@ class ODM_Reconstruction(object):
log.ODM_INFO("GCP file already exist: %s" % output_gcp_file) log.ODM_INFO("GCP file already exist: %s" % output_gcp_file)
self.gcp = GCPFile(output_gcp_file) self.gcp = GCPFile(output_gcp_file)
self.georef = ODM_GeoRef.FromCoordsFile(output_coords_file) self.georef = ODM_GeoRef.Froband_photosoordsFile(output_coords_file)
return self.georef return self.georef
def georeference_with_gps(self, images_path, output_coords_file, rerun=False): def georeference_with_gps(self, images_path, output_coords_file, rerun=False):
@ -197,7 +218,7 @@ class ODM_Reconstruction(object):
else: else:
log.ODM_INFO("Coordinates file already exist: %s" % output_coords_file) log.ODM_INFO("Coordinates file already exist: %s" % output_coords_file)
self.georef = ODM_GeoRef.FromCoordsFile(output_coords_file) self.georef = ODM_GeoRef.Froband_photosoordsFile(output_coords_file)
except: except:
log.ODM_WARNING('Could not generate coordinates file. An orthophoto will not be generated.') log.ODM_WARNING('Could not generate coordinates file. An orthophoto will not be generated.')
@ -217,7 +238,7 @@ class ODM_GeoRef(object):
return ODM_GeoRef(CRS.from_proj4(projstring)) return ODM_GeoRef(CRS.from_proj4(projstring))
@staticmethod @staticmethod
def FromCoordsFile(coords_file): def Froband_photosoordsFile(coords_file):
# check for coordinate file existence # check for coordinate file existence
if not io.file_exists(coords_file): if not io.file_exists(coords_file):
log.ODM_WARNING('Could not find file %s' % coords_file) log.ODM_WARNING('Could not find file %s' % coords_file)

Wyświetl plik

@ -2,9 +2,10 @@ import unittest
from opendm import types from opendm import types
class ODMPhotoMock: class ODMPhotoMock:
def __init__(self, filename, band_name): def __init__(self, filename, band_name, band_index):
self.filename = filename self.filename = filename
self.band_name = band_name self.band_name = band_name
self.band_index = band_index
def __str__(self): def __str__(self):
return "%s (%s)" % (self.filename, self.band_name) return "%s (%s)" % (self.filename, self.band_name)
@ -18,29 +19,30 @@ class TestTypes(unittest.TestCase):
def test_reconstruction(self): def test_reconstruction(self):
# Multi camera setup # Multi camera setup
micasa_redsense_files = [('IMG_0298_1.tif', 'Red'), ('IMG_0298_2.tif', 'Green'), ('IMG_0298_3.tif', 'Blue'), ('IMG_0298_4.tif', 'NIR'), ('IMG_0298_5.tif', 'Rededge'), micasa_redsense_files = [('IMG_0298_1.tif', 'Red', 1), ('IMG_0298_2.tif', 'Green', 2), ('IMG_0298_3.tif', 'Blue', 3), ('IMG_0298_4.tif', 'NIR', 4), ('IMG_0298_5.tif', 'Rededge', 5),
('IMG_0299_1.tif', 'Red'), ('IMG_0299_2.tif', 'Green'), ('IMG_0299_3.tif', 'Blue'), ('IMG_0299_4.tif', 'NIR'), ('IMG_0299_5.tif', 'Rededge'), ('IMG_0299_1.tif', 'Red', 1), ('IMG_0299_2.tif', 'Green', 2), ('IMG_0299_3.tif', 'Blue', 3), ('IMG_0299_4.tif', 'NIR', 4), ('IMG_0299_5.tif', 'Rededge', 5),
('IMG_0300_1.tif', 'Red'), ('IMG_0300_2.tif', 'Green'), ('IMG_0300_3.tif', 'Blue'), ('IMG_0300_4.tif', 'NIR'), ('IMG_0300_5.tif', 'Rededge')] ('IMG_0300_1.tif', 'Red', 1), ('IMG_0300_2.tif', 'Green', 2), ('IMG_0300_3.tif', 'Blue', 3), ('IMG_0300_4.tif', 'NIR', 4), ('IMG_0300_5.tif', 'Rededge', 5)]
photos = [ODMPhotoMock(f, b) for f, b in micasa_redsense_files] photos = [ODMPhotoMock(f, b, i) for f, b, i in micasa_redsense_files]
recon = types.ODM_Reconstruction(photos) recon = types.ODM_Reconstruction(photos)
self.assertTrue(recon.multi_camera is not None) self.assertTrue(recon.multi_camera is not None)
# Found all 5 bands # Found all 5 bands
for b in ["Red", "Blue", "Green", "NIR", "Rededge"]: bands = ["Red", "Green", "Blue", "NIR", "Rededge"]
self.assertTrue(b in recon.multi_camera) for i in range(len(bands)):
self.assertTrue([p.filename for p in recon.multi_camera["Red"]] == ['IMG_0298_1.tif', 'IMG_0299_1.tif', 'IMG_0300_1.tif']) self.assertEqual(bands[i], recon.multi_camera[i]['name'])
self.assertTrue([p.filename for p in recon.multi_camera[0]['photos']] == ['IMG_0298_1.tif', 'IMG_0299_1.tif', 'IMG_0300_1.tif'])
# Missing a file # Missing a file
micasa_redsense_files = [('IMG_0298_1.tif', 'Red'), ('IMG_0298_2.tif', 'Green'), ('IMG_0298_3.tif', 'Blue'), ('IMG_0298_4.tif', 'NIR'), ('IMG_0298_5.tif', 'Rededge'), micasa_redsense_files = [('IMG_0298_1.tif', 'Red', 1), ('IMG_0298_2.tif', 'Green', 2), ('IMG_0298_3.tif', 'Blue', 3), ('IMG_0298_4.tif', 'NIR', 4), ('IMG_0298_5.tif', 'Rededge', 5),
('IMG_0299_2.tif', 'Green'), ('IMG_0299_3.tif', 'Blue'), ('IMG_0299_4.tif', 'NIR'), ('IMG_0299_5.tif', 'Rededge'), ('IMG_0299_2.tif', 'Green', 2), ('IMG_0299_3.tif', 'Blue', 3), ('IMG_0299_4.tif', 'NIR', 4), ('IMG_0299_5.tif', 'Rededge', 5),
('IMG_0300_1.tif', 'Red'), ('IMG_0300_2.tif', 'Green'), ('IMG_0300_3.tif', 'Blue'), ('IMG_0300_4.tif', 'NIR'), ('IMG_0300_5.tif', 'Rededge')] ('IMG_0300_1.tif', 'Red', 1), ('IMG_0300_2.tif', 'Green', 2), ('IMG_0300_3.tif', 'Blue', 3), ('IMG_0300_4.tif', 'NIR', 4), ('IMG_0300_5.tif', 'Rededge', 5)]
photos = [ODMPhotoMock(f, b) for f,b in micasa_redsense_files] photos = [ODMPhotoMock(f, b, i) for f,b,i in micasa_redsense_files]
self.assertRaises(RuntimeError, types.ODM_Reconstruction, photos) self.assertRaises(RuntimeError, types.ODM_Reconstruction, photos)
# Single camera # Single camera
dji_files = ['DJI_0018.JPG','DJI_0019.JPG','DJI_0020.JPG','DJI_0021.JPG','DJI_0022.JPG','DJI_0023.JPG'] dji_files = ['DJI_0018.JPG','DJI_0019.JPG','DJI_0020.JPG','DJI_0021.JPG','DJI_0022.JPG','DJI_0023.JPG']
photos = [ODMPhotoMock(f, 'RGB') for f in dji_files] photos = [ODMPhotoMock(f, 'RGB', 0) for f in dji_files]
recon = types.ODM_Reconstruction(photos) recon = types.ODM_Reconstruction(photos)
self.assertTrue(recon.multi_camera is None) self.assertTrue(recon.multi_camera is None)