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:
+1
-1
@@ -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 |
+62
-7
@@ -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,9 +1114,20 @@ 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 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
value = std::string(szAttribute);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const char* szAbout(document->Attribute("rdf:about"));
|
const char* szAbout(document->Attribute("rdf:about"));
|
||||||
if (0 == strcasecmp(Make.c_str(), "DJI") || (szAbout != NULL && 0 == strcasecmp(szAbout, "DJI Meta Data"))) {
|
if (0 == strcasecmp(Make.c_str(), "DJI") || (szAbout != NULL && 0 == strcasecmp(szAbout, "DJI Meta Data"))) {
|
||||||
@@ -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
@@ -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.
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user