reconstruct3d 0.1.0__py3-none-any.whl
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.
- reconstruct3d/__init__.py +17 -0
- reconstruct3d/api.py +218 -0
- reconstruct3d/bundle_adjust.py +370 -0
- reconstruct3d/calibrate.py +199 -0
- reconstruct3d/cgal_mesh/CMakeLists.txt +22 -0
- reconstruct3d/cgal_mesh/mesh_reconstruct.cpp +312 -0
- reconstruct3d/chunked.py +335 -0
- reconstruct3d/cli.py +448 -0
- reconstruct3d/core.py +515 -0
- reconstruct3d/dense_mvs.py +256 -0
- reconstruct3d/init_sfm.py +151 -0
- reconstruct3d/mesh.py +99 -0
- reconstruct3d/track_sfm.py +253 -0
- reconstruct3d/viewer.py +108 -0
- reconstruct3d-0.1.0.dist-info/METADATA +416 -0
- reconstruct3d-0.1.0.dist-info/RECORD +19 -0
- reconstruct3d-0.1.0.dist-info/WHEEL +4 -0
- reconstruct3d-0.1.0.dist-info/entry_points.txt +2 -0
- reconstruct3d-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: reconstruct3d
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Pipeline offline de reconstrucción 3D desde video monocular: Structure-from-Motion incremental + Bundle Adjustment + densificación MVS + mallado CGAL, con front-ends de features intercambiables (SIFT, ORB, SuperPoint+LightGlue).
|
|
5
|
+
Project-URL: Homepage, https://github.com/FernandoUs/Template-SLAM
|
|
6
|
+
Project-URL: Repository, https://github.com/FernandoUs/Template-SLAM
|
|
7
|
+
Project-URL: Issues, https://github.com/FernandoUs/Template-SLAM/issues
|
|
8
|
+
Author-email: BlackMonkcr <aaron.navarro@utec.edu.pe>
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: 3d-reconstruction,bundle-adjustment,cgal,computer-vision,mvs,opencv,photogrammetry,point-cloud,sfm,structure-from-motion
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Image Recognition
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: numpy>=1.26
|
|
22
|
+
Requires-Dist: opencv-contrib-python>=4.8
|
|
23
|
+
Requires-Dist: pandas>=2.0
|
|
24
|
+
Requires-Dist: scipy>=1.11
|
|
25
|
+
Requires-Dist: tqdm>=4.66
|
|
26
|
+
Provides-Extra: api
|
|
27
|
+
Requires-Dist: fastapi>=0.110; extra == 'api'
|
|
28
|
+
Requires-Dist: httpx>=0.27; extra == 'api'
|
|
29
|
+
Requires-Dist: python-multipart>=0.0.9; extra == 'api'
|
|
30
|
+
Requires-Dist: uvicorn[standard]>=0.27; extra == 'api'
|
|
31
|
+
Provides-Extra: spglue
|
|
32
|
+
Requires-Dist: lightglue; extra == 'spglue'
|
|
33
|
+
Requires-Dist: torch>=2.2; extra == 'spglue'
|
|
34
|
+
Requires-Dist: torchvision>=0.17; extra == 'spglue'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# Pipeline de Reconstrucción 3D (SfM offline + Densificación MVS)
|
|
38
|
+
|
|
39
|
+
Pipeline **offline** que reconstruye una escena 3D a partir de un **video
|
|
40
|
+
monocular**: estima la trayectoria de la cámara mediante Structure-from-Motion
|
|
41
|
+
(SfM) incremental, refina con Bundle Adjustment y genera una nube de puntos
|
|
42
|
+
—primero rala (*sparse*) y luego densa (*dense*)—.
|
|
43
|
+
|
|
44
|
+
> **Nota sobre el nombre:** aunque el repo se llama "Template-SLAM", esto es SfM
|
|
45
|
+
> offline + densificación MVS, **no SLAM en tiempo real**. No hay loop-closure ni
|
|
46
|
+
> mapeo online. Ver [CLAUDE.md](CLAUDE.md) para el detalle técnico.
|
|
47
|
+
|
|
48
|
+
## Características
|
|
49
|
+
|
|
50
|
+
- **3 front-ends de features intercambiables:**
|
|
51
|
+
- `sift` (default) — SIFT + BFMatcher (L2). Solo CPU, sin dependencias pesadas.
|
|
52
|
+
- `orb` — ORB + BFMatcher (Hamming). Más rápido, menos preciso.
|
|
53
|
+
- `spglue` — SuperPoint + **LightGlue** (deep learning, CPU/GPU). Opcional,
|
|
54
|
+
requiere `torch`.
|
|
55
|
+
- **Bundle Adjustment** local (por ventana, durante el tracking) y global.
|
|
56
|
+
- **Densificación MVS-lite** por stereo de dos vistas (StereoSGBM) con fusión
|
|
57
|
+
multi-vista.
|
|
58
|
+
- **Mallado con CGAL** ([cgal_mesh/](cgal_mesh/)) — reconstruye una malla
|
|
59
|
+
triangulada desde la nube densa (Advancing Front o Poisson).
|
|
60
|
+
- **Visor POV interactivo** que proyecta los puntos 3D sobre el video original.
|
|
61
|
+
- **Orquestador único** ([pipeline.py](pipeline.py)) — todo el pipeline en un
|
|
62
|
+
solo comando.
|
|
63
|
+
- **Calibración desde video** ([calibrate.py](calibrate.py)) — estima `K` de tu
|
|
64
|
+
dispositivo a partir de un video de un tablero de ajedrez y crea/actualiza
|
|
65
|
+
`camera.json`.
|
|
66
|
+
- **Paralelización** (`--jobs`) en extracción, matching y densificación.
|
|
67
|
+
- **Reconstrucción por chunks** ([chunked.py](chunked.py)) — para videos largos:
|
|
68
|
+
parte el video en fragmentos solapados, los reconstruye en paralelo y fusiona
|
|
69
|
+
las nubes alineándolas por el solape (similaridad Sim(3)).
|
|
70
|
+
|
|
71
|
+
## Requisitos
|
|
72
|
+
|
|
73
|
+
- **[uv](https://docs.astral.sh/uv/)** para gestionar el entorno y dependencias.
|
|
74
|
+
- Python ≥ 3.10 (uv lo instala automáticamente según `.python-version`).
|
|
75
|
+
- **Solo para el mallado** (`mesh`): dependencias nativas de CGAL (no las instala
|
|
76
|
+
uv). En macOS: `brew install cgal cmake eigen boost gmp mpfr`. En Debian/Ubuntu:
|
|
77
|
+
`sudo apt install libcgal-dev cmake libeigen3-dev`. El resto del pipeline
|
|
78
|
+
funciona sin ellas.
|
|
79
|
+
|
|
80
|
+
## Instalación
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Dependencias base (front-ends sift / orb):
|
|
84
|
+
uv sync
|
|
85
|
+
|
|
86
|
+
# Opcional: front-end spglue (SuperPoint + LightGlue, instala torch):
|
|
87
|
+
uv sync --extra spglue
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`uv` crea el entorno virtual, **instala el paquete `reconstruct3d`** (editable) y
|
|
91
|
+
resuelve todo desde `pyproject.toml`. No hace falta activar nada: usa
|
|
92
|
+
`uv run <comando>`. Queda disponible el CLI instalado `reconstruct3d` (equivalente
|
|
93
|
+
al shim `python pipeline.py`).
|
|
94
|
+
|
|
95
|
+
## Uso como librería (API Python)
|
|
96
|
+
|
|
97
|
+
El pipeline se puede usar desde código con la clase `Pipeline`:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from reconstruct3d import Pipeline
|
|
101
|
+
|
|
102
|
+
pipe = Pipeline("outputs/run1", frontend="sift", camera="camera.json", jobs=0)
|
|
103
|
+
pipe.extract("video.mp4", k_skip=15, m_window=4)
|
|
104
|
+
pipe.init()
|
|
105
|
+
pipe.track()
|
|
106
|
+
pipe.bundle_adjust()
|
|
107
|
+
pipe.dense("video.mp4")
|
|
108
|
+
pipe.mesh(method="afront")
|
|
109
|
+
print(pipe.artifacts()) # {'extract': '.../sfm_data.pkl', 'dense': '.../dense_cloud.ply', ...}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
O todo de una vez, eligiendo etapas y recibiendo progreso por callback:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from reconstruct3d import Pipeline
|
|
116
|
+
|
|
117
|
+
def on_event(ev): # ev = {stage, status, message, ...}
|
|
118
|
+
print(ev["stage"], ev["status"])
|
|
119
|
+
|
|
120
|
+
pipe = Pipeline("outputs/run1", on_event=on_event)
|
|
121
|
+
pipe.run("video.mp4",
|
|
122
|
+
stages=["extract", "init", "track", "dense"],
|
|
123
|
+
config={"extract": {"k_skip": 15, "m_window": 4}})
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Atajo: `reconstruct3d.run_all(video, out_dir, stages=..., config=...)`.
|
|
127
|
+
|
|
128
|
+
## Uso rápido (CLI)
|
|
129
|
+
|
|
130
|
+
Coloca tu video en `data/` y ejecuta el pipeline completo:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
uv run reconstruct3d all data/mi_video.mp4 # o: uv run python pipeline.py all ...
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Esto encadena: **extract → init → track → ba → dense → mesh**. Los artefactos
|
|
137
|
+
quedan en `outputs/sift/` (o `outputs/<frontend>/`). El mallado se omite
|
|
138
|
+
automáticamente si CGAL no está instalado (o con `--no-mesh`).
|
|
139
|
+
|
|
140
|
+
Con otro front-end, o saltando etapas:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
uv run python pipeline.py all data/mi_video.mp4 --frontend spglue
|
|
144
|
+
uv run python pipeline.py all data/mi_video.mp4 --no-ba --no-dense # solo sparse
|
|
145
|
+
uv run python pipeline.py all data/mi_video.mp4 --view # abre el visor al final
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Cámara / calibración (por dispositivo)
|
|
149
|
+
|
|
150
|
+
La matriz intrínseca `K` **depende del dispositivo con el que grabaste**, así que
|
|
151
|
+
es configurable. Copia [camera.example.json](camera.example.json), ajústalo a tu
|
|
152
|
+
cámara y pásalo en `extract` (o en `all`):
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
uv run python pipeline.py all data/mi_video.mp4 --camera camera.json
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
La config se **persiste** en `sfm_data.pkl` y `map_state.npy` y se **propaga
|
|
159
|
+
automáticamente** a todas las etapas — solo la indicas una vez. Sin `--camera`,
|
|
160
|
+
se usan los valores por defecto (iPhone @ 540×960).
|
|
161
|
+
|
|
162
|
+
Formato del JSON (atajo `fx/fy/cx/cy`, o matriz `K` completa):
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"fx": 801.25, "fy": 801.25, "cx": 188.67, "cy": 390.22,
|
|
167
|
+
"width": 540, "height": 960,
|
|
168
|
+
"dist_coeffs": [0, 0, 0, 0, 0]
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
`width`/`height` es la resolución a la que `K` está calibrada: el video se
|
|
173
|
+
redimensiona a ese tamaño antes de extraer features. Si das `fx/fy/cx/cy`, deben
|
|
174
|
+
corresponder a esa resolución.
|
|
175
|
+
|
|
176
|
+
### Calibrar K automáticamente desde un video
|
|
177
|
+
|
|
178
|
+
Si no conoces `K`, grábala: graba un video moviendo un **tablero de ajedrez**
|
|
179
|
+
frente a la cámara (cubriendo zonas y ángulos) y calibra:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# Genera/actualiza camera.json (tablero de 9x6 esquinas internas):
|
|
183
|
+
uv run python pipeline.py calibrate data/calib.mp4 --board 9x6 --square 0.025
|
|
184
|
+
# Revisión manual de cada vista (ventana OpenCV):
|
|
185
|
+
uv run python pipeline.py calibrate data/calib.mp4 --interactive
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
También puedes calibrar **en el mismo comando** de reconstrucción, o dejar que el
|
|
189
|
+
pipeline lo haga solo:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# Calibra y luego reconstruye, en un paso:
|
|
193
|
+
uv run python pipeline.py all data/video.mp4 --calibrate data/calib.mp4
|
|
194
|
+
|
|
195
|
+
# Auto-detección: si no pasas --camera, el pipeline usa ./camera.json si existe,
|
|
196
|
+
# o busca un video con 'calib' en el nombre (en data/calib/, data/ o .) y calibra.
|
|
197
|
+
uv run python pipeline.py all data/video.mp4
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Calibrar fija `proc_size` a la resolución nativa del video de calibración, así que
|
|
201
|
+
el punto principal queda centrado y `K` siempre es coherente con la resolución.
|
|
202
|
+
|
|
203
|
+
## Paralelización (`--jobs`)
|
|
204
|
+
|
|
205
|
+
La extracción de features, el matching por pares y la densificación MVS están
|
|
206
|
+
paralelizados con hilos. Controla los hilos con `--jobs` (`0`=auto=nº de CPUs,
|
|
207
|
+
`1`=secuencial):
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
uv run python pipeline.py extract data/video.mp4 --jobs 8
|
|
211
|
+
uv run python pipeline.py dense data/video.mp4 --jobs 8
|
|
212
|
+
uv run python pipeline.py all data/video.mp4 --jobs 8
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Notas: los detectores de OpenCV no son thread-safe compartidos, así que cada hilo
|
|
216
|
+
usa su propia instancia (resultados **idénticos** al modo secuencial). Con
|
|
217
|
+
`--frontend spglue` el paralelismo se fuerza a 1 hilo (torch ya paraleliza
|
|
218
|
+
internamente y su modelo no es thread-safe).
|
|
219
|
+
|
|
220
|
+
## Videos largos: reconstrucción por chunks
|
|
221
|
+
|
|
222
|
+
Para videos largos, reconstruir todo de una vez es lento y acumula deriva. El modo
|
|
223
|
+
`chunked` parte el video en fragmentos **solapados**, reconstruye cada uno de forma
|
|
224
|
+
**independiente y en paralelo** (procesos), y fusiona las sub-nubes alineándolas
|
|
225
|
+
por los frames del solape (similaridad Sim(3) vía Umeyama sobre los centros de
|
|
226
|
+
cámara compartidos):
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
uv run python pipeline.py chunked data/video.mp4 \
|
|
230
|
+
--chunk 80 --overlap 20 --chunk-jobs 4
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
- `--chunk` / `--overlap`: tamaño y solape del fragmento, en frames muestreados.
|
|
234
|
+
El solape debe ser suficiente para alinear (≥4 frames; por defecto 20).
|
|
235
|
+
- `--chunk-jobs`: cuántos chunks se reconstruyen en paralelo (procesos).
|
|
236
|
+
- `--inner-jobs`: hilos de extracción dentro de cada chunk (default 1, para no
|
|
237
|
+
saturar al correr varios chunks a la vez).
|
|
238
|
+
|
|
239
|
+
Salida en `outputs/<frontend>/`: `merged_cloud.ply` (nube global) y
|
|
240
|
+
`merged_state.npy` (poses + puntos en el marco global, copiado también como
|
|
241
|
+
`map_state.npy` para poder lanzar `dense`/`view` sobre el resultado fusionado).
|
|
242
|
+
|
|
243
|
+
## Mallado de la nube (CGAL)
|
|
244
|
+
|
|
245
|
+
Convierte la nube densa en una **malla triangulada** con CGAL. Requiere las
|
|
246
|
+
dependencias nativas (ver *Requisitos*); el binario C++ se **compila solo** la
|
|
247
|
+
primera vez que se ejecuta.
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
uv run python pipeline.py mesh # usa outputs/sift/dense_cloud.ply
|
|
251
|
+
uv run python pipeline.py mesh outputs/sift/dense_cloud.ply # ruta explícita a la nube
|
|
252
|
+
uv run python pipeline.py mesh ruta/a/nube.ply --method poisson --smooth 24
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Puedes indicar la nube de entrada como **argumento posicional** (o con `--input`);
|
|
256
|
+
si no pasas `--out`, el `mesh.ply` se escribe en la carpeta de esa nube.
|
|
257
|
+
|
|
258
|
+
Dos métodos:
|
|
259
|
+
|
|
260
|
+
- **`afront`** (Advancing Front, default) — **interpola** los puntos de entrada,
|
|
261
|
+
conserva el color y respeta bordes abiertos. Ideal para superficies vistas de un
|
|
262
|
+
lado (fachadas). Fiel a la nube.
|
|
263
|
+
- **`poisson`** (Poisson screened) — superficie **suave y cerrada**, tolera mejor
|
|
264
|
+
el ruido pero puede "inflar" zonas abiertas. Estima normales y transfiere el
|
|
265
|
+
color por vecino más cercano.
|
|
266
|
+
|
|
267
|
+
### Mejorar la calidad (la nube tiene ruido)
|
|
268
|
+
|
|
269
|
+
Advancing Front **interpola** los puntos, así que el ruido se vuelve picos
|
|
270
|
+
("grumoso"). Para una malla más limpia hay tres palancas, aplicadas por defecto y
|
|
271
|
+
ajustables:
|
|
272
|
+
|
|
273
|
+
- **Limpiar la nube antes de mallar**: `--outlier-pct P` (elimina % de outliers),
|
|
274
|
+
`--simplify CELL` (rejilla; `0`=auto~2×spacing, coarsea→suaviza y acelera;
|
|
275
|
+
`<0`=sin simplificar para máximo detalle), `--smooth N` (suavizado jet de los
|
|
276
|
+
puntos con N vecinos).
|
|
277
|
+
- **Post-procesar la malla** (activo por defecto): `--mesh-smooth ITERS` (suavizado
|
|
278
|
+
tangencial que respeta bordes, default 2) y `--min-component FRAC` (elimina
|
|
279
|
+
componentes con menos de `FRAC×caras`, p.ej. islas de ruido flotantes,
|
|
280
|
+
default 0.002).
|
|
281
|
+
- **Cambiar de método**: `--method poisson` produce una superficie **suave y
|
|
282
|
+
cerrada** que tolera mucho mejor el ruido (a costa de "inflar" bordes abiertos).
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
# Más limpio (afront + suavizado fuerte + quitar islas):
|
|
286
|
+
uv run python pipeline.py mesh --mesh-smooth 5 --min-component 0.01 --smooth 12
|
|
287
|
+
# Superficie suave (Poisson):
|
|
288
|
+
uv run python pipeline.py mesh --method poisson --smooth 12
|
|
289
|
+
# Máximo detalle (sin simplificar ni suavizar):
|
|
290
|
+
uv run python pipeline.py mesh --simplify -1 --mesh-smooth 0 --min-component 0
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
La salida es `mesh.ply`, abrible en MeshLab/CloudCompare o cualquier visor de PLY.
|
|
294
|
+
|
|
295
|
+
## Uso por etapas
|
|
296
|
+
|
|
297
|
+
Las etapas comparten el mismo directorio de salida. Útil para iterar sobre una
|
|
298
|
+
etapa sin recalcular las anteriores:
|
|
299
|
+
|
|
300
|
+
| Etapa | Comando | Produce |
|
|
301
|
+
|---|---|---|
|
|
302
|
+
| 1. Extracción | `uv run python pipeline.py extract data/v.mp4` | `sfm_data.pkl` |
|
|
303
|
+
| 2. Inicialización | `uv run python pipeline.py init` | `map_state.npy`, `init_cloud.ply` |
|
|
304
|
+
| 3. Tracking (sparse) | `uv run python pipeline.py track` | `tracked_cloud.ply` |
|
|
305
|
+
| 4. Bundle Adjustment | `uv run python pipeline.py ba` | `map_state.npy` (refinado) |
|
|
306
|
+
| 5. Densificación | `uv run python pipeline.py dense data/v.mp4` | `dense_cloud.ply` |
|
|
307
|
+
| 6. Mallado (CGAL) | `uv run python pipeline.py mesh` | `mesh.ply` |
|
|
308
|
+
| 7. Visor | `uv run python pipeline.py view data/v.mp4` | (interactivo) |
|
|
309
|
+
|
|
310
|
+
Cada subcomando expone sus parámetros; consúltalos con `--help`:
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
uv run python pipeline.py extract --help
|
|
314
|
+
uv run python pipeline.py track --help
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Parámetros frecuentes:
|
|
318
|
+
|
|
319
|
+
- `extract --k-skip N` — procesa 1 de cada N frames (default 5).
|
|
320
|
+
- `extract --start-seconds S` — salta un arranque malo (rotación casi pura).
|
|
321
|
+
- `track --min-angle G` — ángulo mínimo de triangulación (descarta ruido de escala).
|
|
322
|
+
- `dense --min-views N` — conserva solo puntos confirmados por ≥N pares.
|
|
323
|
+
|
|
324
|
+
## Resultados
|
|
325
|
+
|
|
326
|
+
Las nubes `.ply` se abren en **MeshLab** o **CloudCompare**. El visor interactivo
|
|
327
|
+
proyecta los puntos sobre el video:
|
|
328
|
+
|
|
329
|
+
- Slider **Frame** — navega en el tiempo.
|
|
330
|
+
- Slider **Fondo %** — opacidad del video (0 = fondo negro, 100 = video normal).
|
|
331
|
+
- `q` o `ESC` — cerrar.
|
|
332
|
+
|
|
333
|
+
## Demo web (API + frontend)
|
|
334
|
+
|
|
335
|
+
Una demo de la librería: backend FastAPI que expone el pipeline por HTTP +
|
|
336
|
+
frontend Vite/React con **visor 3D** (Three.js) para subir un video, elegir las
|
|
337
|
+
etapas, ver el progreso y explorar la nube/malla resultante en el navegador.
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
# 1) Backend (instala FastAPI con el extra `api`):
|
|
341
|
+
uv sync --extra api
|
|
342
|
+
uv run uvicorn backend.app:app --reload --port 8000
|
|
343
|
+
|
|
344
|
+
# 2) Frontend (en otra terminal):
|
|
345
|
+
cd frontend
|
|
346
|
+
npm install
|
|
347
|
+
npm run dev # http://localhost:5173 (proxy /api -> :8000)
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Abre http://localhost:5173, sube un video, marca las etapas y pulsa
|
|
351
|
+
**Reconstruir**; al terminar, haz clic en un artefacto para verlo en 3D.
|
|
352
|
+
|
|
353
|
+
Endpoints principales del backend: `POST /api/jobs` (video + config),
|
|
354
|
+
`GET /api/jobs/{id}` (estado/progreso/eventos), `GET /api/jobs/{id}/artifacts/{name}`.
|
|
355
|
+
|
|
356
|
+
## Estructura del proyecto
|
|
357
|
+
|
|
358
|
+
```
|
|
359
|
+
reconstruct3d/ Paquete de la librería (instalable)
|
|
360
|
+
api.py API de alto nivel (clase Pipeline)
|
|
361
|
+
cli.py Orquestador CLI (subcomandos)
|
|
362
|
+
core.py Cámara, features, front-ends, base de datos SfM
|
|
363
|
+
init_sfm.py Par semilla + triangulación inicial
|
|
364
|
+
track_sfm.py Registro incremental PnP + BA local
|
|
365
|
+
bundle_adjust.py BA local (ventana) y global + fusión de puntos
|
|
366
|
+
dense_mvs.py Densificación stereo multi-vista
|
|
367
|
+
mesh.py Wrapper del mallado CGAL (compila y llama al binario)
|
|
368
|
+
calibrate.py Calibración de K desde un video de tablero
|
|
369
|
+
chunked.py Reconstrucción por chunks con solape + fusión
|
|
370
|
+
viewer.py Visor POV interactivo (OpenCV)
|
|
371
|
+
cgal_mesh/ Programa C++ CGAL (mesh_reconstruct.cpp + CMakeLists)
|
|
372
|
+
pipeline.py Shim de compatibilidad -> reconstruct3d.cli
|
|
373
|
+
backend/ Demo: API FastAPI (app.py)
|
|
374
|
+
frontend/ Demo: Vite + React + Three.js (visor 3D)
|
|
375
|
+
camera.example.json Plantilla de intrínsecos por dispositivo
|
|
376
|
+
pyproject.toml Paquete + dependencias (fuente de verdad)
|
|
377
|
+
data/ Videos de entrada (no versionados)
|
|
378
|
+
outputs/ Artefactos regenerables (no versionados)
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## Publicar en PyPI
|
|
382
|
+
|
|
383
|
+
El paquete está listo para publicarse (`twine check` PASSED; nombre `reconstruct3d`
|
|
384
|
+
libre). Pasos:
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
uv build # genera dist/*.whl y dist/*.tar.gz
|
|
388
|
+
uv run --with twine twine check dist/*
|
|
389
|
+
|
|
390
|
+
# Ensayo en TestPyPI (recomendado):
|
|
391
|
+
uv publish --publish-url https://test.pypi.org/legacy/ --token <TEST_PYPI_TOKEN>
|
|
392
|
+
|
|
393
|
+
# Publicación real:
|
|
394
|
+
uv publish --token <PYPI_TOKEN>
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
Notas para quien instale desde PyPI:
|
|
398
|
+
|
|
399
|
+
- `pip install reconstruct3d` trae los front-ends **SIFT/ORB** (sin torch).
|
|
400
|
+
- El front-end **spglue** (SuperPoint+LightGlue) requiere instalar LightGlue a
|
|
401
|
+
mano (no está en PyPI):
|
|
402
|
+
`pip install "reconstruct3d[spglue]"` y luego
|
|
403
|
+
`pip install "lightglue @ git+https://github.com/cvg/LightGlue.git"`.
|
|
404
|
+
- El paso **`mesh`** necesita CGAL nativo (CGAL + cmake + compilador); es opcional
|
|
405
|
+
y se compila bajo demanda. El resto del pipeline funciona sin él.
|
|
406
|
+
|
|
407
|
+
## Notas técnicas
|
|
408
|
+
|
|
409
|
+
- **Reset:** si el tracking se estanca, vuelve a correr `init` antes de reintentar.
|
|
410
|
+
- **Calibración:** los intrínsecos por defecto son de un iPhone @ 540×960. Para
|
|
411
|
+
otro dispositivo, pasa `--camera tu_camara.json` (ver sección *Cámara*). El
|
|
412
|
+
video se redimensiona a la resolución de calibración antes de extraer.
|
|
413
|
+
- **`req.txt`** queda como referencia histórica; la gestión real de dependencias
|
|
414
|
+
es `pyproject.toml` + `uv`.
|
|
415
|
+
|
|
416
|
+
Para contexto de arquitectura, convenciones y *gotchas*, ver **[CLAUDE.md](CLAUDE.md)**.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
reconstruct3d/__init__.py,sha256=_MTKAhDNA4uvxu-srxMYfLgSgDgM5frCci1SMfGSHEY,685
|
|
2
|
+
reconstruct3d/api.py,sha256=v57OzbwK0t1lGz1SDWNj2_m1AgsAs9iLbEjlr7OdM7o,9406
|
|
3
|
+
reconstruct3d/bundle_adjust.py,sha256=7IW4lx7PhsLXL6kh_Ibq2oyihdLQ-eBZsbzDlS6O04A,14831
|
|
4
|
+
reconstruct3d/calibrate.py,sha256=lG9xk2bEF05PCaT1flH8w5NGQqoUBCTLtysNyX7rUWE,8586
|
|
5
|
+
reconstruct3d/chunked.py,sha256=HuSRF49vpZ2KOoj4S0xQ0mwLXvjEedsdpVR7yi-b7rI,15672
|
|
6
|
+
reconstruct3d/cli.py,sha256=zMxcFe5NwpY5tZMEdBmXJXyPHgU4dGiLGOfzJMEo4Ag,21227
|
|
7
|
+
reconstruct3d/core.py,sha256=0aFS1SwZ6zBP67kBABFKsXLqnt9HyBEh2GuK5afz50w,21625
|
|
8
|
+
reconstruct3d/dense_mvs.py,sha256=w9K9GxDqcykFwjEnNotvNlVJHccfSDOLlzsXr8kpUzU,11110
|
|
9
|
+
reconstruct3d/init_sfm.py,sha256=q_9d-QRhtuxMGtz-8K_mnHN0Bj1_GIEmr5v54YY5UC4,6225
|
|
10
|
+
reconstruct3d/mesh.py,sha256=UvdrXA1x7xeeHcMnJFvSdFPr-SBhui8mbfwlByuknUg,5031
|
|
11
|
+
reconstruct3d/track_sfm.py,sha256=Z-8OtycWBzmHGw_HAmZyIZUeltAZglMxKoI9JhrbExM,12004
|
|
12
|
+
reconstruct3d/viewer.py,sha256=Zx09CT1R1dNUZ9sOqJjJTvu2CmFuJa5aE5RiyCtKzzY,4223
|
|
13
|
+
reconstruct3d/cgal_mesh/CMakeLists.txt,sha256=L187LXfy1269jNi2OCW3m8elHTsXvbTPzz66RQJ5qKk,696
|
|
14
|
+
reconstruct3d/cgal_mesh/mesh_reconstruct.cpp,sha256=AyrjBmKcvz61pzIyUY4Li-kj52MOaD-kALpraqKfsjI,13491
|
|
15
|
+
reconstruct3d-0.1.0.dist-info/METADATA,sha256=Kuq_43qPu1gFCgl323wWPGCojwajTGtYKk6NBjx7rfs,17515
|
|
16
|
+
reconstruct3d-0.1.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
17
|
+
reconstruct3d-0.1.0.dist-info/entry_points.txt,sha256=2RatR0ezPmG_FFZYsXGrzm2KdCfUW5zU11YDZtNyRkY,57
|
|
18
|
+
reconstruct3d-0.1.0.dist-info/licenses/LICENSE,sha256=M5sWK_Vw7QdMjgdL6cyM2JeVzzIp3Q8d1l73Fa8e7a4,1068
|
|
19
|
+
reconstruct3d-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 BlackMonkcr
|
|
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.
|