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)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
+63
-8
@@ -32,18 +32,18 @@
|
||||
*/
|
||||
|
||||
#include "TinyEXIF.h"
|
||||
|
||||
#ifndef TINYEXIF_NO_XMP_SUPPORT
|
||||
#include <tinyxml2.h>
|
||||
#endif // TINYEXIF_NO_XMP_SUPPORT
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#ifndef TINYEXIF_NO_XMP_SUPPORT
|
||||
#include <tinyxml2.h>
|
||||
#endif // TINYEXIF_NO_XMP_SUPPORT
|
||||
|
||||
#ifdef _MSC_VER
|
||||
namespace {
|
||||
@@ -1114,8 +1114,19 @@ int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {
|
||||
if (element == NULL || (szAttribute = element->GetText()) == NULL)
|
||||
return false;
|
||||
}
|
||||
value = strtoul(szAttribute, NULL, 0); return true;
|
||||
return false;
|
||||
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;
|
||||
}
|
||||
value = std::string(szAttribute);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
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:CalibratedOpticalCenterX", Calibration.OpticalCenterX);
|
||||
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
|
||||
if (0 == strcasecmp(Make.c_str(), "senseFly") || 0 == strcasecmp(Make.c_str(), "Sentera")) {
|
||||
ParseXMP::Value(document, "Camera:Roll", GeoLocation.RollDegree);
|
||||
@@ -1165,6 +1198,17 @@ int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {
|
||||
|
||||
#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() {
|
||||
// Convert GPS latitude
|
||||
if (LatComponents.degrees != DBL_MAX ||
|
||||
@@ -1210,6 +1254,9 @@ bool EXIFInfo::Geolocation_t::hasOrientation() const {
|
||||
bool EXIFInfo::Geolocation_t::hasSpeed() const {
|
||||
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 {
|
||||
return PosePitchDegrees != DBL_MAX;
|
||||
@@ -1306,6 +1353,14 @@ void EXIFInfo::clear() {
|
||||
GeoLocation.LonComponents.seconds = 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.PosePitchDegrees = DBL_MAX;
|
||||
GPano.PoseRollDegrees = DBL_MAX;
|
||||
|
||||
+15
@@ -251,7 +251,21 @@ public:
|
||||
double FocalLength; // Focal length (pixels)
|
||||
double OpticalCenterX; // Principal point X (pixels)
|
||||
double OpticalCenterY; // Principal point Y (pixels)
|
||||
bool hasCalibration() const; // Return true if FocalLength, OpticalCenterX, OpticalCenterY are available (nonzero)
|
||||
} 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
|
||||
double FStopMin; // Min 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 hasOrientation() const; // Return true if (roll,yaw,pitch) is available
|
||||
bool hasSpeed() const; // Return true if (speedX,speedY,speedZ) is available
|
||||
bool hasAccuracy() const; // Return true if (accuracyXY,accuracyZ) is available
|
||||
} GeoLocation;
|
||||
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.
|
||||
|
||||
@@ -130,5 +130,11 @@ int main(int argc, const char** argv)
|
||||
std::cout << "GPano.PosePitchDegrees " << imageEXIF.GPano.PosePitchDegrees << "\n";
|
||||
if (imageEXIF.GPano.hasPoseRollDegrees())
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user