QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GeoTagController.h
Go to the documentation of this file.
1#pragma once
2
3#include "GeoTagData.h"
4#include "GeoTagImageModel.h"
5
6#include <QtCore/QElapsedTimer>
7#include <QtCore/QFileInfo>
8#include <QtCore/QFileInfoList>
9#include <QtCore/QFutureWatcher>
10#include <QtCore/QHash>
11#include <QtCore/QLoggingCategory>
12#include <QtCore/QMap>
13#include <QtCore/QMutex>
14#include <QtCore/QObject>
15#include <QtCore/QString>
16#include <QtPositioning/QGeoCoordinate>
17#include <QtQmlIntegration/QtQmlIntegration>
18
19#include <atomic>
20
21Q_DECLARE_LOGGING_CATEGORY(GeoTagControllerLog)
22
23
25 QList<int> imageIndices;
26 QList<int> triggerIndices;
27 QList<int> unmatchedImages;
28 int skippedTriggers = 0;
29};
30
32
39CalibrationResult calibrate(const QList<qint64> &imageTimestamps,
40 const QList<GeoTagData> &triggers,
41 qint64 timeOffsetSecs,
42 qint64 toleranceSecs);
43
44} // namespace GeoTagCalibrator
45
48class GeoTagController : public QObject
49{
50 Q_OBJECT
51 QML_ELEMENT
52
53 Q_PROPERTY(QString logFile READ logFile WRITE setLogFile NOTIFY logFileChanged)
54 Q_PROPERTY(QString imageDirectory READ imageDirectory WRITE setImageDirectory NOTIFY imageDirectoryChanged)
55 Q_PROPERTY(QString saveDirectory READ saveDirectory WRITE setSaveDirectory NOTIFY saveDirectoryChanged)
56 Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged)
57 Q_PROPERTY(double progress READ progress NOTIFY progressChanged)
58 Q_PROPERTY(bool inProgress READ inProgress NOTIFY inProgressChanged)
59 Q_PROPERTY(int taggedCount READ taggedCount NOTIFY taggingCompleteChanged)
60 Q_PROPERTY(int skippedCount READ skippedCount NOTIFY taggingCompleteChanged)
61 Q_PROPERTY(int failedCount READ failedCount NOTIFY taggingCompleteChanged)
62 Q_PROPERTY(double timeOffsetSecs READ timeOffsetSecs WRITE setTimeOffsetSecs NOTIFY timeOffsetSecsChanged)
63 Q_PROPERTY(double toleranceSecs READ toleranceSecs WRITE setToleranceSecs NOTIFY toleranceSecsChanged)
64 Q_PROPERTY(bool previewMode READ previewMode WRITE setPreviewMode NOTIFY previewModeChanged)
65 Q_PROPERTY(bool recursiveScan READ recursiveScan WRITE setRecursiveScan NOTIFY recursiveScanChanged)
66 Q_PROPERTY(GeoTagImageModel* imageModel READ imageModel CONSTANT)
67
68public:
69 explicit GeoTagController(QObject *parent = nullptr);
70 ~GeoTagController() override;
71
72 Q_INVOKABLE void startTagging();
73 Q_INVOKABLE void cancelTagging();
74
75 QString logFile() const { return _logFile; }
76 QString imageDirectory() const { return _imageDirectory; }
77 QString saveDirectory() const { return _saveDirectory; }
78 double progress() const { return _progress; }
79 bool inProgress() const { return _stage != Stage::Idle; }
80 QString errorMessage() const { return _errorMessage; }
81 int taggedCount() const { return _taggedCount; }
82 int skippedCount() const { return _skippedCount; }
83 int failedCount() const { return _failedCount; }
84 double timeOffsetSecs() const { return _timeOffsetSecs; }
85 double toleranceSecs() const { return _toleranceSecs; }
86 bool previewMode() const { return _previewMode; }
87 bool recursiveScan() const { return _recursiveScan; }
88 GeoTagImageModel* imageModel() const { return _imageModel; }
89
90 void setLogFile(const QString &file);
91 void setImageDirectory(const QString &dir);
92 void setSaveDirectory(const QString &dir);
93 void setTimeOffsetSecs(double offset);
94 void setToleranceSecs(double tolerance);
95 void setPreviewMode(bool preview);
96 void setRecursiveScan(bool recursive);
97
98signals:
99 void logFileChanged(const QString &logFile);
100 void imageDirectoryChanged(const QString &imageDirectory);
101 void saveDirectoryChanged(const QString &saveDirectory);
102 void progressChanged(double progress);
104 void errorMessageChanged(const QString &errorMessage);
106 void timeOffsetSecsChanged(double timeOffsetSecs);
107 void toleranceSecsChanged(double toleranceSecs);
108 void previewModeChanged(bool previewMode);
109 void recursiveScanChanged(bool recursiveScan);
110
111private:
112 // Processing stages for async state machine
113 enum class Stage {
114 Idle,
115 LoadingImages,
116 ParsingExif,
117 ParsingLogs,
118 Calibrating,
119 TaggingImages,
120 Finished
121 };
122
123 static const char* stageName(Stage stage);
124
125 struct ExifResult {
126 qint64 timestamp = 0;
127 QString errorMessage;
128 bool success = false;
129 };
130
131 struct TagResult {
132 int imageIndex = -1;
133 QString fileName;
134 QString errorMessage;
135 QGeoCoordinate coordinate;
136 bool success = false;
137 };
138
139 struct TagTask {
140 int imageIndex = -1;
141 QFileInfo imageInfo;
142 GeoTagData geoTag;
143 QString outputDir;
144 bool previewMode = false;
145 };
146
147 // State machine control
148 void _setErrorMessage(const QString &errorMsg);
149 void _setProgress(double progress);
150 void _transitionTo(Stage stage);
151 void _finishWithError(const QString &errorMsg);
152 void _finishSuccess();
153
154 // Stage implementations
155 void _startLoadImages();
156 void _startParseExif();
157 void _startParseLogs();
158 void _startCalibrate();
159 void _startTagImages();
160
161 // Async stage handlers (slots for QFutureWatcher signals)
162 void _onExifProgress(int value);
163 void _onExifFinished();
164 void _onTagProgress(int value);
165 void _onTagFinished();
166
167 // Synchronous helpers (called from stage implementations)
168 bool _loadImages(QString &errorMsg);
169 bool _parseLogs(QString &errorMsg);
170 bool _calibrate(QString &errorMsg);
171 bool _validateOutputDirectory(const QString &outputDir, QString &errorMsg);
172 QList<TagTask> _buildTagTasks(const QString &outputDir, bool preview, QString &errorMsg);
173 qint64 _estimateOutputSize() const;
174
175 ExifResult _parseExifForImage(const QFileInfo &imageInfo);
176 TagResult _tagImage(const TagTask &task);
177
178 // Image buffer cache (thread-safe)
179 QByteArray _readImageCached(const QString &path, QString *errorString = nullptr);
180 void _evictUnmatchedImages();
181 void _clearImageCache();
182
183 // QML properties
184 QString _logFile;
185 QString _imageDirectory;
186 QString _saveDirectory;
187 QString _errorMessage;
188 double _progress = 0.;
189 int _taggedCount = 0;
190 int _skippedCount = 0;
191 int _failedCount = 0;
192 double _timeOffsetSecs = 0.0;
193 double _toleranceSecs = 2.0;
194 bool _previewMode = false;
195 bool _recursiveScan = false;
196
197 // Processing state
198 struct ProcessingState {
199 QFileInfoList imageList;
200 QList<qint64> imageTimestamps;
201 QList<GeoTagData> triggerList;
202 QList<int> imageIndices;
203 QList<int> triggerIndices;
204 int skippedCount = 0;
205 int failedCount = 0;
206
207 void clear() {
208 imageList.clear();
209 imageTimestamps.clear();
210 triggerList.clear();
211 imageIndices.clear();
212 triggerIndices.clear();
213 skippedCount = 0;
214 failedCount = 0;
215 }
216 };
217
218 // Async state machine
219 Stage _stage = Stage::Idle;
220 std::atomic<bool> _cancel{false};
221 QElapsedTimer _totalTimer;
222 QElapsedTimer _stageTimer;
223
224 // Async watchers for parallel stages
225 QFutureWatcher<ExifResult> _exifWatcher;
226 QFutureWatcher<TagResult> _tagWatcher;
227
228 ProcessingState _state;
229
230 // Image model for QML display
231 GeoTagImageModel *_imageModel = nullptr;
232
233 // Image buffer cache to avoid reading files twice
234 mutable QMutex _bufferMutex;
235 QHash<QString, QByteArray> _imageBuffers;
236
237 // Progress calculation constants
238 static constexpr double kLoadImagesEnd = 20.0;
239 static constexpr double kParseExifEnd = 40.0;
240 static constexpr double kParseLogsEnd = 60.0;
241 static constexpr double kCalibrateEnd = 80.0;
242 static constexpr double kTagImagesEnd = 100.0;
243};
Q_DECLARE_LOGGING_CATEGORY(AndroidSerialLog)
QString errorString
void recursiveScanChanged(bool recursiveScan)
void timeOffsetSecsChanged(double timeOffsetSecs)
void previewModeChanged(bool previewMode)
void saveDirectoryChanged(const QString &saveDirectory)
void imageDirectoryChanged(const QString &imageDirectory)
void toleranceSecsChanged(double toleranceSecs)
void progressChanged(double progress)
void logFileChanged(const QString &logFile)
void errorMessageChanged(const QString &errorMessage)
void taggingCompleteChanged()
void inProgressChanged()
Model for displaying geotagging image status in QML.
CalibrationResult calibrate(const QList< qint64 > &imageTimestamps, const QList< GeoTagData > &triggers, qint64 timeOffsetSecs, qint64 toleranceSecs)
QString errorMessage(const QNetworkReply *reply)
Result of timestamp-based calibration/matching.
QList< int > imageIndices
Matched image indices (parallel with triggerIndices)
QList< int > triggerIndices
Matched trigger indices (parallel with imageIndices)
QList< int > unmatchedImages
Image indices with no matching trigger.