lunadem 0.2.2__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.
- lunadem-0.2.2/.gitignore +40 -0
- lunadem-0.2.2/LICENSE +21 -0
- lunadem-0.2.2/PKG-INFO +163 -0
- lunadem-0.2.2/README.md +87 -0
- lunadem-0.2.2/examples/webapp/README.md +8 -0
- lunadem-0.2.2/lunardem/__init__.py +41 -0
- lunadem-0.2.2/lunardem/assets/fun.mp3 +0 -0
- lunadem-0.2.2/lunardem/assets/japneet.jpeg +0 -0
- lunadem-0.2.2/lunardem/assets/noor.mp4 +0 -0
- lunadem-0.2.2/lunardem/cli.py +286 -0
- lunadem-0.2.2/lunardem/core/__init__.py +39 -0
- lunadem-0.2.2/lunardem/core/api.py +223 -0
- lunadem-0.2.2/lunardem/core/config.py +155 -0
- lunadem-0.2.2/lunardem/core/models.py +46 -0
- lunadem-0.2.2/lunardem/core/registry.py +26 -0
- lunadem-0.2.2/lunardem/geometry/__init__.py +16 -0
- lunadem-0.2.2/lunardem/geometry/lighting.py +26 -0
- lunadem-0.2.2/lunardem/geometry/planetary.py +9 -0
- lunadem-0.2.2/lunardem/geometry/scaling.py +28 -0
- lunadem-0.2.2/lunardem/geometry/surface.py +21 -0
- lunadem-0.2.2/lunardem/io/__init__.py +8 -0
- lunadem-0.2.2/lunardem/io/image.py +78 -0
- lunadem-0.2.2/lunardem/io/manifest.py +15 -0
- lunadem-0.2.2/lunardem/io/mesh.py +60 -0
- lunadem-0.2.2/lunardem/io/pds.py +51 -0
- lunadem-0.2.2/lunardem/io/raster.py +81 -0
- lunadem-0.2.2/lunardem/landing/__init__.py +6 -0
- lunadem-0.2.2/lunardem/landing/analysis.py +64 -0
- lunadem-0.2.2/lunardem/landing/suitability.py +86 -0
- lunadem-0.2.2/lunardem/methods/__init__.py +14 -0
- lunadem-0.2.2/lunardem/methods/base.py +33 -0
- lunadem-0.2.2/lunardem/methods/hybrid.py +52 -0
- lunadem-0.2.2/lunardem/methods/ml_models.py +49 -0
- lunadem-0.2.2/lunardem/methods/multiscale.py +68 -0
- lunadem-0.2.2/lunardem/methods/sfs.py +148 -0
- lunadem-0.2.2/lunardem/utils/__init__.py +7 -0
- lunadem-0.2.2/lunardem/utils/arrays.py +26 -0
- lunadem-0.2.2/lunardem/utils/config.py +30 -0
- lunadem-0.2.2/lunardem/utils/files.py +12 -0
- lunadem-0.2.2/lunardem/utils/logging.py +18 -0
- lunadem-0.2.2/lunardem/visualization/__init__.py +5 -0
- lunadem-0.2.2/lunardem/visualization/plots.py +58 -0
- lunadem-0.2.2/pyproject.toml +136 -0
- lunadem-0.2.2/setup.py +97 -0
- lunadem-0.2.2/sfs_photoclinometry/__init__.py +8 -0
- lunadem-0.2.2/sfs_photoclinometry/core.py +46 -0
- lunadem-0.2.2/sfs_photoclinometry/io_handler.py +38 -0
- lunadem-0.2.2/sfs_photoclinometry/utils.py +15 -0
- lunadem-0.2.2/sfs_photoclinometry/visualization.py +10 -0
lunadem-0.2.2/.gitignore
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Bytecode and build outputs
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.so
|
|
5
|
+
*.pyd
|
|
6
|
+
*.egg-info/
|
|
7
|
+
.pytest_cache/
|
|
8
|
+
.mypy_cache/
|
|
9
|
+
.ruff_cache/
|
|
10
|
+
dist/
|
|
11
|
+
build/
|
|
12
|
+
japneet.jpeg
|
|
13
|
+
fun.mp3
|
|
14
|
+
noor.mp4
|
|
15
|
+
v2.md
|
|
16
|
+
# Virtual environments
|
|
17
|
+
.venv/
|
|
18
|
+
venv/
|
|
19
|
+
|
|
20
|
+
# Demo and generated outputs
|
|
21
|
+
output/
|
|
22
|
+
uploads/
|
|
23
|
+
static/outputs/
|
|
24
|
+
*.obj
|
|
25
|
+
*.ply
|
|
26
|
+
*.tif
|
|
27
|
+
*.tiff
|
|
28
|
+
|
|
29
|
+
# Local docs not intended for GitHub
|
|
30
|
+
upload.md
|
|
31
|
+
explain.md
|
|
32
|
+
new_func.md
|
|
33
|
+
*.readme
|
|
34
|
+
*readme*.md
|
|
35
|
+
!README.md
|
|
36
|
+
|
|
37
|
+
# Local IDE artifacts
|
|
38
|
+
.vscode/
|
|
39
|
+
.idea/
|
|
40
|
+
tempCodeRunnerFile.py
|
lunadem-0.2.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 LunarDEM Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
lunadem-0.2.2/PKG-INFO
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lunadem
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Production-ready DEM generation toolkit for lunar and planetary imagery.
|
|
5
|
+
Project-URL: Homepage, https://github.com/Kartavya728/Generation-of-High-resolution-Digital-Elevation-Model-from-Lunar-Images-using-Photoclinometry
|
|
6
|
+
Project-URL: Repository, https://github.com/Kartavya728/Generation-of-High-resolution-Digital-Elevation-Model-from-Lunar-Images-using-Photoclinometry
|
|
7
|
+
Project-URL: Documentation, https://github.com/Kartavya728/Generation-of-High-resolution-Digital-Elevation-Model-from-Lunar-Images-using-Photoclinometry/tree/main/docs
|
|
8
|
+
Project-URL: Issues, https://github.com/Kartavya728/Generation-of-High-resolution-Digital-Elevation-Model-from-Lunar-Images-using-Photoclinometry/issues
|
|
9
|
+
Author-email: kartavya suryawanshi <kartavya.xenon@gmail.com>
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 LunarDEM Contributors
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Keywords: dem,geospatial,lunar,photoclinometry,planetary,shape-from-shading
|
|
33
|
+
Classifier: Development Status :: 3 - Alpha
|
|
34
|
+
Classifier: Intended Audience :: Science/Research
|
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
41
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
42
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
43
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
44
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
45
|
+
Requires-Python: >=3.8
|
|
46
|
+
Requires-Dist: imageio-ffmpeg>=0.5
|
|
47
|
+
Requires-Dist: imageio>=2.34
|
|
48
|
+
Requires-Dist: matplotlib>=3.8
|
|
49
|
+
Requires-Dist: numpy>=1.24
|
|
50
|
+
Requires-Dist: pydantic>=2.8
|
|
51
|
+
Requires-Dist: pygame>=2.6
|
|
52
|
+
Requires-Dist: pyyaml>=6.0
|
|
53
|
+
Requires-Dist: rasterio>=1.3
|
|
54
|
+
Requires-Dist: scipy>=1.10
|
|
55
|
+
Requires-Dist: typer>=0.12
|
|
56
|
+
Provides-Extra: dev
|
|
57
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
58
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
59
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
60
|
+
Requires-Dist: pytest>=8.2; extra == 'dev'
|
|
61
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
62
|
+
Requires-Dist: twine>=5.1; extra == 'dev'
|
|
63
|
+
Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
|
|
64
|
+
Requires-Dist: wheel>=0.45; extra == 'dev'
|
|
65
|
+
Provides-Extra: docs
|
|
66
|
+
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
|
|
67
|
+
Requires-Dist: mkdocs>=1.6; extra == 'docs'
|
|
68
|
+
Requires-Dist: mkdocstrings[python]>=0.25; extra == 'docs'
|
|
69
|
+
Provides-Extra: ml
|
|
70
|
+
Requires-Dist: torch>=2.2; extra == 'ml'
|
|
71
|
+
Provides-Extra: pds
|
|
72
|
+
Requires-Dist: pvl>=1.3; extra == 'pds'
|
|
73
|
+
Provides-Extra: viz
|
|
74
|
+
Requires-Dist: matplotlib>=3.8; extra == 'viz'
|
|
75
|
+
Description-Content-Type: text/markdown
|
|
76
|
+
|
|
77
|
+
# lunadem
|
|
78
|
+
|
|
79
|
+
`lunadem` is a Python library for generating and analyzing Digital Elevation Models (DEM) from lunar and planetary images.
|
|
80
|
+
|
|
81
|
+
PyPI project page:
|
|
82
|
+
|
|
83
|
+
https://pypi.org/project/lunadem/
|
|
84
|
+
|
|
85
|
+
## Install
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install lunadem
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Note: in code, the module import is `lunardem`.
|
|
92
|
+
|
|
93
|
+
CLI commands are available as both `lunadem` and `lunardem`.
|
|
94
|
+
|
|
95
|
+
## Main Capabilities
|
|
96
|
+
|
|
97
|
+
- DEM generation from image input (PNG, JPG, TIFF, GeoTIFF)
|
|
98
|
+
- Multiple methods: `sfs`, `multiscale_sfs`, `ml`, `hybrid`
|
|
99
|
+
- Terrain analytics: slope, roughness, curvature, elevation statistics, histogram summaries
|
|
100
|
+
- Landing suitability: safe/unsafe masks, hazard filtering, score and safe-area summary
|
|
101
|
+
- Exports: GeoTIFF DEM, OBJ/PLY mesh, visualization images, JSON run manifest
|
|
102
|
+
|
|
103
|
+
## Core Functions (Python API)
|
|
104
|
+
|
|
105
|
+
- `generate_dem(input_data, method, config) -> DEMResult`
|
|
106
|
+
- `analyze_dem(dem_or_path, analysis_config) -> TerrainMetrics`
|
|
107
|
+
- `assess_landing(dem_or_path, landing_config) -> LandingReport`
|
|
108
|
+
|
|
109
|
+
## Quick API Example
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
from lunardem import ReconstructionConfig, generate_dem
|
|
113
|
+
|
|
114
|
+
cfg = ReconstructionConfig(
|
|
115
|
+
output={"output_dir": "output", "base_name": "moon_run"},
|
|
116
|
+
)
|
|
117
|
+
result = generate_dem("data/moon1.png", method="multiscale_sfs", config=cfg)
|
|
118
|
+
print(result.exports)
|
|
119
|
+
print(result.metrics.stats)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## CLI Usage
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
lunadem generate data/moon1.png --method sfs --output output
|
|
126
|
+
lunadem analyze output/reconstructed_dem.tif
|
|
127
|
+
lunadem landing output/reconstructed_dem.tif --spacecraft examples/configs/landing.yaml
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Web App Usage
|
|
131
|
+
|
|
132
|
+
Web app is provided as a demo in:
|
|
133
|
+
|
|
134
|
+
`examples/webapp/app.py`
|
|
135
|
+
|
|
136
|
+
Run:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
python examples/webapp/app.py
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Then open:
|
|
143
|
+
|
|
144
|
+
`http://127.0.0.1:5000/`
|
|
145
|
+
|
|
146
|
+
Endpoints:
|
|
147
|
+
|
|
148
|
+
- `GET /` health message
|
|
149
|
+
- `POST /generate` image upload + DEM generation response
|
|
150
|
+
|
|
151
|
+
## Optional Extras
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
pip install "lunadem[viz]"
|
|
155
|
+
pip install "lunadem[ml]"
|
|
156
|
+
pip install "lunadem[pds]"
|
|
157
|
+
pip install "lunadem[docs]"
|
|
158
|
+
pip install "lunadem[dev]"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT License. See [LICENSE](LICENSE).
|
lunadem-0.2.2/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# lunadem
|
|
2
|
+
|
|
3
|
+
`lunadem` is a Python library for generating and analyzing Digital Elevation Models (DEM) from lunar and planetary images.
|
|
4
|
+
|
|
5
|
+
PyPI project page:
|
|
6
|
+
|
|
7
|
+
https://pypi.org/project/lunadem/
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install lunadem
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Note: in code, the module import is `lunardem`.
|
|
16
|
+
|
|
17
|
+
CLI commands are available as both `lunadem` and `lunardem`.
|
|
18
|
+
|
|
19
|
+
## Main Capabilities
|
|
20
|
+
|
|
21
|
+
- DEM generation from image input (PNG, JPG, TIFF, GeoTIFF)
|
|
22
|
+
- Multiple methods: `sfs`, `multiscale_sfs`, `ml`, `hybrid`
|
|
23
|
+
- Terrain analytics: slope, roughness, curvature, elevation statistics, histogram summaries
|
|
24
|
+
- Landing suitability: safe/unsafe masks, hazard filtering, score and safe-area summary
|
|
25
|
+
- Exports: GeoTIFF DEM, OBJ/PLY mesh, visualization images, JSON run manifest
|
|
26
|
+
|
|
27
|
+
## Core Functions (Python API)
|
|
28
|
+
|
|
29
|
+
- `generate_dem(input_data, method, config) -> DEMResult`
|
|
30
|
+
- `analyze_dem(dem_or_path, analysis_config) -> TerrainMetrics`
|
|
31
|
+
- `assess_landing(dem_or_path, landing_config) -> LandingReport`
|
|
32
|
+
|
|
33
|
+
## Quick API Example
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from lunardem import ReconstructionConfig, generate_dem
|
|
37
|
+
|
|
38
|
+
cfg = ReconstructionConfig(
|
|
39
|
+
output={"output_dir": "output", "base_name": "moon_run"},
|
|
40
|
+
)
|
|
41
|
+
result = generate_dem("data/moon1.png", method="multiscale_sfs", config=cfg)
|
|
42
|
+
print(result.exports)
|
|
43
|
+
print(result.metrics.stats)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## CLI Usage
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
lunadem generate data/moon1.png --method sfs --output output
|
|
50
|
+
lunadem analyze output/reconstructed_dem.tif
|
|
51
|
+
lunadem landing output/reconstructed_dem.tif --spacecraft examples/configs/landing.yaml
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Web App Usage
|
|
55
|
+
|
|
56
|
+
Web app is provided as a demo in:
|
|
57
|
+
|
|
58
|
+
`examples/webapp/app.py`
|
|
59
|
+
|
|
60
|
+
Run:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
python examples/webapp/app.py
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Then open:
|
|
67
|
+
|
|
68
|
+
`http://127.0.0.1:5000/`
|
|
69
|
+
|
|
70
|
+
Endpoints:
|
|
71
|
+
|
|
72
|
+
- `GET /` health message
|
|
73
|
+
- `POST /generate` image upload + DEM generation response
|
|
74
|
+
|
|
75
|
+
## Optional Extras
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pip install "lunadem[viz]"
|
|
79
|
+
pip install "lunadem[ml]"
|
|
80
|
+
pip install "lunadem[pds]"
|
|
81
|
+
pip install "lunadem[docs]"
|
|
82
|
+
pip install "lunadem[dev]"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
MIT License. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Legacy Flask Demo
|
|
2
|
+
|
|
3
|
+
This web app is provided as a non-core example.
|
|
4
|
+
|
|
5
|
+
For production usage, prefer:
|
|
6
|
+
|
|
7
|
+
- Python API (`lunardem.generate_dem`, `lunardem.analyze_dem`, `lunardem.assess_landing`)
|
|
8
|
+
- CLI (`lunardem generate`, `lunardem analyze`, `lunardem landing`)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""LunarDEM public package API."""
|
|
2
|
+
|
|
3
|
+
from lunardem.core.api import analyze_dem, assess_landing, generate_dem
|
|
4
|
+
from lunardem.core.config import (
|
|
5
|
+
AnalysisConfig,
|
|
6
|
+
GeoreferenceConfig,
|
|
7
|
+
HybridMethodConfig,
|
|
8
|
+
IlluminationConfig,
|
|
9
|
+
LandingConfig,
|
|
10
|
+
LandingConstraints,
|
|
11
|
+
MLMethodConfig,
|
|
12
|
+
OutputConfig,
|
|
13
|
+
PreprocessingConfig,
|
|
14
|
+
ReconstructionConfig,
|
|
15
|
+
SFSMethodConfig,
|
|
16
|
+
SensorConfig,
|
|
17
|
+
)
|
|
18
|
+
from lunardem.core.models import DEMResult, LandingReport, TerrainMetrics
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"AnalysisConfig",
|
|
22
|
+
"DEMResult",
|
|
23
|
+
"GeoreferenceConfig",
|
|
24
|
+
"HybridMethodConfig",
|
|
25
|
+
"IlluminationConfig",
|
|
26
|
+
"LandingConfig",
|
|
27
|
+
"LandingConstraints",
|
|
28
|
+
"LandingReport",
|
|
29
|
+
"MLMethodConfig",
|
|
30
|
+
"OutputConfig",
|
|
31
|
+
"PreprocessingConfig",
|
|
32
|
+
"ReconstructionConfig",
|
|
33
|
+
"SFSMethodConfig",
|
|
34
|
+
"SensorConfig",
|
|
35
|
+
"TerrainMetrics",
|
|
36
|
+
"analyze_dem",
|
|
37
|
+
"assess_landing",
|
|
38
|
+
"generate_dem",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
__version__ = "0.2.2"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
"""Command-line interface for LunarDEM."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
import sys
|
|
9
|
+
import threading
|
|
10
|
+
import time
|
|
11
|
+
from typing import Any, Dict, Optional
|
|
12
|
+
|
|
13
|
+
import typer
|
|
14
|
+
|
|
15
|
+
from lunardem import __version__, analyze_dem, assess_landing, generate_dem
|
|
16
|
+
from lunardem.core.config import AnalysisConfig, LandingConfig, ReconstructionConfig
|
|
17
|
+
from lunardem.utils.config import load_config_file
|
|
18
|
+
|
|
19
|
+
app = typer.Typer(help="LunarDEM CLI for DEM generation, analytics, and landing suitability.")
|
|
20
|
+
PYPI_PROJECT_URL = "https://pypi.org/project/lunadem/"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _merge_overrides(base: Dict[str, Any], updates: Dict[str, Any]) -> Dict[str, Any]:
|
|
24
|
+
merged = dict(base)
|
|
25
|
+
for key, value in updates.items():
|
|
26
|
+
if isinstance(value, dict) and isinstance(merged.get(key), dict):
|
|
27
|
+
merged[key] = _merge_overrides(merged[key], value)
|
|
28
|
+
else:
|
|
29
|
+
merged[key] = value
|
|
30
|
+
return merged
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _resolve_asset(filename: str) -> Path:
|
|
34
|
+
asset = Path(__file__).resolve().parent / "assets" / filename
|
|
35
|
+
if asset.exists():
|
|
36
|
+
return asset
|
|
37
|
+
raise FileNotFoundError(
|
|
38
|
+
f"Required packaged media file missing: {filename}. "
|
|
39
|
+
"Reinstall package to ensure assets are bundled."
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _play_fun_audio(repeat_count: int) -> None:
|
|
44
|
+
try:
|
|
45
|
+
import pygame
|
|
46
|
+
except ImportError as exc:
|
|
47
|
+
raise RuntimeError("pygame is required for internal audio playback.") from exc
|
|
48
|
+
|
|
49
|
+
if repeat_count <= 0:
|
|
50
|
+
raise ValueError("Repeat count must be >= 1.")
|
|
51
|
+
media = _resolve_asset("fun.mp3")
|
|
52
|
+
|
|
53
|
+
pygame.mixer.init()
|
|
54
|
+
try:
|
|
55
|
+
for _ in range(repeat_count):
|
|
56
|
+
pygame.mixer.music.load(str(media))
|
|
57
|
+
pygame.mixer.music.play()
|
|
58
|
+
while pygame.mixer.music.get_busy():
|
|
59
|
+
time.sleep(0.1)
|
|
60
|
+
finally:
|
|
61
|
+
pygame.mixer.music.stop()
|
|
62
|
+
pygame.mixer.quit()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _show_babies_image(block: bool = True) -> None:
|
|
66
|
+
import imageio.v2 as imageio
|
|
67
|
+
import matplotlib.pyplot as plt
|
|
68
|
+
|
|
69
|
+
image = imageio.imread(_resolve_asset("japneet.jpeg"))
|
|
70
|
+
fig, ax = plt.subplots(num="babies")
|
|
71
|
+
ax.imshow(image)
|
|
72
|
+
ax.set_title("babies")
|
|
73
|
+
ax.axis("off")
|
|
74
|
+
plt.tight_layout()
|
|
75
|
+
if block:
|
|
76
|
+
plt.show()
|
|
77
|
+
else:
|
|
78
|
+
plt.show(block=False)
|
|
79
|
+
plt.pause(0.1)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _show_noor_video(block: bool = True) -> None:
|
|
83
|
+
import imageio.v2 as imageio
|
|
84
|
+
import matplotlib.pyplot as plt
|
|
85
|
+
|
|
86
|
+
video_path = _resolve_asset("noor.mp4")
|
|
87
|
+
reader = imageio.get_reader(video_path)
|
|
88
|
+
metadata = reader.get_meta_data()
|
|
89
|
+
fps = float(metadata.get("fps", 24.0))
|
|
90
|
+
frame_delay = 1.0 / max(fps, 1.0)
|
|
91
|
+
|
|
92
|
+
fig, ax = plt.subplots(num="noor")
|
|
93
|
+
ax.axis("off")
|
|
94
|
+
frame_iter = iter(reader)
|
|
95
|
+
first_frame = next(frame_iter)
|
|
96
|
+
image_plot = ax.imshow(first_frame)
|
|
97
|
+
ax.set_title("noor")
|
|
98
|
+
plt.tight_layout()
|
|
99
|
+
plt.show(block=False)
|
|
100
|
+
plt.pause(0.1)
|
|
101
|
+
|
|
102
|
+
for frame in frame_iter:
|
|
103
|
+
image_plot.set_data(frame)
|
|
104
|
+
plt.pause(frame_delay)
|
|
105
|
+
|
|
106
|
+
reader.close()
|
|
107
|
+
if block:
|
|
108
|
+
plt.show()
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@app.command("generate")
|
|
112
|
+
def generate_command(
|
|
113
|
+
input_path: Path = typer.Argument(..., exists=True, help="Input image path."),
|
|
114
|
+
method: str = typer.Option("sfs", "--method", "-m", help="Method: sfs, multiscale_sfs, ml, hybrid."),
|
|
115
|
+
output: Path = typer.Option(Path("output"), "--output", "-o", help="Output directory."),
|
|
116
|
+
config: Optional[Path] = typer.Option(None, "--config", "-c", help="JSON or YAML config file."),
|
|
117
|
+
) -> None:
|
|
118
|
+
"""Generate DEM from an image."""
|
|
119
|
+
cfg_data: Dict[str, Any] = {}
|
|
120
|
+
if config is not None:
|
|
121
|
+
cfg_data = load_config_file(config)
|
|
122
|
+
|
|
123
|
+
cfg_data = _merge_overrides(
|
|
124
|
+
cfg_data,
|
|
125
|
+
{
|
|
126
|
+
"output": {
|
|
127
|
+
"output_dir": str(output),
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
)
|
|
131
|
+
reconstruction_config = ReconstructionConfig.model_validate(cfg_data)
|
|
132
|
+
result = generate_dem(input_data=input_path, method=method, config=reconstruction_config)
|
|
133
|
+
|
|
134
|
+
payload = {
|
|
135
|
+
"method": result.method,
|
|
136
|
+
"pixel_scale_m": result.pixel_scale_m,
|
|
137
|
+
"crs": result.crs,
|
|
138
|
+
"exports": result.exports,
|
|
139
|
+
"diagnostics": result.diagnostics,
|
|
140
|
+
"stats": result.metrics.stats if result.metrics else {},
|
|
141
|
+
}
|
|
142
|
+
typer.echo(json.dumps(payload, indent=2))
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@app.command("analyze")
|
|
146
|
+
def analyze_command(
|
|
147
|
+
dem_path: Path = typer.Argument(..., exists=True, help="DEM path (.tif preferred)."),
|
|
148
|
+
config: Optional[Path] = typer.Option(None, "--config", "-c", help="JSON or YAML analysis config."),
|
|
149
|
+
) -> None:
|
|
150
|
+
"""Analyze DEM terrain metrics."""
|
|
151
|
+
cfg = AnalysisConfig()
|
|
152
|
+
if config is not None:
|
|
153
|
+
cfg = AnalysisConfig.model_validate(load_config_file(config))
|
|
154
|
+
metrics = analyze_dem(dem_or_path=dem_path, analysis_config=cfg)
|
|
155
|
+
payload = {
|
|
156
|
+
"stats": metrics.stats,
|
|
157
|
+
}
|
|
158
|
+
typer.echo(json.dumps(payload, indent=2))
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@app.command("landing")
|
|
162
|
+
def landing_command(
|
|
163
|
+
dem_path: Path = typer.Argument(..., exists=True, help="DEM path."),
|
|
164
|
+
spacecraft: Optional[Path] = typer.Option(
|
|
165
|
+
None,
|
|
166
|
+
"--spacecraft",
|
|
167
|
+
"-s",
|
|
168
|
+
help="Landing/spacecraft constraints config (JSON or YAML).",
|
|
169
|
+
),
|
|
170
|
+
) -> None:
|
|
171
|
+
"""Run landing suitability checks for a DEM."""
|
|
172
|
+
cfg = LandingConfig()
|
|
173
|
+
if spacecraft is not None:
|
|
174
|
+
cfg = LandingConfig.model_validate(load_config_file(spacecraft))
|
|
175
|
+
report = assess_landing(dem_or_path=dem_path, landing_config=cfg)
|
|
176
|
+
payload = {
|
|
177
|
+
"safe_fraction": report.safe_fraction,
|
|
178
|
+
"score": report.score,
|
|
179
|
+
"summary": report.summary,
|
|
180
|
+
}
|
|
181
|
+
typer.echo(json.dumps(payload, indent=2))
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _print_lunadem_terminal_docs() -> None:
|
|
185
|
+
try:
|
|
186
|
+
from rich.console import Console
|
|
187
|
+
from rich.panel import Panel
|
|
188
|
+
from rich.table import Table
|
|
189
|
+
|
|
190
|
+
console = Console()
|
|
191
|
+
console.print(
|
|
192
|
+
Panel.fit(
|
|
193
|
+
"[bold cyan]lunadem[/bold cyan] [white]-[/white] DEM Toolkit For Lunar And Planetary Imaging\n"
|
|
194
|
+
"[dim]API import name: lunardem[/dim]\n"
|
|
195
|
+
f"[dim]Installed version: {__version__}[/dim]\n"
|
|
196
|
+
f"[dim]PyPI: {PYPI_PROJECT_URL}[/dim]",
|
|
197
|
+
title="Library Overview",
|
|
198
|
+
border_style="blue",
|
|
199
|
+
)
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
capability_table = Table(title="Core Capabilities", show_header=True, header_style="bold magenta")
|
|
203
|
+
capability_table.add_column("Area", style="cyan", width=24)
|
|
204
|
+
capability_table.add_column("Details", style="white")
|
|
205
|
+
capability_table.add_row("DEM Methods", "sfs, multiscale_sfs, ml, hybrid")
|
|
206
|
+
capability_table.add_row("Analytics", "slope, roughness, curvature, histograms")
|
|
207
|
+
capability_table.add_row("Landing", "safe mask, hazard mask, score, safe fraction")
|
|
208
|
+
capability_table.add_row("Exports", "GeoTIFF, OBJ/PLY, plots, JSON manifest")
|
|
209
|
+
capability_table.add_row("Inputs", "PNG, JPG, TIFF, GeoTIFF, NumPy arrays")
|
|
210
|
+
console.print(capability_table)
|
|
211
|
+
|
|
212
|
+
command_table = Table(title="Primary CLI Commands", show_header=True, header_style="bold green")
|
|
213
|
+
command_table.add_column("Command", style="green", width=22)
|
|
214
|
+
command_table.add_column("Purpose", style="white")
|
|
215
|
+
command_table.add_row("lunadem generate", "Generate DEM from image input")
|
|
216
|
+
command_table.add_row("lunadem analyze", "Compute terrain statistics")
|
|
217
|
+
command_table.add_row("lunadem landing", "Run deterministic landing suitability checks")
|
|
218
|
+
console.print(command_table)
|
|
219
|
+
console.print("[dim]Alias also available:[/dim] [bold]lunardem[/bold]")
|
|
220
|
+
except Exception:
|
|
221
|
+
# Fallback for environments where rich cannot render.
|
|
222
|
+
print("lunadem - DEM Toolkit")
|
|
223
|
+
print(f"Installed version: {__version__}")
|
|
224
|
+
print(f"PyPI: {PYPI_PROJECT_URL}")
|
|
225
|
+
print("Methods: sfs, multiscale_sfs, ml, hybrid")
|
|
226
|
+
print("CLI: lunadem generate | lunadem analyze | lunadem landing")
|
|
227
|
+
print("Alias: lunardem")
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def lunadem_main() -> None:
|
|
231
|
+
"""Entry command for `lunadem` that shows docs or dispatches CLI commands."""
|
|
232
|
+
parser = argparse.ArgumentParser(prog="lunadem", add_help=False)
|
|
233
|
+
parser.add_argument("--version", action="store_true")
|
|
234
|
+
parser.add_argument("--docs", action="store_true")
|
|
235
|
+
known, remaining = parser.parse_known_args()
|
|
236
|
+
if known.version:
|
|
237
|
+
print(__version__)
|
|
238
|
+
return
|
|
239
|
+
if known.docs or (len(sys.argv) == 1 and not remaining):
|
|
240
|
+
_print_lunadem_terminal_docs()
|
|
241
|
+
return
|
|
242
|
+
app(prog_name="lunadem")
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def kartavya_main() -> None:
|
|
246
|
+
"""Fun command: play `fun.mp3` with optional repeats."""
|
|
247
|
+
parser = argparse.ArgumentParser(prog="kartavya", description="Play fun.mp3 on your device.")
|
|
248
|
+
parser.add_argument("-n", type=int, default=1, help="Number of times to play audio.")
|
|
249
|
+
args = parser.parse_args()
|
|
250
|
+
if args.n <= 0:
|
|
251
|
+
parser.error("-n must be >= 1")
|
|
252
|
+
_play_fun_audio(args.n)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def babies_main() -> None:
|
|
256
|
+
"""Fun command: open japneet.jpeg."""
|
|
257
|
+
_show_babies_image(block=True)
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def noor_main() -> None:
|
|
261
|
+
"""Fun command: play noor.mp4."""
|
|
262
|
+
_show_noor_video(block=True)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def overkill_main() -> None:
|
|
266
|
+
"""Fun command: run audio + image + video actions together."""
|
|
267
|
+
parser = argparse.ArgumentParser(prog="overkill", description="Run all fun actions together.")
|
|
268
|
+
parser.add_argument("-n", type=int, default=1, help="Number of times to play fun.mp3.")
|
|
269
|
+
args = parser.parse_args()
|
|
270
|
+
if args.n <= 0:
|
|
271
|
+
parser.error("-n must be >= 1")
|
|
272
|
+
|
|
273
|
+
audio_worker = threading.Thread(target=_play_fun_audio, args=(args.n,), daemon=True)
|
|
274
|
+
audio_worker.start()
|
|
275
|
+
_show_babies_image(block=False)
|
|
276
|
+
_show_noor_video(block=True)
|
|
277
|
+
audio_worker.join()
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def main() -> None:
|
|
281
|
+
"""CLI entrypoint for console scripts."""
|
|
282
|
+
app(prog_name="lunardem")
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
if __name__ == "__main__":
|
|
286
|
+
main()
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Core API, configuration, and method registry."""
|
|
2
|
+
|
|
3
|
+
from lunardem.core.api import analyze_dem, assess_landing, generate_dem
|
|
4
|
+
from lunardem.core.config import (
|
|
5
|
+
AnalysisConfig,
|
|
6
|
+
GeoreferenceConfig,
|
|
7
|
+
HybridMethodConfig,
|
|
8
|
+
IlluminationConfig,
|
|
9
|
+
LandingConfig,
|
|
10
|
+
LandingConstraints,
|
|
11
|
+
MLMethodConfig,
|
|
12
|
+
OutputConfig,
|
|
13
|
+
PreprocessingConfig,
|
|
14
|
+
ReconstructionConfig,
|
|
15
|
+
SFSMethodConfig,
|
|
16
|
+
SensorConfig,
|
|
17
|
+
)
|
|
18
|
+
from lunardem.core.models import DEMResult, LandingReport, TerrainMetrics
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"AnalysisConfig",
|
|
22
|
+
"DEMResult",
|
|
23
|
+
"GeoreferenceConfig",
|
|
24
|
+
"HybridMethodConfig",
|
|
25
|
+
"IlluminationConfig",
|
|
26
|
+
"LandingConfig",
|
|
27
|
+
"LandingConstraints",
|
|
28
|
+
"LandingReport",
|
|
29
|
+
"MLMethodConfig",
|
|
30
|
+
"OutputConfig",
|
|
31
|
+
"PreprocessingConfig",
|
|
32
|
+
"ReconstructionConfig",
|
|
33
|
+
"SFSMethodConfig",
|
|
34
|
+
"SensorConfig",
|
|
35
|
+
"TerrainMetrics",
|
|
36
|
+
"analyze_dem",
|
|
37
|
+
"assess_landing",
|
|
38
|
+
"generate_dem",
|
|
39
|
+
]
|