diff --git a/.github/workflows/lint-test.yaml b/.github/workflows/lint-test.yaml index cb8c9c2..b6cff72 100644 --- a/.github/workflows/lint-test.yaml +++ b/.github/workflows/lint-test.yaml @@ -16,9 +16,9 @@ jobs: - name: Install Exiftool run: | - wget https://exiftool.org/Image-ExifTool-13.56.tar.gz - gzip -dc Image-ExifTool-13.56.tar.gz | tar -xf - - cd Image-ExifTool-13.56 + wget https://exiftool.org/Image-ExifTool-13.59.tar.gz + gzip -dc Image-ExifTool-13.59.tar.gz | tar -xf - + cd Image-ExifTool-13.59 perl Makefile.PL sudo make install cd .. diff --git a/cfg/dji.cfg b/cfg/dji.cfg new file mode 100644 index 0000000..cf3fd6f --- /dev/null +++ b/cfg/dji.cfg @@ -0,0 +1,168 @@ +#------------------------------------------------------------------------------ +# File: exiftool.cfg +# +# Description: This config file contains tag definitions needed to be able +# to write Pix4D and Sentera XMP-Camera tags +# +# Usage: exiftool -config exiftool.cfg -XMP-camera:TAG=VAL ... +# +# Requires: ExifTool version 7.00 or later +# +# References: 1) https://support.pix4d.com/hc/en-us/articles/360016450032-Specifications-of-xmpcamera-tags +#------------------------------------------------------------------------------ + +%Image::ExifTool::UserDefined = ( + 'Image::ExifTool::XMP::Main' => { + Camera => { + SubDirectory => { + TagTable => 'Image::ExifTool::UserDefined::Camera', + }, + }, + 'drone-dji' => { + SubDirectory => { + TagTable => 'Image::ExifTool::UserDefined::DJI', + }, + }, + }, +); + +%Image::ExifTool::UserDefined::Camera = ( + GROUPS => { 0 => 'XMP', 1 => 'XMP-Camera', 2 => 'Camera' }, + NAMESPACE => { 'Camera' => 'http://pix4d.com/camera/1.0/' }, + WRITABLE => 'string', + Yaw => { Writable => 'real' }, + Pitch => { Writable => 'real' }, + Roll => { Writable => 'real' }, + IMUSampleSize => { Writable => 'integer' }, + IMUTimeOffset => { Writable => 'integer' }, + LineReadoutTime => { Writable => 'integer' }, + IMUFrequency => { Writable => 'real' }, + PrincipalPoint => { }, + ModelType => { }, + PerspectiveFocalLength => { Writable => 'real' }, + PerspectiveDistortion => { }, + IMULinearVelocity => { }, + GPSXYAccuracy => { Writable => 'real' }, + GPSZAccuracy => { Writable => 'real' }, + RigName => { }, + RigCameraIndex => { Writable => 'integer' }, + IMUAngularVelocity => { + Binary => 1, + ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)', + ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)', + }, + # added 2020/04/02 (ref 1) + FisheyeAffineMatrix => { }, + FisheyeAffineSymmetric => { }, + FisheyePolynomial => { }, + RigRelatives => { }, + PerspectiveFocalLengthUnits => { }, + CentralWavelength => { List => 'Seq' }, + WavelengthFWHM => { List => 'Seq' }, + BlackCurrent => { List => 'Seq' }, + BandSensitivity => { List => 'Seq' }, + SunSensor => { List => 'Seq' }, + SunSensorExposureTime => { Writable => 'real' }, + SunSensorSensitivity => { List => 'Seq' }, + InvalidPixel => { List => 'Seq' }, + VignettingPolynomial => { List => 'Seq' }, + VignettingCenter => { List => 'Seq' }, + VignettingPolynomial2DName => { List => 'Seq' }, + VignettingPolynomial2D => { List => 'Seq' }, + ColorTransform => { List => 'Seq' }, + IsNormalized => { Writable => 'real' }, + Albedo => { List => 'Seq' }, + ReflectArea => { List => 'Seq' }, + CalibrationPicture => { Writable => 'integer' }, + GyroRate => { Writable => 'real' }, + IMUPitchAccuracy => { Writable => 'real' }, + IMURollAccuracy => { Writable => 'real' }, + IMUYawAccuracy => { Writable => 'real' }, + NominalCameraDistance => { Writable => 'real' }, + SunSensorYaw => { Writable => 'real' }, + SunSensorPitch => { Writable => 'real' }, + SunSensorRoll => { Writable => 'real' }, + SunSensorRelativeRotation => { Writable => 'real', List => 'Seq' }, + TransformAlpha => { List => 'Seq' }, + TransformBeta => { List => 'Seq' }, + TransformGamma => { List => 'Seq' }, + SensorBitDepth => { Writable => 'integer' }, + SensorTemperature => { Writable => 'real' }, + # (ref https://community.pix4d.com/t/camera-sun-irradiance-and-sun-angle-in-red-text/3290) + IrradianceRelativeRotation => { }, + Irradiance => { List => 'Seq' }, + IrradianceExposureTime => { Writable => 'real' }, + IrradianceGain => { Writable => 'real' }, + BandName => { List => 'Seq' }, + # Not official pix4d fields +); + +%Image::ExifTool::UserDefined::DJI = ( + GROUPS => { 0 => 'XMP', 1 => 'XMP-drone-dji', 2 => 'drone-dji' }, + NAMESPACE => { 'drone-dji' => 'http://www.dji.com/drone-dji/1.0/' }, + WRITABLE => 'string', + # Original GPS/flight tags from built-in DJI::XMP + AbsoluteAltitude => { Writable => 'real' }, + RelativeAltitude => { Writable => 'real' }, + GimbalRollDegree => { Writable => 'real' }, + GimbalYawDegree => { Writable => 'real' }, + GimbalPitchDegree => { Writable => 'real' }, + FlightRollDegree => { Writable => 'real' }, + FlightYawDegree => { Writable => 'real' }, + FlightPitchDegree => { Writable => 'real' }, + GpsLatitude => { Writable => 'real' }, + GpsLongtitude => { Writable => 'real' }, + GpsLongitude => { Writable => 'real' }, + FlightXSpeed => { Writable => 'real' }, + FlightYSpeed => { Writable => 'real' }, + FlightZSpeed => { Writable => 'real' }, + CamReverse => { }, + GimbalReverse => { }, + SelfData => { }, + CalibratedFocalLength => { Writable => 'real' }, + CalibratedOpticalCenterX => { Writable => 'real' }, + CalibratedOpticalCenterY => { Writable => 'real' }, + RtkFlag => { }, + RtkStdLon => { Writable => 'real' }, + RtkStdLat => { Writable => 'real' }, + RtkStdHgt => { Writable => 'real' }, + DewarpData => { }, + DewarpFlag => { }, + Latitude => { Writable => 'real' }, + Longitude => { Writable => 'real' }, + # Multispectral / M3M tags + ImageSource => { }, + GpsStatus => { }, + AltitudeType => { }, + RtkDiffAge => { Writable => 'real' }, + NTRIPMountPoint => { }, + NTRIPPort => { Writable => 'integer' }, + NTRIPHost => { }, + SurveryingMode => { Writable => 'integer' }, + UTCAtExposure => { }, + ShutterType => { }, + CameraSerialNumber => { }, + DroneModel => { }, + DroneSerialNumber => { }, + CaptureUUID => { }, + RelativeOpticalCenterX => { Writable => 'real' }, + RelativeOpticalCenterY => { Writable => 'real' }, + DewarpHMatrix => { List => 'Seq' }, + CalibratedHMatrix => { List => 'Seq' }, + VignettingFlag => { }, + VignettingData => { List => 'Seq' }, + LSType => { }, + LSstatus => { }, + Packageidx => { }, + Cfgcnt => { }, + RawData => { }, + BandFreq => { List => 'Seq' }, + Irradiance => { List => 'Seq' }, + SensorGain => { }, + SensorGainAdjustment => { }, + SensorIndex => { }, + BlackLevel => { }, + DroneID => { }, +); + +1; #end diff --git a/correct_images_dir.spec b/correct_images_dir.spec index ec08526..88804d7 100644 --- a/correct_images_dir.spec +++ b/correct_images_dir.spec @@ -1,16 +1,18 @@ # -*- mode: python ; coding: utf-8 -*- +import importlib.metadata from PyInstaller.utils.hooks import copy_metadata block_cipher = None metadata_datas = copy_metadata('imageio') + copy_metadata('imgcorrect') +version = importlib.metadata.version('imgcorrect') a = Analysis(['scripts\\correct_images.py'], pathex=['.'], binaries=[], - datas=[('exiftool/exiftool.exe', '.'), ('cfg/exiftool.cfg', 'cfg'), ('cfg/reg_config.ini', 'cfg')] + metadata_datas, + datas=[('exiftool/exiftool.exe', '.'), ('cfg/exiftool.cfg', 'cfg'), ('cfg/dji.cfg', 'cfg'), ('cfg/reg_config.ini', 'cfg')] + metadata_datas, hiddenimports=['pkg_resources.py2_warn'], hookspath=[], runtime_hooks=[], @@ -27,7 +29,7 @@ exe = EXE( a.scripts, [], exclude_binaries=True, - name='ImageryCorrector', + name=f'ImageryCorrector_{version}', debug=False, bootloader_ignore_signals=False, strip=False, @@ -42,5 +44,5 @@ coll = COLLECT( strip=False, upx=False, upx_exclude=[], - name='ImageryCorrector', + name=f'ImageryCorrector_{version}', ) diff --git a/correct_images_gui_onefile.spec b/correct_images_gui_onefile.spec index 0c00edf..31595e4 100644 --- a/correct_images_gui_onefile.spec +++ b/correct_images_gui_onefile.spec @@ -1,16 +1,19 @@ # -*- mode: python ; coding: utf-8 -*- +import importlib.metadata from PyInstaller.utils.hooks import copy_metadata block_cipher = None metadata_datas = copy_metadata('imageio') + copy_metadata('imgcorrect') +version = importlib.metadata.version('imgcorrect') + a = Analysis(['scripts\\correct_images_gui.py'], pathex=['.'], binaries=[], - datas=[('exiftool/exiftool.exe', '.'), ('cfg/exiftool.cfg', 'cfg'), ('cfg/reg_config.ini', 'cfg'), ('sentera_radiometric_corrections_icon.ico', '.')] + metadata_datas, + datas=[('exiftool/exiftool.exe', '.'), ('cfg/exiftool.cfg', 'cfg'), ('cfg/dji.cfg', 'cfg'), ('cfg/reg_config.ini', 'cfg'), ('sentera_radiometric_corrections_icon.ico', '.')] + metadata_datas, hiddenimports=['pkg_resources.py2_warn'], hookspath=[], runtime_hooks=[], @@ -27,7 +30,7 @@ exe = EXE(pyz, a.zipfiles, a.datas, [], - name='SenteraRadiometricCorrectionsGUI', + name=f'SenteraRadiometricCorrectionsGUI_{version}', icon='sentera_radiometric_corrections_icon.ico', debug=False, bootloader_ignore_signals=False, diff --git a/correct_images_onefile.spec b/correct_images_onefile.spec index 6fc0b9c..15747d3 100644 --- a/correct_images_onefile.spec +++ b/correct_images_onefile.spec @@ -1,16 +1,18 @@ # -*- mode: python ; coding: utf-8 -*- +import importlib.metadata from PyInstaller.utils.hooks import copy_metadata block_cipher = None metadata_datas = copy_metadata('imageio') + copy_metadata('imgcorrect') +version = importlib.metadata.version('imgcorrect') a = Analysis(['scripts\\correct_images.py'], pathex=['.'], binaries=[], - datas=[('exiftool/exiftool.exe', '.'), ('cfg/exiftool.cfg', 'cfg'), ('cfg/reg_config.ini', 'cfg')] + metadata_datas, + datas=[('exiftool/exiftool.exe', '.'), ('cfg/exiftool.cfg', 'cfg'), ('cfg/dji.cfg', 'cfg'), ('cfg/reg_config.ini', 'cfg')] + metadata_datas, hiddenimports=['pkg_resources.py2_warn'], hookspath=[], runtime_hooks=[], @@ -27,7 +29,7 @@ exe = EXE(pyz, a.zipfiles, a.datas, [], - name='ImageryCorrector', + name=f'ImageryCorrector_{version}', debug=False, bootloader_ignore_signals=False, strip=False, diff --git a/get_corrections_dir.spec b/get_corrections_dir.spec index 35f4a75..130a720 100644 --- a/get_corrections_dir.spec +++ b/get_corrections_dir.spec @@ -1,16 +1,18 @@ # -*- mode: python ; coding: utf-8 -*- +import importlib.metadata from PyInstaller.utils.hooks import copy_metadata block_cipher = None metadata_datas = copy_metadata('imageio') + copy_metadata('imgcorrect') +version = importlib.metadata.version('imgcorrect') a = Analysis(['scripts\\get_corrections.py'], pathex=['.'], binaries=[], - datas=[('exiftool/exiftool.exe', '.'), ('cfg/exiftool.cfg', 'cfg'), ('cfg/reg_config.ini', 'cfg')] + metadata_datas, + datas= metadata_datas, hiddenimports=['pkg_resources.py2_warn'], hookspath=[], runtime_hooks=[], @@ -26,7 +28,7 @@ exe = EXE( a.scripts, [], exclude_binaries=True, - name='GetCorrectionsCsv', + name=f'GetCorrectionsCsv_{version}', debug=False, bootloader_ignore_signals=False, strip=False, @@ -41,5 +43,5 @@ coll = COLLECT( strip=False, upx=False, upx_exclude=[], - name='GetCorrectionsCsv', + name=f'GetCorrectionsCsv_{version}', ) diff --git a/get_corrections_onefile.spec b/get_corrections_onefile.spec index 144bea0..9c1b179 100644 --- a/get_corrections_onefile.spec +++ b/get_corrections_onefile.spec @@ -1,16 +1,18 @@ # -*- mode: python ; coding: utf-8 -*- +import importlib.metadata from PyInstaller.utils.hooks import copy_metadata block_cipher = None metadata_datas = copy_metadata('imageio') + copy_metadata('imgcorrect') +version = importlib.metadata.version('imgcorrect') a = Analysis(['scripts\\get_corrections.py'], pathex=['.'], binaries=[], - datas=[('exiftool/exiftool.exe', '.'), ('cfg/exiftool.cfg', 'cfg'), ('cfg/reg_config.ini', 'cfg')] + metadata_datas, + datas= metadata_datas, hiddenimports=['pkg_resources.py2_warn'], hookspath=[], runtime_hooks=[], @@ -27,7 +29,7 @@ exe = EXE(pyz, a.zipfiles, a.datas, [], - name='GetCorrectionsCsv', + name=f'GetCorrectionsCsv_{version}', debug=False, bootloader_ignore_signals=False, strip=False, diff --git a/imgcorrect/metadata.py b/imgcorrect/metadata.py index ac19e21..8025190 100644 --- a/imgcorrect/metadata.py +++ b/imgcorrect/metadata.py @@ -10,10 +10,17 @@ def copy_exif(image_df_row, exiftool_path): """Copy image metadata with necessary changes from original image to corrected image.""" + parser = MetadataParser(image_df_row.image_path) + command = [ exiftool_path, - "-config", - "cfg/exiftool.cfg", + ] + make = parser.make() + if make == "DJI": + command += ["-config", "cfg/dji.cfg"] + elif make == "Sentera": + command += ["-config", "cfg/exiftool.cfg"] + command += [ "-overwrite_original", "-TagsFromFile", image_df_row.image_path, @@ -25,7 +32,6 @@ def copy_exif(image_df_row, exiftool_path): "-xmp-Camera:BlackCurrent=0", ] if image_df_row.reduce_xmp: - parser = MetadataParser(image_df_row.image_path) cent_arr, fwhm_arr = parser.wavelength_data() band_arr = parser.bandnames() i = int(image_df_row.XMP_index) diff --git a/pyproject.toml b/pyproject.toml index a68c43c..5d263ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "imgcorrect" -version = "2.1.2" +version = "2.1.3" description = "Library to perform various corrections on imagery from supported sensors" authors = ["Samuel Williams ", "Joseph Franck "]