diff --git a/SuperBuild/cmake/External-MvsTexturing.cmake b/SuperBuild/cmake/External-MvsTexturing.cmake index 2e916d9e..8410b11f 100644 --- a/SuperBuild/cmake/External-MvsTexturing.cmake +++ b/SuperBuild/cmake/External-MvsTexturing.cmake @@ -9,7 +9,7 @@ ExternalProject_Add(${_proj_name} #--Download step-------------- DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}/${_proj_name} GIT_REPOSITORY https://github.com/OpenDroneMap/mvs-texturing - GIT_TAG 267 + GIT_TAG 280 #--Update/Patch step---------- UPDATE_COMMAND "" #--Configure step------------- diff --git a/VERSION b/VERSION index 37c2961c..834f2629 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.7.2 +2.8.0 diff --git a/opendm/mesh.py b/opendm/mesh.py index 332c93a1..1a0e7834 100644 --- a/opendm/mesh.py +++ b/opendm/mesh.py @@ -105,6 +105,7 @@ def dem_to_mesh_gridded(inGeotiff, outMesh, maxVertexCount, verbose=False, maxCo '-maxTileLength 2000 ' '-maxVertexCount {maxVertexCount} ' '-maxConcurrency {maxConcurrency} ' + '-edgeSwapThreshold 0.15 ' ' {verbose} '.format(**kwargs)) break except Exception as e: diff --git a/opendm/photo.py b/opendm/photo.py index c37d0311..13ee1c6b 100644 --- a/opendm/photo.py +++ b/opendm/photo.py @@ -169,6 +169,9 @@ class ODM_Photo: except Exception as e: raise PhotoCorruptedException(str(e)) + tags = {} + xtags = {} + with open(_path_file, 'rb') as f: tags = exifread.process_file(f, details=False) try: @@ -199,11 +202,6 @@ class ODM_Photo: except (IndexError, ValueError) as e: log.ODM_WARNING("Cannot read basic EXIF tags for %s: %s" % (_path_file, str(e))) - try: - self.focal_ratio = self.extract_focal(self.camera_make, self.camera_model, tags) - except (IndexError, ValueError) as e: - log.ODM_WARNING("Cannot extract focal ratio for %s: %s" % (_path_file, str(e))) - try: if 'Image Tag 0xC61A' in tags: self.black_level = self.list_values(tags['Image Tag 0xC61A']) @@ -251,98 +249,108 @@ class ODM_Photo: f.seek(0) xmp = self.get_xmp(f) - for tags in xmp: + for xtags in xmp: try: - band_name = self.get_xmp_tag(tags, ['Camera:BandName', '@Camera:BandName']) + band_name = self.get_xmp_tag(xtags, ['Camera:BandName', '@Camera:BandName']) if band_name is not None: self.band_name = band_name.replace(" ", "") - self.set_attr_from_xmp_tag('band_index', tags, [ + self.set_attr_from_xmp_tag('band_index', xtags, [ 'DLS:SensorId', # Micasense RedEdge '@Camera:RigCameraIndex', # Parrot Sequoia, Sentera 21244-00_3.2MP-GS-0001 'Camera:RigCameraIndex', # MicaSense Altum ]) - self.set_attr_from_xmp_tag('radiometric_calibration', tags, [ + self.set_attr_from_xmp_tag('radiometric_calibration', xtags, [ 'MicaSense:RadiometricCalibration', ]) - self.set_attr_from_xmp_tag('vignetting_center', tags, [ + self.set_attr_from_xmp_tag('vignetting_center', xtags, [ 'Camera:VignettingCenter', 'Sentera:VignettingCenter', ]) - self.set_attr_from_xmp_tag('vignetting_polynomial', tags, [ + self.set_attr_from_xmp_tag('vignetting_polynomial', xtags, [ 'Camera:VignettingPolynomial', 'Sentera:VignettingPolynomial', ]) - self.set_attr_from_xmp_tag('horizontal_irradiance', tags, [ + self.set_attr_from_xmp_tag('horizontal_irradiance', xtags, [ 'Camera:HorizontalIrradiance' ], float) - self.set_attr_from_xmp_tag('irradiance_scale_to_si', tags, [ + self.set_attr_from_xmp_tag('irradiance_scale_to_si', xtags, [ 'Camera:IrradianceScaleToSIUnits' ], float) - self.set_attr_from_xmp_tag('sun_sensor', tags, [ + self.set_attr_from_xmp_tag('sun_sensor', xtags, [ 'Camera:SunSensor', ], float) - self.set_attr_from_xmp_tag('spectral_irradiance', tags, [ + self.set_attr_from_xmp_tag('spectral_irradiance', xtags, [ 'Camera:SpectralIrradiance', 'Camera:Irradiance', ], float) - self.set_attr_from_xmp_tag('capture_uuid', tags, [ + self.set_attr_from_xmp_tag('capture_uuid', xtags, [ '@drone-dji:CaptureUUID', # DJI '@Camera:ImageUniqueID', # sentera 6x ]) + # Camera make / model for some cameras is stored in the XMP + if self.camera_make == '': + self.set_attr_from_xmp_tag('camera_make', xtags, [ + '@tiff:Make' + ]) + if self.camera_model == '': + self.set_attr_from_xmp_tag('camera_model', xtags, [ + '@tiff:Model' + ]) + # DJI GPS tags - self.set_attr_from_xmp_tag('longitude', tags, [ + self.set_attr_from_xmp_tag('longitude', xtags, [ '@drone-dji:Longitude' ], float) - self.set_attr_from_xmp_tag('latitude', tags, [ + self.set_attr_from_xmp_tag('latitude', xtags, [ '@drone-dji:Latitude' ], float) - self.set_attr_from_xmp_tag('altitude', tags, [ + self.set_attr_from_xmp_tag('altitude', xtags, [ '@drone-dji:AbsoluteAltitude' ], float) # Phantom 4 RTK - if '@drone-dji:RtkStdLon' in tags: - y = float(self.get_xmp_tag(tags, '@drone-dji:RtkStdLon')) - x = float(self.get_xmp_tag(tags, '@drone-dji:RtkStdLat')) + if '@drone-dji:RtkStdLon' in xtags: + y = float(self.get_xmp_tag(xtags, '@drone-dji:RtkStdLon')) + x = float(self.get_xmp_tag(xtags, '@drone-dji:RtkStdLat')) self.gps_xy_stddev = max(x, y) - if '@drone-dji:RtkStdHgt' in tags: - self.gps_z_stddev = float(self.get_xmp_tag(tags, '@drone-dji:RtkStdHgt')) + if '@drone-dji:RtkStdHgt' in xtags: + self.gps_z_stddev = float(self.get_xmp_tag(xtags, '@drone-dji:RtkStdHgt')) else: - self.set_attr_from_xmp_tag('gps_xy_stddev', tags, [ + self.set_attr_from_xmp_tag('gps_xy_stddev', xtags, [ '@Camera:GPSXYAccuracy', 'GPSXYAccuracy' ], float) - self.set_attr_from_xmp_tag('gps_z_stddev', tags, [ + self.set_attr_from_xmp_tag('gps_z_stddev', xtags, [ '@Camera:GPSZAccuracy', 'GPSZAccuracy' ], float) - if 'DLS:Yaw' in tags: - self.set_attr_from_xmp_tag('dls_yaw', tags, ['DLS:Yaw'], float) - self.set_attr_from_xmp_tag('dls_pitch', tags, ['DLS:Pitch'], float) - self.set_attr_from_xmp_tag('dls_roll', tags, ['DLS:Roll'], float) + if 'DLS:Yaw' in xtags: + self.set_attr_from_xmp_tag('dls_yaw', xtags, ['DLS:Yaw'], float) + self.set_attr_from_xmp_tag('dls_pitch', xtags, ['DLS:Pitch'], float) + self.set_attr_from_xmp_tag('dls_roll', xtags, ['DLS:Roll'], float) - camera_projection = self.get_xmp_tag(tags, ['@Camera:ModelType', 'Camera:ModelType']) + camera_projection = self.get_xmp_tag(xtags, ['@Camera:ModelType', 'Camera:ModelType']) if camera_projection is not None: camera_projection = camera_projection.lower() if camera_projection in projections: self.camera_projection = camera_projection # OPK - self.set_attr_from_xmp_tag('yaw', tags, ['@drone-dji:FlightYawDegree', '@Camera:Yaw', 'Camera:Yaw'], float) - self.set_attr_from_xmp_tag('pitch', tags, ['@drone-dji:GimbalPitchDegree', '@Camera:Pitch', 'Camera:Pitch'], float) - self.set_attr_from_xmp_tag('roll', tags, ['@drone-dji:GimbalRollDegree', '@Camera:Roll', 'Camera:Roll'], float) + self.set_attr_from_xmp_tag('yaw', xtags, ['@drone-dji:FlightYawDegree', '@Camera:Yaw', 'Camera:Yaw'], float) + self.set_attr_from_xmp_tag('pitch', xtags, ['@drone-dji:GimbalPitchDegree', '@Camera:Pitch', 'Camera:Pitch'], float) + self.set_attr_from_xmp_tag('roll', xtags, ['@drone-dji:GimbalRollDegree', '@Camera:Roll', 'Camera:Roll'], float) # Normalize YPR conventions (assuming nadir camera) # Yaw: 0 --> top of image points north @@ -361,20 +369,27 @@ class ODM_Photo: except Exception as e: log.ODM_WARNING("Cannot read XMP tags for %s: %s" % (_path_file, str(e))) - # self.set_attr_from_xmp_tag('center_wavelength', tags, [ + # self.set_attr_from_xmp_tag('center_wavelength', xtags, [ # 'Camera:CentralWavelength' # ], float) - # self.set_attr_from_xmp_tag('bandwidth', tags, [ + # self.set_attr_from_xmp_tag('bandwidth', xtags, [ # 'Camera:WavelengthFWHM' # ], float) # Sanitize band name since we use it in folder paths self.band_name = re.sub('[^A-Za-z0-9]+', '', self.band_name) + self.compute_focal(tags, xtags) self.compute_opk() - def extract_focal(self, make, model, tags): + def compute_focal(self, tags, xtags): + try: + self.focal_ratio = self.extract_focal(self.camera_make, self.camera_model, tags, xtags) + except (IndexError, ValueError) as e: + log.ODM_WARNING("Cannot extract focal ratio for %s: %s" % (self.filename, str(e))) + + def extract_focal(self, make, model, tags, xtags): if make != "unknown": # remove duplicate 'make' information in 'model' model = model.replace(make, "") @@ -400,6 +415,11 @@ class ODM_Photo: focal_35 = self.float_value(tags["EXIF FocalLengthIn35mmFilm"]) if "EXIF FocalLength" in tags: focal = self.float_value(tags["EXIF FocalLength"]) + if focal is None and "@aux:Lens" in xtags: + lens = self.get_xmp_tag(xtags, ["@aux:Lens"]) + matches = re.search('([\d\.]+)mm', str(lens)) + if matches: + focal = float(matches.group(1)) if focal_35 is not None and focal_35 > 0: focal_ratio = focal_35 / 36.0 # 35mm film produces 36x24mm pictures. diff --git a/requirements.txt b/requirements.txt index fb1666a2..13b16223 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ lxml==4.6.1 matplotlib==3.3.3 networkx==2.5 numpy==1.21.1 -Pillow==8.0.1 +Pillow==8.3.2 vmem==1.0.1 pyodm==1.5.8 pyproj==3.0.0.post1 diff --git a/win32env.bat b/win32env.bat index 35f3339d..e363696e 100644 --- a/win32env.bat +++ b/win32env.bat @@ -13,7 +13,7 @@ set GDALBASE=%ODMBASE%venv\Lib\site-packages\osgeo set OSFMBASE=%ODMBASE%SuperBuild\install\bin\opensfm\bin set SBBIN=%ODMBASE%SuperBuild\install\bin -set PATH="%GDALBASE%";"%SBBIN%";"%OSFMBASE%" +set PATH=%GDALBASE%;%SBBIN%;%OSFMBASE% set PROJ_LIB=%GDALBASE%\data\proj set VIRTUAL_ENV=%ODMBASE%venv @@ -48,4 +48,4 @@ set PATH=%VIRTUAL_ENV%\Scripts;%PATH% if defined _OLD_CODEPAGE ( "%SystemRoot%\System32\chcp.com" %_OLD_CODEPAGE% > nul set _OLD_CODEPAGE= -) \ No newline at end of file +)