geopic-tag-reader 1.1.0__tar.gz → 1.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/CHANGELOG.md +8 -1
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/PKG-INFO +1 -1
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/docs/reader.md +24 -18
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/geopic_tag_reader/__init__.py +1 -1
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/geopic_tag_reader/main.py +2 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/geopic_tag_reader/reader.py +41 -2
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/test_reader.py +10 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/.gitignore +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/.gitlab-ci.yml +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/.pre-commit-config.yaml +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/CODE_OF_CONDUCT.md +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/LICENSE +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/Makefile +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/README.md +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/docs/.pages +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/docs/API_USAGE.md +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/docs/CLI_USAGE.md +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/docs/Develop.md +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/docs/Install.md +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/docs/camera.md +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/docs/model.md +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/docs/writer.md +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/geopic_tag_reader/camera.py +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/geopic_tag_reader/model.py +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/geopic_tag_reader/py.typed +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/geopic_tag_reader/writer.py +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/pyproject.toml +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/pytest.ini +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/__init__.py +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/conftest.py +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/1.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/IMG_20210720_144918.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/IMG_20210720_161352.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/a1.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/b1.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/broken_makernotes.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/c1.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/charset.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/cropped.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/d1.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/datetime_ms_float.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/datetime_offset.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/e1.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/flat.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/gopromax_flat.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/gps_date_slash.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/gps_date_time_stamp.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/img_Ricoh_Theta.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/img_V4MPack.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/img_categorisee.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/img_datetimeoriginal.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/img_gps_date_string.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/img_gps_datestamp.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/img_gps_sotm.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/img_invalid_gps_date.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/img_without_coord.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/img_without_dt.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/img_without_exif_tags.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/insta360_date.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/int_long_tag.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/out_of_bounds_lat.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/out_of_bounds_lon.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/pic_with_float_lat.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/ricoh_theta_no_projection.jpg +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/test_main.py +0 -0
- {geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/test_writer.py +0 -0
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.1.1] - 2024-04-26
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Reader now handles pitch & roll values from various EXIF/XMP tags.
|
|
15
|
+
|
|
10
16
|
## [1.1.0] - 2024-04-17
|
|
11
17
|
|
|
12
18
|
### Changed
|
|
@@ -160,7 +166,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
160
166
|
|
|
161
167
|
- EXIF tag reading methods extracted from [GeoVisio API](https://gitlab.com/geovisio/api)
|
|
162
168
|
|
|
163
|
-
[Unreleased]: https://gitlab.com/geovisio/geo-picture-tag-reader/-/compare/1.1.
|
|
169
|
+
[Unreleased]: https://gitlab.com/geovisio/geo-picture-tag-reader/-/compare/1.1.1...main
|
|
170
|
+
[1.1.1]: https://gitlab.com/geovisio/geo-picture-tag-reader/-/compare/1.1.0...1.1.1
|
|
164
171
|
[1.1.0]: https://gitlab.com/geovisio/geo-picture-tag-reader/-/compare/1.0.6...1.1.0
|
|
165
172
|
[1.0.6]: https://gitlab.com/geovisio/geo-picture-tag-reader/-/compare/1.0.5...1.0.6
|
|
166
173
|
[1.0.5]: https://gitlab.com/geovisio/geo-picture-tag-reader/-/compare/1.0.4...1.0.5
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
13
|
+
<a href="../geopic_tag_reader/reader.py#L124"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
14
14
|
|
|
15
15
|
## <kbd>function</kbd> `readPictureMetadata`
|
|
16
16
|
|
|
@@ -35,7 +35,7 @@ Extracts metadata from picture file
|
|
|
35
35
|
|
|
36
36
|
---
|
|
37
37
|
|
|
38
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
38
|
+
<a href="../geopic_tag_reader/reader.py#L394"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
39
39
|
|
|
40
40
|
## <kbd>function</kbd> `decodeMakeModel`
|
|
41
41
|
|
|
@@ -48,7 +48,7 @@ Python 2/3 compatible decoding of make/model field.
|
|
|
48
48
|
|
|
49
49
|
---
|
|
50
50
|
|
|
51
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
51
|
+
<a href="../geopic_tag_reader/reader.py#L405"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
52
52
|
|
|
53
53
|
## <kbd>function</kbd> `isValidManyFractions`
|
|
54
54
|
|
|
@@ -63,7 +63,7 @@ isValidManyFractions(value: str) → bool
|
|
|
63
63
|
|
|
64
64
|
---
|
|
65
65
|
|
|
66
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
66
|
+
<a href="../geopic_tag_reader/reader.py#L412"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
67
67
|
|
|
68
68
|
## <kbd>function</kbd> `decodeManyFractions`
|
|
69
69
|
|
|
@@ -76,7 +76,7 @@ Try to decode a list of fractions, separated by spaces
|
|
|
76
76
|
|
|
77
77
|
---
|
|
78
78
|
|
|
79
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
79
|
+
<a href="../geopic_tag_reader/reader.py#L425"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
80
80
|
|
|
81
81
|
## <kbd>function</kbd> `decodeLatLon`
|
|
82
82
|
|
|
@@ -92,7 +92,7 @@ Reads GPS info from given group to get latitude/longitude as float coordinates
|
|
|
92
92
|
|
|
93
93
|
---
|
|
94
94
|
|
|
95
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
95
|
+
<a href="../geopic_tag_reader/reader.py#L480"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
96
96
|
|
|
97
97
|
## <kbd>function</kbd> `decodeDateTimeOriginal`
|
|
98
98
|
|
|
@@ -112,7 +112,7 @@ decodeDateTimeOriginal(
|
|
|
112
112
|
|
|
113
113
|
---
|
|
114
114
|
|
|
115
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
115
|
+
<a href="../geopic_tag_reader/reader.py#L534"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
116
116
|
|
|
117
117
|
## <kbd>function</kbd> `decodeTimeOffset`
|
|
118
118
|
|
|
@@ -127,7 +127,7 @@ decodeTimeOffset(data: dict, offsetTimeField: str) → Optional[tzinfo]
|
|
|
127
127
|
|
|
128
128
|
---
|
|
129
129
|
|
|
130
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
130
|
+
<a href="../geopic_tag_reader/reader.py#L540"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
131
131
|
|
|
132
132
|
## <kbd>function</kbd> `decodeGPSDateTime`
|
|
133
133
|
|
|
@@ -147,7 +147,7 @@ decodeGPSDateTime(
|
|
|
147
147
|
|
|
148
148
|
---
|
|
149
149
|
|
|
150
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
150
|
+
<a href="../geopic_tag_reader/reader.py#L591"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
151
151
|
|
|
152
152
|
## <kbd>function</kbd> `decodeSecondsAndMicroSeconds`
|
|
153
153
|
|
|
@@ -165,7 +165,7 @@ decodeSecondsAndMicroSeconds(
|
|
|
165
165
|
|
|
166
166
|
---
|
|
167
167
|
|
|
168
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
168
|
+
<a href="../geopic_tag_reader/reader.py#L617"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
169
169
|
|
|
170
170
|
## <kbd>function</kbd> `isExifTagUsable`
|
|
171
171
|
|
|
@@ -245,7 +245,7 @@ Tags associated to a geolocated picture
|
|
|
245
245
|
- <b>`lat`</b> (float): GPS Latitude (in WGS84)
|
|
246
246
|
- <b>`lon`</b> (float): GPS Longitude (in WGS84)
|
|
247
247
|
- <b>`ts`</b> (datetime): The capture date (date & time with timezone)
|
|
248
|
-
- <b>`heading`</b> (int): Picture heading (in degrees, North = 0°, East = 90°, South = 180°, West = 270°)
|
|
248
|
+
- <b>`heading`</b> (int): Picture heading/yaw (in degrees, North = 0°, East = 90°, South = 180°, West = 270°)
|
|
249
249
|
- <b>`type`</b> (str): The kind of picture (flat, equirectangular)
|
|
250
250
|
- <b>`make`</b> (str): The camera manufacturer name
|
|
251
251
|
- <b>`model`</b> (str): The camera model name
|
|
@@ -254,6 +254,8 @@ Tags associated to a geolocated picture
|
|
|
254
254
|
- <b>`exif`</b> (dict[str, str]): Raw EXIF tags from picture (following Exiv2 naming scheme, see https://exiv2.org/metadata.html)
|
|
255
255
|
- <b>`tagreader_warnings`</b> (list[str]): List of thrown warnings during metadata reading
|
|
256
256
|
- <b>`altitude`</b> (float): altitude (in m) (optional)
|
|
257
|
+
- <b>`pitch`</b> (float): Picture pitch angle, compared to horizon (in degrees, bottom = -90°, horizon = 0°, top = 90°)
|
|
258
|
+
- <b>`roll`</b> (float): Picture roll angle, on a right/left axis (in degrees, left-arm down = -90°, flat = 0°, right-arm down = 90°)
|
|
257
259
|
|
|
258
260
|
|
|
259
261
|
|
|
@@ -276,7 +278,9 @@ __init__(
|
|
|
276
278
|
crop: Optional[CropValues],
|
|
277
279
|
exif: Dict[str, str] = <factory>,
|
|
278
280
|
tagreader_warnings: List[str] = <factory>,
|
|
279
|
-
altitude: Optional[float] = None
|
|
281
|
+
altitude: Optional[float] = None,
|
|
282
|
+
pitch: Optional[float] = None,
|
|
283
|
+
roll: Optional[float] = None
|
|
280
284
|
) → None
|
|
281
285
|
```
|
|
282
286
|
|
|
@@ -290,12 +294,12 @@ __init__(
|
|
|
290
294
|
|
|
291
295
|
---
|
|
292
296
|
|
|
293
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
297
|
+
<a href="../geopic_tag_reader/reader.py#L81"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
294
298
|
|
|
295
299
|
## <kbd>class</kbd> `InvalidExifException`
|
|
296
300
|
Exception for invalid EXIF information from image
|
|
297
301
|
|
|
298
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
302
|
+
<a href="../geopic_tag_reader/reader.py#L84"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
299
303
|
|
|
300
304
|
### <kbd>method</kbd> `__init__`
|
|
301
305
|
|
|
@@ -313,7 +317,7 @@ __init__(msg)
|
|
|
313
317
|
|
|
314
318
|
---
|
|
315
319
|
|
|
316
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
320
|
+
<a href="../geopic_tag_reader/reader.py#L88"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
317
321
|
|
|
318
322
|
## <kbd>class</kbd> `PartialGeoPicTags`
|
|
319
323
|
Tags associated to a geolocated picture when not all tags have been found
|
|
@@ -337,7 +341,9 @@ __init__(
|
|
|
337
341
|
crop: Optional[CropValues] = None,
|
|
338
342
|
exif: Dict[str, str] = <factory>,
|
|
339
343
|
tagreader_warnings: List[str] = <factory>,
|
|
340
|
-
altitude: Optional[float] = None
|
|
344
|
+
altitude: Optional[float] = None,
|
|
345
|
+
pitch: Optional[float] = None,
|
|
346
|
+
roll: Optional[float] = None
|
|
341
347
|
) → None
|
|
342
348
|
```
|
|
343
349
|
|
|
@@ -351,14 +357,14 @@ __init__(
|
|
|
351
357
|
|
|
352
358
|
---
|
|
353
359
|
|
|
354
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
360
|
+
<a href="../geopic_tag_reader/reader.py#L111"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
355
361
|
|
|
356
362
|
## <kbd>class</kbd> `PartialExifException`
|
|
357
363
|
Exception for partial / missing EXIF information from image
|
|
358
364
|
|
|
359
365
|
Contains a PartialGeoPicTags with all tags that have been read and the list of missing tags
|
|
360
366
|
|
|
361
|
-
<a href="../geopic_tag_reader/reader.py#
|
|
367
|
+
<a href="../geopic_tag_reader/reader.py#L118"><img align="right" style="float:right;" src="https://img.shields.io/badge/-source-cccccc?style=flat-square"></a>
|
|
362
368
|
|
|
363
369
|
### <kbd>method</kbd> `__init__`
|
|
364
370
|
|
|
@@ -29,6 +29,8 @@ def read(
|
|
|
29
29
|
print("Model:", metadata.model)
|
|
30
30
|
print("Focal length:", metadata.focal_length)
|
|
31
31
|
print("Crop parameters:", metadata.crop)
|
|
32
|
+
print("Pitch:", metadata.pitch)
|
|
33
|
+
print("Roll:", metadata.roll)
|
|
32
34
|
|
|
33
35
|
if len(metadata.tagreader_warnings) > 0:
|
|
34
36
|
print("Warnings raised by reader:")
|
|
@@ -46,7 +46,7 @@ class GeoPicTags:
|
|
|
46
46
|
lat (float): GPS Latitude (in WGS84)
|
|
47
47
|
lon (float): GPS Longitude (in WGS84)
|
|
48
48
|
ts (datetime): The capture date (date & time with timezone)
|
|
49
|
-
heading (int): Picture heading (in degrees, North = 0°, East = 90°, South = 180°, West = 270°)
|
|
49
|
+
heading (int): Picture heading/yaw (in degrees, North = 0°, East = 90°, South = 180°, West = 270°)
|
|
50
50
|
type (str): The kind of picture (flat, equirectangular)
|
|
51
51
|
make (str): The camera manufacturer name
|
|
52
52
|
model (str): The camera model name
|
|
@@ -55,6 +55,8 @@ class GeoPicTags:
|
|
|
55
55
|
exif (dict[str, str]): Raw EXIF tags from picture (following Exiv2 naming scheme, see https://exiv2.org/metadata.html)
|
|
56
56
|
tagreader_warnings (list[str]): List of thrown warnings during metadata reading
|
|
57
57
|
altitude (float): altitude (in m) (optional)
|
|
58
|
+
pitch (float): Picture pitch angle, compared to horizon (in degrees, bottom = -90°, horizon = 0°, top = 90°)
|
|
59
|
+
roll (float): Picture roll angle, on a right/left axis (in degrees, left-arm down = -90°, flat = 0°, right-arm down = 90°)
|
|
58
60
|
|
|
59
61
|
|
|
60
62
|
Implementation note: this needs to be sync with the PartialGeoPicTags structure
|
|
@@ -72,6 +74,8 @@ class GeoPicTags:
|
|
|
72
74
|
exif: Dict[str, str] = field(default_factory=lambda: {})
|
|
73
75
|
tagreader_warnings: List[str] = field(default_factory=lambda: [])
|
|
74
76
|
altitude: Optional[float] = None
|
|
77
|
+
pitch: Optional[float] = None
|
|
78
|
+
roll: Optional[float] = None
|
|
75
79
|
|
|
76
80
|
|
|
77
81
|
class InvalidExifException(Exception):
|
|
@@ -100,6 +104,8 @@ class PartialGeoPicTags:
|
|
|
100
104
|
exif: Dict[str, str] = field(default_factory=lambda: {})
|
|
101
105
|
tagreader_warnings: List[str] = field(default_factory=lambda: [])
|
|
102
106
|
altitude: Optional[float] = None
|
|
107
|
+
pitch: Optional[float] = None
|
|
108
|
+
roll: Optional[float] = None
|
|
103
109
|
|
|
104
110
|
|
|
105
111
|
class PartialExifException(Exception):
|
|
@@ -213,7 +219,7 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
213
219
|
except Exception as e:
|
|
214
220
|
warnings.append("Skipping Mapillary date/time as it was not recognized:\n\t" + str(e))
|
|
215
221
|
|
|
216
|
-
# Heading
|
|
222
|
+
# Heading/Yaw
|
|
217
223
|
heading = None
|
|
218
224
|
if isExifTagUsable(data, "Xmp.GPano.PoseHeadingDegrees", float) and isExifTagUsable(data, "Exif.GPSInfo.GPSImgDirection", Fraction):
|
|
219
225
|
gpsDir = int(round(float(Fraction(data["Exif.GPSInfo.GPSImgDirection"]))))
|
|
@@ -236,6 +242,35 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
236
242
|
elif "MAPCompassHeading" in data and isExifTagUsable(data["MAPCompassHeading"], "TrueHeading", float):
|
|
237
243
|
heading = int(round(float(data["MAPCompassHeading"]["TrueHeading"])))
|
|
238
244
|
|
|
245
|
+
# Pitch & roll
|
|
246
|
+
pitch = None
|
|
247
|
+
roll = None
|
|
248
|
+
exifPRFields = ["Xmp.Camera.$$", "Exif.GPSInfo.GPS$$", "Xmp.GPano.Pose$$Degrees", "Xmp.GPano.InitialView$$Degrees"]
|
|
249
|
+
# For each potential EXIF field
|
|
250
|
+
for exifField in exifPRFields:
|
|
251
|
+
# Try out both Pitch & Roll variants
|
|
252
|
+
for checkField in ["Pitch", "Roll"]:
|
|
253
|
+
exifCheckField = exifField.replace("$$", checkField)
|
|
254
|
+
foundValue = None
|
|
255
|
+
# Look for float or fraction
|
|
256
|
+
if isExifTagUsable(data, exifCheckField, float):
|
|
257
|
+
foundValue = float(data[exifCheckField])
|
|
258
|
+
elif isExifTagUsable(data, exifCheckField, Fraction):
|
|
259
|
+
foundValue = float(Fraction(data[exifCheckField]))
|
|
260
|
+
|
|
261
|
+
# Save to correct variable (if not already set)
|
|
262
|
+
if foundValue is not None:
|
|
263
|
+
if checkField == "Pitch":
|
|
264
|
+
if pitch is None:
|
|
265
|
+
pitch = foundValue
|
|
266
|
+
else:
|
|
267
|
+
continue
|
|
268
|
+
elif checkField == "Roll":
|
|
269
|
+
if roll is None:
|
|
270
|
+
roll = foundValue
|
|
271
|
+
else:
|
|
272
|
+
continue
|
|
273
|
+
|
|
239
274
|
# Make and model
|
|
240
275
|
make = data.get("Exif.Image.Make") or data.get("MAPDeviceMake")
|
|
241
276
|
model = data.get("Exif.Image.Model") or data.get("MAPDeviceModel")
|
|
@@ -332,6 +367,8 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
332
367
|
exif=data,
|
|
333
368
|
tagreader_warnings=warnings,
|
|
334
369
|
altitude=altitude,
|
|
370
|
+
pitch=pitch,
|
|
371
|
+
roll=roll,
|
|
335
372
|
),
|
|
336
373
|
)
|
|
337
374
|
|
|
@@ -349,6 +386,8 @@ def readPictureMetadata(picture: bytes) -> GeoPicTags:
|
|
|
349
386
|
exif=data,
|
|
350
387
|
tagreader_warnings=warnings,
|
|
351
388
|
altitude=altitude,
|
|
389
|
+
pitch=pitch,
|
|
390
|
+
roll=roll,
|
|
352
391
|
)
|
|
353
392
|
|
|
354
393
|
|
|
@@ -13,6 +13,8 @@ def assertGeoPicTagsEquals(gpt, expectedDict):
|
|
|
13
13
|
assert gpt.model == expectedDict.get("model")
|
|
14
14
|
assert gpt.focal_length == expectedDict.get("focal_length")
|
|
15
15
|
assert gpt.altitude == expectedDict.get("altitude")
|
|
16
|
+
assert gpt.pitch == expectedDict.get("pitch")
|
|
17
|
+
assert gpt.roll == expectedDict.get("roll")
|
|
16
18
|
assert gpt.tagreader_warnings == expectedDict.get("tagreader_warnings", [])
|
|
17
19
|
assert len(gpt.exif) > 0
|
|
18
20
|
|
|
@@ -49,6 +51,8 @@ def test_readPictureMetadata(datafiles):
|
|
|
49
51
|
"model": "Max",
|
|
50
52
|
"focal_length": 3,
|
|
51
53
|
"altitude": 93,
|
|
54
|
+
"roll": 0,
|
|
55
|
+
"pitch": 0,
|
|
52
56
|
},
|
|
53
57
|
)
|
|
54
58
|
|
|
@@ -68,6 +72,8 @@ def test_readPictureMetadata_negCoords(datafiles):
|
|
|
68
72
|
"model": "Max",
|
|
69
73
|
"focal_length": 3,
|
|
70
74
|
"altitude": 79,
|
|
75
|
+
"roll": 0,
|
|
76
|
+
"pitch": 0,
|
|
71
77
|
},
|
|
72
78
|
)
|
|
73
79
|
|
|
@@ -161,6 +167,8 @@ def test_readPictureMetadata_ricoh_theta(datafiles):
|
|
|
161
167
|
"model": "THETA m15",
|
|
162
168
|
"ts": "2016-03-25T14:12:13+01:00",
|
|
163
169
|
"type": "equirectangular",
|
|
170
|
+
"roll": 3,
|
|
171
|
+
"pitch": 1,
|
|
164
172
|
},
|
|
165
173
|
)
|
|
166
174
|
|
|
@@ -602,6 +610,8 @@ def test_readPictureMetadata_datetime_offset(datafiles):
|
|
|
602
610
|
"model": "Max",
|
|
603
611
|
"focal_length": 3,
|
|
604
612
|
"altitude": 79,
|
|
613
|
+
"roll": 0,
|
|
614
|
+
"pitch": 0,
|
|
605
615
|
},
|
|
606
616
|
)
|
|
607
617
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/img_without_exif_tags.jpg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{geopic_tag_reader-1.1.0 → geopic_tag_reader-1.1.1}/tests/fixtures/ricoh_theta_no_projection.jpg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|