1
0
mirror of https://github.com/cdcseacave/TinyEXIF.git synced 2026-07-21 19:23:01 +04:00

Added support for DJI distortion (#21)

This commit is contained in:
Paul Gafton
2025-10-09 11:45:16 +02:00
committed by GitHub
parent 79e124e1e1
commit e5d0e39a9b
6 changed files with 85 additions and 9 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.1) cmake_minimum_required(VERSION 3.10)
project(TinyEXIF) project(TinyEXIF)
include(GNUInstallDirs) include(GNUInstallDirs)
Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

+63 -8
View File
@@ -32,18 +32,18 @@
*/ */
#include "TinyEXIF.h" #include "TinyEXIF.h"
#include <cstddef>
#ifndef TINYEXIF_NO_XMP_SUPPORT
#include <tinyxml2.h>
#endif // TINYEXIF_NO_XMP_SUPPORT
#include <cstdint>
#include <cstdio> #include <cstdio>
#include <cmath> #include <cmath>
#include <cfloat> #include <cfloat>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
#include <sstream>
#ifndef TINYEXIF_NO_XMP_SUPPORT
#include <tinyxml2.h>
#endif // TINYEXIF_NO_XMP_SUPPORT
#ifdef _MSC_VER #ifdef _MSC_VER
namespace { namespace {
@@ -1114,8 +1114,19 @@ int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {
if (element == NULL || (szAttribute = element->GetText()) == NULL) if (element == NULL || (szAttribute = element->GetText()) == NULL)
return false; return false;
} }
value = strtoul(szAttribute, NULL, 0); return true; value = strtoul(szAttribute, NULL, 0);
return false; return true;
}
// same as previous function but with std::string
static bool Value(const tinyxml2::XMLElement* document, const char* name, std::string& value) {
const char* szAttribute = document->Attribute(name);
if (szAttribute == NULL) {
const tinyxml2::XMLElement* const element(document->FirstChildElement(name));
if (element == NULL || (szAttribute = element->GetText()) == NULL)
return false;
}
value = std::string(szAttribute);
return true;
} }
}; };
const char* szAbout(document->Attribute("rdf:about")); const char* szAbout(document->Attribute("rdf:about"));
@@ -1128,6 +1139,28 @@ int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {
ParseXMP::Value(document, "drone-dji:CalibratedFocalLength", Calibration.FocalLength); ParseXMP::Value(document, "drone-dji:CalibratedFocalLength", Calibration.FocalLength);
ParseXMP::Value(document, "drone-dji:CalibratedOpticalCenterX", Calibration.OpticalCenterX); ParseXMP::Value(document, "drone-dji:CalibratedOpticalCenterX", Calibration.OpticalCenterX);
ParseXMP::Value(document, "drone-dji:CalibratedOpticalCenterY", Calibration.OpticalCenterY); ParseXMP::Value(document, "drone-dji:CalibratedOpticalCenterY", Calibration.OpticalCenterY);
std::string dewarpData;
ParseXMP::Value(document, "drone-dji:DewarpFlag", Distortion.DewarpFlag);
ParseXMP::Value(document, "drone-dji:DewarpData", dewarpData);
std::vector<double> distortionParams;
size_t pos = dewarpData.find(';');
if (pos != std::string::npos) {
std::stringstream ss(dewarpData.substr(pos + 1));
std::string item;
while (std::getline(ss, item, ',')) {
distortionParams.push_back(std::stod(item));
}
}
// The DewarpData string has the following format:
// date;Fx,Fy,Cx,Cy,K1,K2,P1,P2,K3
// , where Fx, Fy are focal lengths in pixels, Cx, Cy are optical center offsets from the image center in pixels
if (distortionParams.size() == 9) {
Distortion.K1 = distortionParams[4];
Distortion.K2 = distortionParams[5];
Distortion.P1 = distortionParams[6];
Distortion.P2 = distortionParams[7];
Distortion.K3 = distortionParams[8];
}
} else } else
if (0 == strcasecmp(Make.c_str(), "senseFly") || 0 == strcasecmp(Make.c_str(), "Sentera")) { if (0 == strcasecmp(Make.c_str(), "senseFly") || 0 == strcasecmp(Make.c_str(), "Sentera")) {
ParseXMP::Value(document, "Camera:Roll", GeoLocation.RollDegree); ParseXMP::Value(document, "Camera:Roll", GeoLocation.RollDegree);
@@ -1165,6 +1198,17 @@ int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {
#endif // TINYEXIF_NO_XMP_SUPPORT #endif // TINYEXIF_NO_XMP_SUPPORT
bool EXIFInfo::Calibration_t::hasCalibration() const {
return FocalLength > 0.0 && OpticalCenterX > 0.0 && OpticalCenterY > 0.0;
}
bool EXIFInfo::Distortion_t::hasDewarpFlag() const {
return DewarpFlag != UINT32_MAX;
}
bool EXIFInfo::Distortion_t::hasDistortion() const {
return K1 != 0.0 || K2 != 0.0 || P1 != 0.0 || P2 != 0.0 || K3 != 0.0;
}
void EXIFInfo::Geolocation_t::parseCoords() { void EXIFInfo::Geolocation_t::parseCoords() {
// Convert GPS latitude // Convert GPS latitude
if (LatComponents.degrees != DBL_MAX || if (LatComponents.degrees != DBL_MAX ||
@@ -1210,6 +1254,9 @@ bool EXIFInfo::Geolocation_t::hasOrientation() const {
bool EXIFInfo::Geolocation_t::hasSpeed() const { bool EXIFInfo::Geolocation_t::hasSpeed() const {
return SpeedX != DBL_MAX && SpeedY != DBL_MAX && SpeedZ != DBL_MAX; return SpeedX != DBL_MAX && SpeedY != DBL_MAX && SpeedZ != DBL_MAX;
} }
bool EXIFInfo::Geolocation_t::hasAccuracy() const {
return AccuracyXY != 0 && AccuracyZ != 0;
}
bool EXIFInfo::GPano_t::hasPosePitchDegrees() const { bool EXIFInfo::GPano_t::hasPosePitchDegrees() const {
return PosePitchDegrees != DBL_MAX; return PosePitchDegrees != DBL_MAX;
@@ -1306,6 +1353,14 @@ void EXIFInfo::clear() {
GeoLocation.LonComponents.seconds = 0; GeoLocation.LonComponents.seconds = 0;
GeoLocation.LonComponents.direction = 0; GeoLocation.LonComponents.direction = 0;
// Distortion
Distortion.DewarpFlag = UINT32_MAX;
Distortion.K1 = 0;
Distortion.K2 = 0;
Distortion.P1 = 0;
Distortion.P2 = 0;
Distortion.K3 = 0;
// GPano // GPano
GPano.PosePitchDegrees = DBL_MAX; GPano.PosePitchDegrees = DBL_MAX;
GPano.PoseRollDegrees = DBL_MAX; GPano.PoseRollDegrees = DBL_MAX;
+15
View File
@@ -251,7 +251,21 @@ public:
double FocalLength; // Focal length (pixels) double FocalLength; // Focal length (pixels)
double OpticalCenterX; // Principal point X (pixels) double OpticalCenterX; // Principal point X (pixels)
double OpticalCenterY; // Principal point Y (pixels) double OpticalCenterY; // Principal point Y (pixels)
bool hasCalibration() const; // Return true if FocalLength, OpticalCenterX, OpticalCenterY are available (nonzero)
} Calibration; } Calibration;
struct TINYEXIF_LIB Distortion_t { // Lens distortion information
uint32_t DewarpFlag; // Dewarp flag - indicates whether undistortion has been applied to the image
// UINT32_MAX: flag missing from EXIF data
// 0: no dewarp (raw image) - the image is distorted, should also have coefficients
// 1: dewarp applied (undistorted image)
double K1;
double K2;
double P1;
double P2;
double K3;
bool hasDewarpFlag() const; // Return true if DewarpFlag is available
bool hasDistortion() const; // Return true if any of K1, K2, P1, P2, K3 are available
} Distortion;
struct TINYEXIF_LIB LensInfo_t { // Lens information struct TINYEXIF_LIB LensInfo_t { // Lens information
double FStopMin; // Min aperture (f-stop) double FStopMin; // Min aperture (f-stop)
double FStopMax; // Max aperture (f-stop) double FStopMax; // Max aperture (f-stop)
@@ -302,6 +316,7 @@ public:
bool hasRelativeAltitude()const;// Return true if (rel_alt) is available bool hasRelativeAltitude()const;// Return true if (rel_alt) is available
bool hasOrientation() const; // Return true if (roll,yaw,pitch) is available bool hasOrientation() const; // Return true if (roll,yaw,pitch) is available
bool hasSpeed() const; // Return true if (speedX,speedY,speedZ) is available bool hasSpeed() const; // Return true if (speedX,speedY,speedZ) is available
bool hasAccuracy() const; // Return true if (accuracyXY,accuracyZ) is available
} GeoLocation; } GeoLocation;
struct TINYEXIF_LIB GPano_t { // Spherical metadata. https://developers.google.com/streetview/spherical-metadata struct TINYEXIF_LIB GPano_t { // Spherical metadata. https://developers.google.com/streetview/spherical-metadata
double PosePitchDegrees; // Pitch, measured in degrees above the horizon, for the center in the image. Value must be >= -90 and <= 90. double PosePitchDegrees; // Pitch, measured in degrees above the horizon, for the center in the image. Value must be >= -90 and <= 90.
+6
View File
@@ -130,5 +130,11 @@ int main(int argc, const char** argv)
std::cout << "GPano.PosePitchDegrees " << imageEXIF.GPano.PosePitchDegrees << "\n"; std::cout << "GPano.PosePitchDegrees " << imageEXIF.GPano.PosePitchDegrees << "\n";
if (imageEXIF.GPano.hasPoseRollDegrees()) if (imageEXIF.GPano.hasPoseRollDegrees())
std::cout << "GPano.PoseRollDegrees " << imageEXIF.GPano.PoseRollDegrees << "\n"; std::cout << "GPano.PoseRollDegrees " << imageEXIF.GPano.PoseRollDegrees << "\n";
if (imageEXIF.Distortion.hasDewarpFlag())
std::cout << "Distortion.DewarpFlag " << imageEXIF.Distortion.DewarpFlag << "\n";
if (imageEXIF.Distortion.hasDistortion())
std::cout << "Distortion [K1 K2 P1 P2 K3] " << std::setprecision(6)
<< imageEXIF.Distortion.K1 << " " << imageEXIF.Distortion.K2 << " " << imageEXIF.Distortion.P1
<< " " << imageEXIF.Distortion.P2 << " " << imageEXIF.Distortion.K3 << "\n";
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }