geopic-tag-reader 1.3.2__tar.gz → 1.4.0__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.3.2 → geopic_tag_reader-1.4.0}/CHANGELOG.md +17 -1
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/PKG-INFO +2 -2
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/docs/develop.md +14 -0
- geopic_tag_reader-1.4.0/docs/images/quality_score.png +0 -0
- geopic_tag_reader-1.4.0/docs/images/quality_score_viewer.png +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/docs/index.md +1 -1
- geopic_tag_reader-1.4.0/docs/quality_score.md +84 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/__init__.py +1 -1
- geopic_tag_reader-1.4.0/geopic_tag_reader/camera.py +148 -0
- geopic_tag_reader-1.4.0/geopic_tag_reader/cameras.csv +3775 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/main.py +3 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/reader.py +89 -8
- geopic_tag_reader-1.4.0/geopic_tag_reader/translations/da/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- geopic_tag_reader-1.4.0/geopic_tag_reader/translations/da/LC_MESSAGES/geopic_tag_reader.po +209 -0
- geopic_tag_reader-1.4.0/geopic_tag_reader/translations/de/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/translations/de/LC_MESSAGES/geopic_tag_reader.po +44 -1
- geopic_tag_reader-1.4.0/geopic_tag_reader/translations/en/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/translations/en/LC_MESSAGES/geopic_tag_reader.po +77 -34
- geopic_tag_reader-1.4.0/geopic_tag_reader/translations/eo/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- geopic_tag_reader-1.4.0/geopic_tag_reader/translations/eo/LC_MESSAGES/geopic_tag_reader.po +207 -0
- geopic_tag_reader-1.4.0/geopic_tag_reader/translations/fr/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/translations/fr/LC_MESSAGES/geopic_tag_reader.po +152 -119
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/translations/geopic_tag_reader.pot +68 -30
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/translations/hu/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/translations/hu/LC_MESSAGES/geopic_tag_reader.po +4 -4
- geopic_tag_reader-1.4.0/geopic_tag_reader/translations/it/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- geopic_tag_reader-1.4.0/geopic_tag_reader/translations/it/LC_MESSAGES/geopic_tag_reader.po +212 -0
- geopic_tag_reader-1.4.0/geopic_tag_reader/translations/nl/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- geopic_tag_reader-1.4.0/geopic_tag_reader/translations/nl/LC_MESSAGES/geopic_tag_reader.po +213 -0
- geopic_tag_reader-1.4.0/geopic_tag_reader/translations/pl/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- geopic_tag_reader-1.4.0/geopic_tag_reader/translations/pl/LC_MESSAGES/geopic_tag_reader.po +203 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/mkdocs.yml +1 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/pyproject.toml +1 -1
- geopic_tag_reader-1.3.2/geopic_tag_reader/camera.py +0 -60
- geopic_tag_reader-1.3.2/geopic_tag_reader/translations/de/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- geopic_tag_reader-1.3.2/geopic_tag_reader/translations/en/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- geopic_tag_reader-1.3.2/geopic_tag_reader/translations/fr/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/.gitignore +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/.gitlab-ci.yml +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/.pre-commit-config.yaml +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/CODE_OF_CONDUCT.md +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/LICENSE +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/Makefile +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/README.md +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/docs/install.md +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/docs/tech/api_reference.md +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/docs/tech/cli.md +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/i18n.py +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/model.py +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/py.typed +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/sequence.py +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/translations/es/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/translations/es/LC_MESSAGES/geopic_tag_reader.po +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/translations/fi/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/translations/fi/LC_MESSAGES/geopic_tag_reader.po +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/translations/ko/LC_MESSAGES/geopic_tag_reader.mo +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/translations/ko/LC_MESSAGES/geopic_tag_reader.po +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/geopic_tag_reader/writer.py +0 -0
- {geopic_tag_reader-1.3.2 → geopic_tag_reader-1.4.0}/pytest.ini +0 -0
|
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.4.0] - 2025-01-06
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Camera general metadata (sensor width, 360° devices, GPS average accuracy) is made available through a single CSV file named `cameras.csv`. This make info centralized and will lighten camera info in Panoramax API.
|
|
15
|
+
- New fields are offered in GeoPicTags: `sensor_width, gps_accuracy, field_of_view`
|
|
16
|
+
|
|
17
|
+
## [1.3.3] - 2024-11-24
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Warnings are shown if any useful metadata is missing for computing a quality score (make, model, GPS accuracy...).
|
|
22
|
+
- New languages : 🇵🇱, 🇳🇱, 🇭🇺, 🇪🇸, 🇩🇪 (thanks to all translators !)
|
|
23
|
+
|
|
10
24
|
## [1.3.2] - 2024-10-22
|
|
11
25
|
|
|
12
26
|
### Changed
|
|
@@ -237,7 +251,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
237
251
|
|
|
238
252
|
- EXIF tag reading methods extracted from [Panoramax/GeoVisio API](https://gitlab.com/panoramax/server/api)
|
|
239
253
|
|
|
240
|
-
[Unreleased]: https://gitlab.com/panoramax/server/geo-picture-tag-reader/-/compare/1.
|
|
254
|
+
[Unreleased]: https://gitlab.com/panoramax/server/geo-picture-tag-reader/-/compare/1.4.0...main
|
|
255
|
+
[1.4.0]: https://gitlab.com/panoramax/server/geo-picture-tag-reader/-/compare/1.3.3...1.4.0
|
|
256
|
+
[1.3.3]: https://gitlab.com/panoramax/server/geo-picture-tag-reader/-/compare/1.3.2...1.3.3
|
|
241
257
|
[1.3.2]: https://gitlab.com/panoramax/server/geo-picture-tag-reader/-/compare/1.3.1...1.3.2
|
|
242
258
|
[1.3.1]: https://gitlab.com/panoramax/server/geo-picture-tag-reader/-/compare/1.3.0...1.3.1
|
|
243
259
|
[1.3.0]: https://gitlab.com/panoramax/server/geo-picture-tag-reader/-/compare/1.2.0...1.3.0
|
|
@@ -69,6 +69,20 @@ pip install -e .[dev]
|
|
|
69
69
|
pre-commit install
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
### Add camera information
|
|
73
|
+
|
|
74
|
+
Many fallback information are made available through the `geopic_tag_reader/cameras.csv` file, which is structured this way:
|
|
75
|
+
|
|
76
|
+
- `make`: name of camera builder (as noted in `Make` EXIF field in picture)
|
|
77
|
+
- `model`: name of camera model (as noted in `Model` EXIF field in picture)
|
|
78
|
+
- `sensor_width`: the width of camera sensor (in millimeters)
|
|
79
|
+
- `is_360`: set to `1` if camera is a 360° device, left empty or set to `0` otherwise
|
|
80
|
+
- `gps_accuracy`: average GPS accuracy (in meters) if the camera has an embed GPS and pictures don't contain GPS horizontal positioning error in their metadata
|
|
81
|
+
|
|
82
|
+
If a camera is missing in this list, feel free to offer a pull request or send us these information through an issue or an email so we can expand the list.
|
|
83
|
+
|
|
84
|
+
Also note that more generic information about GPS accuracy from various camera brands is present in `geopic_tag_reader/camera.py` file (`GPS_ACCURACY_MAKE` constant). This allows us to say _"all smartphones from this brand have this GPS accuracy"_, feel free to contact us if we missed some brands.
|
|
85
|
+
|
|
72
86
|
## Make a release
|
|
73
87
|
|
|
74
88
|
```bash
|
|
Binary file
|
|
Binary file
|
|
@@ -54,7 +54,7 @@ Image orientation is read from
|
|
|
54
54
|
|
|
55
55
|
#### :material-timer: Milliseconds in date
|
|
56
56
|
|
|
57
|
-
Milliseconds in date is
|
|
57
|
+
Milliseconds in date is read from `SubSecTimeOriginal`.
|
|
58
58
|
|
|
59
59
|
#### :material-panorama-sphere-outline: 360° or flat
|
|
60
60
|
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# :white_check_mark: Quality score
|
|
2
|
+
|
|
3
|
+
Panoramax offers a _Quality Score_ for each picture in its web viewer. It allows easy map filtering and comprehensive display of high-quality pictures availability.
|
|
4
|
+
|
|
5
|
+
The grade is shown to users as a A/B/C/D/E score (A is the best, E the worst), and shown graphically through this scale (inspired by [Nutri-Score](https://en.wikipedia.org/wiki/Nutri-Score)):
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
## :material-calculator: Score computation
|
|
10
|
+
|
|
11
|
+
Quality score is based on two indicators:
|
|
12
|
+
|
|
13
|
+
- :material-crosshairs-gps: __GPS position accuracy__: how precisely the GPS coordinates are set, in meters. This is 1/5 of the score.
|
|
14
|
+
- :material-camera-iris: __Horizontal pixel density__: how many pixels we have on horizon per _field of view_ degree. This is 4/5 of the score.
|
|
15
|
+
|
|
16
|
+
They are displayed through web viewer in picture metadata popup:
|
|
17
|
+
|
|
18
|
+

|
|
19
|
+
|
|
20
|
+
!!! info
|
|
21
|
+
|
|
22
|
+
We know that this is a pretty simple indicator. Many other information could be taken into account (blurriness, light...) and may be used in the future. We started with something simple to make the _quality score_ available on as many pictures as possible. You can [come and help us](https://docs.panoramax.fr/how-to-contribute/#contribute-to-the-development) to make this happen sooner :grinning:
|
|
23
|
+
|
|
24
|
+
### :material-crosshairs-gps: GPS position accuracy
|
|
25
|
+
|
|
26
|
+
This indicator allows to know if we can rely or not on GPS position, based on its precision. It is expressed as a decimal value in meters. The grade is a 5-star rating, and is applied based on these values:
|
|
27
|
+
|
|
28
|
+
| GPS Accuracy | Grade |
|
|
29
|
+
| ----------------- | ----- |
|
|
30
|
+
| <= 1 m | 5/5 |
|
|
31
|
+
| <= 2 m | 4/5 |
|
|
32
|
+
| <= 5 m | 3/5 |
|
|
33
|
+
| <= 10 m | 2/5 |
|
|
34
|
+
| > 10 m or unknown | 1/5 |
|
|
35
|
+
|
|
36
|
+
The value is read from picture EXIF metadata. We rely on the following tags:
|
|
37
|
+
|
|
38
|
+
- __Horizontal positioning error__ (`Exif.GPSInfo.GPSHPositioningError` or `Xmp.exif.GPSHPositioningError`) : expected positioning error in meters.
|
|
39
|
+
- __Dilution of precision__ (`Exif.GPSInfo.GPSDOP` or `Xmp.exif.GPSDOP`) : indicator of expected precision on coordinates (<= 1 means good precision for the sensor, >= 5 is not good, [more info on Wikipedia](https://en.wikipedia.org/wiki/Dilution_of_precision_(navigation))).
|
|
40
|
+
- __Is the GPS differential__ (`Exif.GPSInfo.GPSDifferential` or `Xmp.exif.GPSDifferential`) : indicates if GPS sensor is using [Differential GPS](https://en.wikipedia.org/wiki/Differential_GPS) or not. If yes, we expect a better precision.
|
|
41
|
+
|
|
42
|
+
These are used to define a precision value in meters. If none of these tags are set, we also rely on a default value for several camera vendors (based on `Make` and `Model` EXIF tags).
|
|
43
|
+
|
|
44
|
+
So, to get a good grade on GPS precision, you can (in order):
|
|
45
|
+
|
|
46
|
+
- Set a precise _Horizontal positioning error_
|
|
47
|
+
- Set a value for _Differential GPS_ and/or _Dilution of precision_
|
|
48
|
+
- Set values for _Make_ and _Model_ if you use a common camera
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
!!! info
|
|
52
|
+
|
|
53
|
+
If you find the shown value not reflecting the real precision of your GPS sensor, feel free to contact us with an example link. We tried to make precision estimates on a large set of cameras, but we may have missed some :material-map-search:
|
|
54
|
+
|
|
55
|
+
### :material-camera-iris: Horizontal pixel density
|
|
56
|
+
|
|
57
|
+
This indicator allows to have an idea of how high the picture resolution is, independently of its field of view (360° or classic picture). The formula is: `picture width in pixels / field of view in degrees`. We have in result a number of pixels per FOV degree. The grade is a 5-star rating, and is applied based on these values:
|
|
58
|
+
|
|
59
|
+
| Grade | Density for 360° | Density for non 360° |
|
|
60
|
+
| ----- | ---------------- | --------------------------- |
|
|
61
|
+
| 5/5 | >= 30 px/deg | Not possible |
|
|
62
|
+
| 4/5 | >= 15 px/deg | >= 30 px/deg |
|
|
63
|
+
| 3/5 | < 15px/deg | >= 15px/deg |
|
|
64
|
+
| 2/5 | Not possible | >= 10 px/deg |
|
|
65
|
+
| 1/5 | Unknown value | < 10 px/deg or unknown value |
|
|
66
|
+
|
|
67
|
+
!!! info
|
|
68
|
+
|
|
69
|
+
A different rating is applied for 360°, as they offer a nicer user experience on web viewer. Note that if you're a technical reuser, the API offers raw values for each indicator, allowing you to do your own custom rating.
|
|
70
|
+
|
|
71
|
+
The value is computed from picture width in pixels, and some EXIF metadata. We rely on the following tags:
|
|
72
|
+
|
|
73
|
+
- __Focal length__ (`Exif.Image.FocalLength` or `Exif.Photo.FocalLength`): distance in millimeters between the nodal point of the lens and the camera sensor.
|
|
74
|
+
- __Make and model__ (`Exif.Image.Make` and `Exif.Image.Make`): camera model, which is used to find camera sensor width.
|
|
75
|
+
- __Projection type__ (for 360° pictures, `Xmp.GPano.ProjectionType`): to mark a picture as 360°
|
|
76
|
+
|
|
77
|
+
Based on these information, we are able to compute the _field of view_ (how wide the camera can look horizontally).
|
|
78
|
+
|
|
79
|
+
As these information are hard to deduce, you may carefully set all of them in EXIF metadata.
|
|
80
|
+
|
|
81
|
+
!!! info
|
|
82
|
+
|
|
83
|
+
If you have pictures with an unknown value for this grade, it's probably because we miss information on your camera model. Make sure your pictures have required information, and contact us with the camera _sensor width_ so we can add it in our listing.
|
|
84
|
+
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
from typing import Optional, Dict, List
|
|
2
|
+
import importlib.resources
|
|
3
|
+
import csv
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Per-make GPS estimated accuracy (in meters)
|
|
8
|
+
GPS_ACCURACY_MAKE = {
|
|
9
|
+
# Diff GPS
|
|
10
|
+
"stfmani": 2,
|
|
11
|
+
"trimble": 2,
|
|
12
|
+
"imajing": 2,
|
|
13
|
+
# Good GPS
|
|
14
|
+
"gopro": 4,
|
|
15
|
+
"insta360": 4,
|
|
16
|
+
"garmin": 4,
|
|
17
|
+
"viofo": 4,
|
|
18
|
+
"xiaoyi": 4,
|
|
19
|
+
"blackvue": 4,
|
|
20
|
+
"tectectec": 4,
|
|
21
|
+
"arashi vision": 4,
|
|
22
|
+
# Smartphone GPS
|
|
23
|
+
"samsung": 5,
|
|
24
|
+
"xiaomi": 5,
|
|
25
|
+
"huawei": 5,
|
|
26
|
+
"ricoh": 5,
|
|
27
|
+
"lenovo": 5,
|
|
28
|
+
"motorola": 5,
|
|
29
|
+
"oneplus": 5,
|
|
30
|
+
"apple": 5,
|
|
31
|
+
"google": 5,
|
|
32
|
+
"sony": 5,
|
|
33
|
+
"wiko": 5,
|
|
34
|
+
"asus": 5,
|
|
35
|
+
"cubot": 5,
|
|
36
|
+
"lge": 5,
|
|
37
|
+
"fairphone": 5,
|
|
38
|
+
"realme": 5,
|
|
39
|
+
"symphony": 5,
|
|
40
|
+
"crosscall": 5,
|
|
41
|
+
"htc": 5,
|
|
42
|
+
"homtom": 5,
|
|
43
|
+
"hmd global": 5,
|
|
44
|
+
"oppo": 5,
|
|
45
|
+
"ulefone": 5,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class CameraMetadata:
|
|
51
|
+
is_360: bool = False
|
|
52
|
+
sensor_width: Optional[float] = None
|
|
53
|
+
gps_accuracy: Optional[float] = None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
CAMERAS: Dict[str, Dict[str, CameraMetadata]] = {} # Make -> Model -> Metadata
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def get_cameras() -> Dict[str, Dict[str, CameraMetadata]]:
|
|
60
|
+
"""
|
|
61
|
+
Retrieve general metadata about cameras
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
if len(CAMERAS) > 0:
|
|
65
|
+
return CAMERAS
|
|
66
|
+
|
|
67
|
+
# Cameras.csv file is a composite of various sources:
|
|
68
|
+
# - Wikipedia's list of 360° cameras ( https://en.wikipedia.org/wiki/List_of_omnidirectional_(360-degree)_cameras )
|
|
69
|
+
# - OpenSfM's sensor widths ( https://github.com/mapillary/OpenSfM/blob/main/opensfm/data/sensor_data.json )
|
|
70
|
+
|
|
71
|
+
with importlib.resources.open_text("geopic_tag_reader", "cameras.csv") as camerasCsv:
|
|
72
|
+
camerasReader = csv.DictReader(camerasCsv, delimiter=";")
|
|
73
|
+
for camera in camerasReader:
|
|
74
|
+
make = camera["make"].lower()
|
|
75
|
+
model = camera["model"].lower()
|
|
76
|
+
sensorWidth = float(camera["sensor_width"]) if camera["sensor_width"] != "" else None
|
|
77
|
+
is360 = camera["is_360"] == "1"
|
|
78
|
+
gpsAccuracy = float(camera["gps_accuracy"]) if camera["gps_accuracy"] != "" else None
|
|
79
|
+
|
|
80
|
+
# Override GPS Accuracy with Make one if necessary
|
|
81
|
+
if gpsAccuracy is None and make in GPS_ACCURACY_MAKE:
|
|
82
|
+
gpsAccuracy = GPS_ACCURACY_MAKE[make]
|
|
83
|
+
|
|
84
|
+
# Append to general list
|
|
85
|
+
if not make in CAMERAS:
|
|
86
|
+
CAMERAS[make] = {}
|
|
87
|
+
|
|
88
|
+
CAMERAS[make][model] = CameraMetadata(is360, sensorWidth, gpsAccuracy)
|
|
89
|
+
|
|
90
|
+
return CAMERAS
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def find_camera(make: Optional[str] = None, model: Optional[str] = None) -> Optional[CameraMetadata]:
|
|
94
|
+
"""
|
|
95
|
+
Finds camera metadata based on make and model.
|
|
96
|
+
|
|
97
|
+
>>> find_camera()
|
|
98
|
+
|
|
99
|
+
>>> find_camera("GoPro")
|
|
100
|
+
|
|
101
|
+
>>> find_camera("GoPro", "Max")
|
|
102
|
+
CameraMetadata(is_360=True, sensor_width=6.17, gps_accuracy=4)
|
|
103
|
+
>>> find_camera("GoPro", "Max 360")
|
|
104
|
+
CameraMetadata(is_360=True, sensor_width=6.17, gps_accuracy=4)
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
# Check make and model are defined
|
|
108
|
+
if not make or not model:
|
|
109
|
+
return None
|
|
110
|
+
|
|
111
|
+
# Find make
|
|
112
|
+
cameras = get_cameras()
|
|
113
|
+
matchMake = next((m for m in cameras.keys() if m in make.lower()), None)
|
|
114
|
+
if matchMake is None:
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
# Find model
|
|
118
|
+
return next((cameras[matchMake][matchModel] for matchModel in cameras[matchMake].keys() if model.lower().startswith(matchModel)), None)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def is_360(make: Optional[str] = None, model: Optional[str] = None, width: Optional[str] = None, height: Optional[str] = None) -> bool:
|
|
122
|
+
"""
|
|
123
|
+
Checks if given camera is equirectangular (360°) based on its make, model and dimensions (width, height).
|
|
124
|
+
|
|
125
|
+
>>> is_360()
|
|
126
|
+
False
|
|
127
|
+
>>> is_360("GoPro")
|
|
128
|
+
False
|
|
129
|
+
>>> is_360("GoPro", "Max 360")
|
|
130
|
+
True
|
|
131
|
+
>>> is_360("GoPro", "Max 360", "2048", "1024")
|
|
132
|
+
True
|
|
133
|
+
>>> is_360("GoPro", "Max 360", "1024", "768")
|
|
134
|
+
False
|
|
135
|
+
>>> is_360("RICOH", "THETA S", "5376", "2688")
|
|
136
|
+
True
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
# Check make and model are defined
|
|
140
|
+
camera = find_camera(make, model)
|
|
141
|
+
if not camera:
|
|
142
|
+
return False
|
|
143
|
+
|
|
144
|
+
# Check width and height are equirectangular
|
|
145
|
+
if not ((width is None or height is None) or int(width) == 2 * int(height)):
|
|
146
|
+
return False
|
|
147
|
+
|
|
148
|
+
return camera.is_360
|