A web application that transforms drone photographs into 3D maps and models using photogrammetry, with AI-powered image classification.
Upload drone photos → Get 3D models, aerial maps, and AI scene tags
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Upload 15+ │ ──► │ Photogrammetry│ ──► │ Download │
│ Drone Photos │ │ Processing │ │ Results │
└──────────────┘ └──────────────┘ └──────────────┘
│
┌──────────────┐ │
│ AI │ ◄───────────┘
│Classification│
└──────────────┘
Converts overlapping aerial photographs into:
| Output | Description |
|---|---|
| Orthophoto | Georeferenced 2D aerial map (like Google Maps) |
| 3D Model | Textured mesh you can view in a browser |
| Point Cloud | Millions of 3D points representing the terrain |
| Elevation Map | Digital Surface Model (DSM) showing heights |
Automatically tags each uploaded image with scene categories:
- Urban (buildings, streets, parking lots)
- Forest (trees, vegetation, woodland)
- Water (rivers, lakes, coastlines)
- Agriculture (farmland, crops)
- Mountain (hills, cliffs, valleys)
- Industrial (factories, construction sites)
┌─────────────────┐
│ React Frontend │
│ Upload Images │
└────────┬────────┘
│
┌────────▼────────┐
│ Express Backend │
│ REST API │
└────────┬────────┘
│
┌───────────────────┼───────────────────┐
│ │ │
┌────▼────┐ ┌─────▼─────┐ ┌────▼────┐
│ MinIO │ │ PostgreSQL│ │ Redis │
│ Storage │ │ Database │ │ Queue │
└─────────┘ └───────────┘ └────┬────┘
│
┌────────────────────────┼────────────────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ NodeODM │ │ Analytics │ │ BullMQ │
│Photogrammetry│ │ PyTorch │ │ Worker │
└─────────────┘ └─────────────┘ └─────────────┘
| Component | Why It's Used |
|---|---|
| MinIO | S3-compatible object storage. Handles large image files (50MB+ each) efficiently. Decouples storage from the API server, enabling horizontal scaling. |
| Redis + BullMQ | Job queue for async processing. Photogrammetry takes 5-30+ minutes—users shouldn't wait. Jobs are queued, processed in background, and users poll for status. |
| PostgreSQL | Relational database for project metadata, job status, and ML classification results. |
| NodeODM | Containerized OpenDroneMap engine. Isolates heavy CPU/memory processing from the main app. Can be scaled independently. |
Key Design Decisions:
- Async Processing: Upload is I/O-bound, photogrammetry is CPU-bound. BullMQ decouples them so uploads complete instantly while processing happens in background.
- Object Storage: Images and outputs (GeoTIFFs, 3D models) are large binary files. MinIO handles this better than filesystem storage and enables cloud migration.
- Containerization: Each service runs in Docker. NodeODM especially benefits from isolation since it can consume all available RAM during processing.
Tested January 2026 on Windows with 7.5GB Docker RAM
| Feature | Status | Notes |
|---|---|---|
| Image Upload | Yes Working | Via API or frontend |
| Photogrammetry Processing | Yes Working | 15 images in ~4 min |
| Orthophoto Generation | Yes Working | GeoTIFF format |
| 3D Model Generation | Yes Working | GLB format |
| Point Cloud Generation | Yes Working | LAZ format |
| Report Generation | Yes Working | PDF quality report |
| AI Classification | Yes Working | MobileNetV2 on CPU |
| Real-time Status API | Yes Working | Progress percentage |
| Output Downloads | Yes Working | All 4 file types |
| Limitation | Details |
|---|---|
| Max Images | ~15 images with 7.5GB RAM (minimal mode) |
| Processing Time | 4-6 minutes for 15 images |
| No DSM/DTM | Disabled in minimal mode to save memory |
| Classification Accuracy | MobileNetV2 not ideal for aerial imagery |
| No GPU Support | Analytics runs on CPU only |
| Mode | Max Images* | Quality | RAM Needed |
|---|---|---|---|
minimal |
~15-25 | Low | ~4 GB |
preview |
~10-15 | Medium | ~6 GB |
balanced |
Not tested | Good | ~12 GB |
quality |
Not tested | Best | ~16+ GB |
*With 7.5GB Docker RAM allocation
Dataset: 15 images from ODM bellus (volcanic terrain) Mode: minimal Processing Time: 4 minutes
| File | Size |
|---|---|
orthophoto.tif |
~50-70 MB |
textured_model.glb |
~10-15 MB |
georeferenced_model.laz |
~2 MB |
report.pdf |
~8 MB |
Scene Distribution (15 images):
Mountain ██████████████ 47% (7 images)
Ant ████████ 27% (4 images) ← misclassification
Water ████ 13% (2 images)
Other ██ 7% (1 image)
Note: "Ant" classifications are MobileNetV2 misinterpreting rock textures. For aerial imagery, use the RESISC45 model instead.
| Component | Technology |
|---|---|
| Frontend | React, Vite, Tailwind CSS |
| Backend | Node.js, Express, Socket.IO |
| Storage | MinIO (S3-compatible) |
| Database | PostgreSQL |
| Queue | Redis, BullMQ |
| Processing | NodeODM (OpenDroneMap) |
| ML/AI | Python, PyTorch, PySpark |
| Infrastructure | Docker, Docker Compose |
weird-drone/
├── frontend/ # React web application
├── backend/ # Express API server
├── analytics-engine/ # Python ML classification
├── docker-compose.yml # Infrastructure setup
└── data/ # Runtime data storage
| Endpoint | Purpose |
|---|---|
POST /api/process?mode=minimal |
Upload images and start processing |
GET /api/status/:id |
Check processing progress (0-100%) |
GET /api/download/:id/:file |
Download output files |
GET /api/projects/:id/tags |
Get AI classifications |
GET /api/health |
Check all service status |