mizukage 0.1.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.
- mizukage-0.1.0/.github/workflows/build.yml +26 -0
- mizukage-0.1.0/.github/workflows/publish.yml +32 -0
- mizukage-0.1.0/.gitignore +13 -0
- mizukage-0.1.0/.python-version +1 -0
- mizukage-0.1.0/PKG-INFO +259 -0
- mizukage-0.1.0/README.md +234 -0
- mizukage-0.1.0/doc/api-reference.md +351 -0
- mizukage-0.1.0/doc/architecture.md +205 -0
- mizukage-0.1.0/doc/camera-hardware.md +144 -0
- mizukage-0.1.0/doc/cli-reference.md +275 -0
- mizukage-0.1.0/doc/format-lri.md +191 -0
- mizukage-0.1.0/doc/format-lris.md +100 -0
- mizukage-0.1.0/doc/format-pixels.md +178 -0
- mizukage-0.1.0/doc/index.md +52 -0
- mizukage-0.1.0/doc/internal/explorer-plan.md +257 -0
- mizukage-0.1.0/doc/protobuf-schema.md +204 -0
- mizukage-0.1.0/doc/quickstart.md +134 -0
- mizukage-0.1.0/known-documentation/calibration-data-applications.md +308 -0
- mizukage-0.1.0/known-documentation/calibration-data-guide.md +459 -0
- mizukage-0.1.0/known-documentation/denoising-networks.md +371 -0
- mizukage-0.1.0/known-documentation/next-steps.md +264 -0
- mizukage-0.1.0/known-documentation/scene-reconstruction.md +344 -0
- mizukage-0.1.0/known-documentation/shader-denoising.md +296 -0
- mizukage-0.1.0/main.py +4 -0
- mizukage-0.1.0/mizukage/__init__.py +78 -0
- mizukage-0.1.0/mizukage/_block.py +70 -0
- mizukage-0.1.0/mizukage/_calib.py +542 -0
- mizukage-0.1.0/mizukage/_debayer.py +186 -0
- mizukage-0.1.0/mizukage/_denoise.py +416 -0
- mizukage-0.1.0/mizukage/_image.py +545 -0
- mizukage-0.1.0/mizukage/_lri.py +253 -0
- mizukage-0.1.0/mizukage/_lris.py +96 -0
- mizukage-0.1.0/mizukage/_proto.py +300 -0
- mizukage-0.1.0/mizukage/_types.py +200 -0
- mizukage-0.1.0/mizukage/_unpack.py +106 -0
- mizukage-0.1.0/mizukage/calib_viewer/__init__.py +133 -0
- mizukage-0.1.0/mizukage/calib_viewer/_color.py +164 -0
- mizukage-0.1.0/mizukage/calib_viewer/_data.py +292 -0
- mizukage-0.1.0/mizukage/calib_viewer/_geometry.py +315 -0
- mizukage-0.1.0/mizukage/calib_viewer/_hotpixels.py +126 -0
- mizukage-0.1.0/mizukage/calib_viewer/_layout.py +117 -0
- mizukage-0.1.0/mizukage/calib_viewer/_noise.py +124 -0
- mizukage-0.1.0/mizukage/calib_viewer/_vignetting.py +122 -0
- mizukage-0.1.0/mizukage/cli/__init__.py +1 -0
- mizukage-0.1.0/mizukage/cli/commands/__init__.py +1 -0
- mizukage-0.1.0/mizukage/cli/commands/calib.py +421 -0
- mizukage-0.1.0/mizukage/cli/commands/calib_view.py +46 -0
- mizukage-0.1.0/mizukage/cli/commands/export.py +521 -0
- mizukage-0.1.0/mizukage/cli/commands/extract.py +155 -0
- mizukage-0.1.0/mizukage/cli/commands/info.py +311 -0
- mizukage-0.1.0/mizukage/cli/main.py +25 -0
- mizukage-0.1.0/mizukage/proto/__init__.py +7 -0
- mizukage-0.1.0/mizukage/proto/camera_id_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/camera_module_pb2.py +47 -0
- mizukage-0.1.0/mizukage/proto/color_calibration_pb2.py +49 -0
- mizukage-0.1.0/mizukage/proto/dead_pixel_map_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/device_temp_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/distortion_pb2.py +44 -0
- mizukage-0.1.0/mizukage/proto/face_data_pb2.py +40 -0
- mizukage-0.1.0/mizukage/proto/flash_calibration_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/geometric_calibration_pb2.py +57 -0
- mizukage-0.1.0/mizukage/proto/gps_data_pb2.py +48 -0
- mizukage-0.1.0/mizukage/proto/hot_pixel_map_pb2.py +38 -0
- mizukage-0.1.0/mizukage/proto/hw_info_pb2.py +54 -0
- mizukage-0.1.0/mizukage/proto/imu_data_pb2.py +39 -0
- mizukage-0.1.0/mizukage/proto/lightheader_pb2.py +71 -0
- mizukage-0.1.0/mizukage/proto/matrix3x3f_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/matrix4x4f_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/mirror_system_pb2.py +49 -0
- mizukage-0.1.0/mizukage/proto/point2f_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/point2i_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/point3f_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/proximity_sensors_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/range2f_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/rectanglei_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/sensor_characterization_pb2.py +40 -0
- mizukage-0.1.0/mizukage/proto/sensor_type_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/time_stamp_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/tof_calibration_pb2.py +36 -0
- mizukage-0.1.0/mizukage/proto/view_preferences_pb2.py +53 -0
- mizukage-0.1.0/mizukage/proto/vignetting_characterization_pb2.py +47 -0
- mizukage-0.1.0/protobuf/camera_id.proto +22 -0
- mizukage-0.1.0/protobuf/camera_module.proto +67 -0
- mizukage-0.1.0/protobuf/color_calibration.proto +47 -0
- mizukage-0.1.0/protobuf/dead_pixel_map.proto +9 -0
- mizukage-0.1.0/protobuf/device_temp.proto +11 -0
- mizukage-0.1.0/protobuf/distortion.proto +31 -0
- mizukage-0.1.0/protobuf/face_data.proto +18 -0
- mizukage-0.1.0/protobuf/flash_calibration.proto +12 -0
- mizukage-0.1.0/protobuf/geometric_calibration.proto +64 -0
- mizukage-0.1.0/protobuf/gps_data.proto +49 -0
- mizukage-0.1.0/protobuf/hot_pixel_map.proto +16 -0
- mizukage-0.1.0/protobuf/hw_info.proto +64 -0
- mizukage-0.1.0/protobuf/imu_data.proto +17 -0
- mizukage-0.1.0/protobuf/lightheader.proto +106 -0
- mizukage-0.1.0/protobuf/matrix3x3f.proto +15 -0
- mizukage-0.1.0/protobuf/matrix4x4f.proto +22 -0
- mizukage-0.1.0/protobuf/mirror_system.proto +50 -0
- mizukage-0.1.0/protobuf/point2f.proto +8 -0
- mizukage-0.1.0/protobuf/point2i.proto +8 -0
- mizukage-0.1.0/protobuf/point3f.proto +9 -0
- mizukage-0.1.0/protobuf/proximity_sensors.proto +11 -0
- mizukage-0.1.0/protobuf/range2f.proto +8 -0
- mizukage-0.1.0/protobuf/rectanglei.proto +10 -0
- mizukage-0.1.0/protobuf/sensor_characterization.proto +26 -0
- mizukage-0.1.0/protobuf/sensor_type.proto +12 -0
- mizukage-0.1.0/protobuf/time_stamp.proto +13 -0
- mizukage-0.1.0/protobuf/tof_calibration.proto +10 -0
- mizukage-0.1.0/protobuf/view_preferences.proto +94 -0
- mizukage-0.1.0/protobuf/vignetting_characterization.proto +30 -0
- mizukage-0.1.0/pyproject.toml +45 -0
- mizukage-0.1.0/scripts/compile_protos.py +47 -0
- mizukage-0.1.0/uv.lock +1545 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Build for CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout
|
|
16
|
+
uses: actions/checkout@v6
|
|
17
|
+
- name: Install uv
|
|
18
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
19
|
+
- name: Install Python
|
|
20
|
+
run: uv python install
|
|
21
|
+
- name: Local install
|
|
22
|
+
run: |
|
|
23
|
+
uv venv
|
|
24
|
+
uv pip install -e .
|
|
25
|
+
- name: Check package runs
|
|
26
|
+
run: uv run mizukage --help
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: "Publish to PyPI"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
environment:
|
|
12
|
+
name: pypi-publish
|
|
13
|
+
permissions:
|
|
14
|
+
id-token: write
|
|
15
|
+
contents: read
|
|
16
|
+
steps:
|
|
17
|
+
- name: Checkout
|
|
18
|
+
uses: actions/checkout@v6
|
|
19
|
+
- name: Install uv
|
|
20
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
21
|
+
- name: Install Python
|
|
22
|
+
run: uv python install
|
|
23
|
+
- name: Build
|
|
24
|
+
run: uv build
|
|
25
|
+
- name: Publish
|
|
26
|
+
run: uv publish
|
|
27
|
+
- name: Create release
|
|
28
|
+
uses: softprops/action-gh-release@v1
|
|
29
|
+
with:
|
|
30
|
+
files: dist/*
|
|
31
|
+
env:
|
|
32
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv
|
|
11
|
+
|
|
12
|
+
# Generated proto files are committed (shadow/proto/*_pb2.py).
|
|
13
|
+
# Regenerate with: uv run --extra dev python scripts/compile_protos.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
mizukage-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mizukage
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Library and tools for reading Light L16 LRI camera files
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Requires-Dist: click>=8.1
|
|
7
|
+
Requires-Dist: numpy>=1.26
|
|
8
|
+
Requires-Dist: pillow>=10.0
|
|
9
|
+
Requires-Dist: protobuf>=5.0
|
|
10
|
+
Requires-Dist: rich>=13.0
|
|
11
|
+
Requires-Dist: scipy>=1.11
|
|
12
|
+
Provides-Extra: demosaic
|
|
13
|
+
Requires-Dist: colour-demosaicing>=0.2.7; extra == 'demosaic'
|
|
14
|
+
Provides-Extra: denoise
|
|
15
|
+
Requires-Dist: bm3d>=4.0; extra == 'denoise'
|
|
16
|
+
Provides-Extra: denoise-gpu
|
|
17
|
+
Requires-Dist: deepinv>=0.2; extra == 'denoise-gpu'
|
|
18
|
+
Requires-Dist: kornia>=0.7; extra == 'denoise-gpu'
|
|
19
|
+
Requires-Dist: torch>=2.0; extra == 'denoise-gpu'
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: grpcio-tools>=1.50; extra == 'dev'
|
|
22
|
+
Provides-Extra: explorer
|
|
23
|
+
Requires-Dist: dearpygui>=1.11; extra == 'explorer'
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# mizukage
|
|
27
|
+
|
|
28
|
+
A Python library and CLI for reading Light L16 camera files — raw image data, depth maps, and factory calibration.
|
|
29
|
+
|
|
30
|
+
The Light L16 is a 16-lens computational camera. Each capture fires up to 16 independent sensors across three focal lengths (28 mm / 70 mm / 150 mm equivalent), producing a bundle of `.lri` raw files and an optional `.lris` depth-map sidecar. `mizukage` parses the proprietary LELR block-stream format, exposes sensor data as NumPy arrays, and can export processed images with full calibration applied.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install mizukage
|
|
38
|
+
# or with uv:
|
|
39
|
+
uv add mizukage
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Optional dependency groups:
|
|
43
|
+
|
|
44
|
+
| Group | Adds |
|
|
45
|
+
|-------|------|
|
|
46
|
+
| `mizukage[demosaic]` | Malvar 2004, Menon 2007, and DDFAPD high-quality debayering |
|
|
47
|
+
| `mizukage[denoise]` | BM3D denoising (CPU) |
|
|
48
|
+
| `mizukage[denoise-gpu]` | GPU bilateral, DnCNN, and DRUNet via kornia + deepinv + PyTorch |
|
|
49
|
+
| `mizukage[explorer]` | `mizukage calib-view` interactive calibration viewer (DearPyGui) |
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## CLI
|
|
54
|
+
|
|
55
|
+
### `mizukage info`
|
|
56
|
+
|
|
57
|
+
Print metadata from an LRI or LRIS file.
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
mizukage info photo.lri
|
|
61
|
+
mizukage info photo.lri --cameras # per-camera exposure, gain, AWB, focus
|
|
62
|
+
mizukage info photo.lri --blocks # raw LELR block layout and sizes
|
|
63
|
+
mizukage info photo.lri --json # machine-readable JSON
|
|
64
|
+
mizukage info photo.lris # depth-map sidecar metadata
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### `mizukage export`
|
|
68
|
+
|
|
69
|
+
Export each camera module's image from an LRI file.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# All cameras -> PNG, debayered + AWB + sRGB gamma
|
|
73
|
+
mizukage export photo.lri ./out
|
|
74
|
+
|
|
75
|
+
# Single camera, TIFF, +1 stop exposure
|
|
76
|
+
mizukage export photo.lri ./out --camera B4 --format tiff --exposure +1.0
|
|
77
|
+
|
|
78
|
+
# Raw 16-bit Bayer (no debayering)
|
|
79
|
+
mizukage export photo.lri ./out --raw
|
|
80
|
+
|
|
81
|
+
# High-quality demosaic (requires mizukage[demosaic])
|
|
82
|
+
mizukage export photo.lri ./out --kernel menon
|
|
83
|
+
|
|
84
|
+
# With factory calibration: hot-pixel correction + sigma-matched denoising
|
|
85
|
+
mizukage export photo.lri ./out --calib images/lightcal --denoise bm3d
|
|
86
|
+
|
|
87
|
+
# Full calibration pipeline: hot-pixel + vignetting + undistortion + denoising
|
|
88
|
+
mizukage export photo.lri ./out \
|
|
89
|
+
--calib images/lightcal \
|
|
90
|
+
--denoise bm3d \
|
|
91
|
+
--undistort
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Output filenames follow the pattern `A1.png`, `B4_raw.tiff`, etc.
|
|
95
|
+
|
|
96
|
+
#### Calibration pipeline (`--calib`)
|
|
97
|
+
|
|
98
|
+
When `--calib DIR` points at a `lightcal` directory, corrections are applied in order, all in linear light before gamma:
|
|
99
|
+
|
|
100
|
+
1. **Hot-pixel correction** — per-camera defect maps from `hotpixel.rec`
|
|
101
|
+
2. **Vignetting correction** — multiplicative falloff grid from `calibration.lri`
|
|
102
|
+
3. **Denoising** (if `--denoise`) — sigma is set automatically from the factory VST noise model
|
|
103
|
+
4. **CCM** — factory `forward_matrix` chosen by matching capture AWB gains to the nearest colour profile
|
|
104
|
+
5. **Lens undistortion** (if `--undistort`) — inverse-map radial polynomial from `calibration.lri`
|
|
105
|
+
6. **Gamma / tone mapping**
|
|
106
|
+
|
|
107
|
+
### `mizukage extract`
|
|
108
|
+
|
|
109
|
+
Dump raw Bayer data as NumPy `.npy` files (one `uint16` array per camera).
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
mizukage extract photo.lri ./raw
|
|
113
|
+
mizukage extract photo.lri ./raw --camera B4 --camera C1
|
|
114
|
+
mizukage extract photo.lri ./raw --no-subtract-black # keep sensor black-level offset
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
A `metadata.json` summary is written alongside the arrays unless `--no-metadata` is given.
|
|
118
|
+
|
|
119
|
+
### `mizukage calib`
|
|
120
|
+
|
|
121
|
+
Inspect a `lightcal` calibration directory as text or JSON.
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
mizukage calib images/lightcal
|
|
125
|
+
mizukage calib images/lightcal --json # full calibration data, all cameras
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Reports geometry (intrinsics, distortion, focus bundles), colour matrices, vignetting grids, sensor characteristics, and hot-pixel statistics.
|
|
129
|
+
|
|
130
|
+
### `mizukage calib-view`
|
|
131
|
+
|
|
132
|
+
Interactive GUI explorer for a `lightcal` directory (requires `mizukage[explorer]`).
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
pip install 'mizukage[explorer]'
|
|
136
|
+
mizukage calib-view images/lightcal
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Select a camera from the sidebar to populate six tabs:
|
|
140
|
+
|
|
141
|
+
| Tab | Contents |
|
|
142
|
+
|-----|----------|
|
|
143
|
+
| **Hot pixels** | Sqrt-scaled defect-density heatmap; per-measurement gain, temperature, exposure |
|
|
144
|
+
| **Noise model** | VST sigma-vs-gain curves per channel (R / Gr / Gb / B) |
|
|
145
|
+
| **Vignetting** | Per-camera falloff correction grid; hall-code selector for C-array cameras |
|
|
146
|
+
| **Geometry** | Intrinsics per focus bundle (fx, fy, cx, cy, RMS, sensor temp); radial distortion coefficients; ideal-vs-distorted grid visualisation; rotation matrix and camera world position |
|
|
147
|
+
| **Color** | Factory forward and colour matrices per illuminant; neutral-point locus scatter plot (rg/bg ratios) |
|
|
148
|
+
| **Layout** | Bird's-eye position map for all 16 modules |
|
|
149
|
+
|
|
150
|
+
The sidebar shows sensor black/white levels, device model, and calibration date.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Python API
|
|
155
|
+
|
|
156
|
+
### Opening a file
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
import mizukage
|
|
160
|
+
|
|
161
|
+
lri = mizukage.open_lri("photo.lri")
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Metadata
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
meta = lri.metadata
|
|
168
|
+
print(meta.focal_length_mm) # e.g. 28.0
|
|
169
|
+
print(meta.device_model) # "L16"
|
|
170
|
+
print(meta.gps) # GpsData | None
|
|
171
|
+
print(meta.awb_gains) # AwbGains(r, gr, gb, b) | None
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Accessing camera images
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
for img in lri.images:
|
|
178
|
+
print(img.camera_id, img.width, img.height)
|
|
179
|
+
|
|
180
|
+
img = lri.get_image(mizukage.CameraId.B4)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Exporting
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
# 8-bit PNG — debayer + AWB + sRGB gamma
|
|
187
|
+
img.to_png("B4.png")
|
|
188
|
+
|
|
189
|
+
# 16-bit TIFF, linear light, +0.5 EV
|
|
190
|
+
img.to_tiff("B4.tiff", gamma="linear", exposure=0.5)
|
|
191
|
+
|
|
192
|
+
# Raw Bayer as NumPy array (uint16)
|
|
193
|
+
bayer = img.to_bayer_numpy()
|
|
194
|
+
|
|
195
|
+
# Debayered float32 (H, W, 3) in linear light
|
|
196
|
+
rgb = img.to_debayered_numpy()
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Calibration-aware export
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
from pathlib import Path
|
|
203
|
+
from mizukage._calib import load_hot_pixel_map, load_distortion_params, load_vignetting_grid
|
|
204
|
+
from mizukage._types import CameraId
|
|
205
|
+
|
|
206
|
+
calib_dir = Path("images/lightcal")
|
|
207
|
+
cam = CameraId.B4
|
|
208
|
+
|
|
209
|
+
img.to_png(
|
|
210
|
+
"B4_calib.png",
|
|
211
|
+
hot_pixel_map=load_hot_pixel_map(calib_dir, cam),
|
|
212
|
+
vignetting_grid=load_vignetting_grid(calib_dir, cam),
|
|
213
|
+
distortion_params=load_distortion_params(calib_dir, cam),
|
|
214
|
+
undistort=True,
|
|
215
|
+
)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Depth maps (LRIS)
|
|
219
|
+
|
|
220
|
+
```python
|
|
221
|
+
lris = mizukage.open_lris("photo.lris")
|
|
222
|
+
depth = lris.depth_map # float32 NumPy array, metres
|
|
223
|
+
conf = lris.confidence_map # float32, 0-1
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## File format
|
|
229
|
+
|
|
230
|
+
`.lri` and `.lris` files are **LELR block streams**: a sequence of 32-byte headers, each followed by a protobuf payload. The magic bytes `LELR` open every block.
|
|
231
|
+
|
|
232
|
+
| Block type | Content |
|
|
233
|
+
|------------|---------|
|
|
234
|
+
| `LIGHT_HEADER` (0) | Capture metadata, camera settings, colour profiles, calibration data |
|
|
235
|
+
| `VIEW_PREFERENCES` (1) | App-level display preferences |
|
|
236
|
+
| `GPS_DATA` (2) | GPS coordinates and timestamp |
|
|
237
|
+
|
|
238
|
+
Image data (raw Bayer or JPEG-compressed Bayer) is stored as binary blobs with offsets recorded in the `LIGHT_HEADER` protobuf. `mizukage` reads these via direct byte slices without copying the entire payload into protobuf fields.
|
|
239
|
+
|
|
240
|
+
Calibration files use the same LELR format. `calibration.lri` holds per-camera `FactoryModuleCalibration` blocks; `hotpixel.rec` embeds zlib-compressed defect bitmaps.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Camera layout
|
|
245
|
+
|
|
246
|
+
| Array | Cameras | Focal length |
|
|
247
|
+
|-------|---------|--------------|
|
|
248
|
+
| A | A1-A5 | 28 mm eq. |
|
|
249
|
+
| B | B1-B5 | 70 mm eq. |
|
|
250
|
+
| C | C1-C6 | 150 mm eq. |
|
|
251
|
+
|
|
252
|
+
C-array cameras use a movable mirror to extend effective aperture. Their calibration includes per-hall-code vignetting grids and mirror actuator mapping.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Requirements
|
|
257
|
+
|
|
258
|
+
- Python 3.12+
|
|
259
|
+
- NumPy >= 1.26, SciPy >= 1.11, Pillow >= 10, protobuf >= 5, click >= 8.1, rich >= 13
|
mizukage-0.1.0/README.md
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# mizukage
|
|
2
|
+
|
|
3
|
+
A Python library and CLI for reading Light L16 camera files — raw image data, depth maps, and factory calibration.
|
|
4
|
+
|
|
5
|
+
The Light L16 is a 16-lens computational camera. Each capture fires up to 16 independent sensors across three focal lengths (28 mm / 70 mm / 150 mm equivalent), producing a bundle of `.lri` raw files and an optional `.lris` depth-map sidecar. `mizukage` parses the proprietary LELR block-stream format, exposes sensor data as NumPy arrays, and can export processed images with full calibration applied.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install mizukage
|
|
13
|
+
# or with uv:
|
|
14
|
+
uv add mizukage
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Optional dependency groups:
|
|
18
|
+
|
|
19
|
+
| Group | Adds |
|
|
20
|
+
|-------|------|
|
|
21
|
+
| `mizukage[demosaic]` | Malvar 2004, Menon 2007, and DDFAPD high-quality debayering |
|
|
22
|
+
| `mizukage[denoise]` | BM3D denoising (CPU) |
|
|
23
|
+
| `mizukage[denoise-gpu]` | GPU bilateral, DnCNN, and DRUNet via kornia + deepinv + PyTorch |
|
|
24
|
+
| `mizukage[explorer]` | `mizukage calib-view` interactive calibration viewer (DearPyGui) |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## CLI
|
|
29
|
+
|
|
30
|
+
### `mizukage info`
|
|
31
|
+
|
|
32
|
+
Print metadata from an LRI or LRIS file.
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
mizukage info photo.lri
|
|
36
|
+
mizukage info photo.lri --cameras # per-camera exposure, gain, AWB, focus
|
|
37
|
+
mizukage info photo.lri --blocks # raw LELR block layout and sizes
|
|
38
|
+
mizukage info photo.lri --json # machine-readable JSON
|
|
39
|
+
mizukage info photo.lris # depth-map sidecar metadata
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### `mizukage export`
|
|
43
|
+
|
|
44
|
+
Export each camera module's image from an LRI file.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# All cameras -> PNG, debayered + AWB + sRGB gamma
|
|
48
|
+
mizukage export photo.lri ./out
|
|
49
|
+
|
|
50
|
+
# Single camera, TIFF, +1 stop exposure
|
|
51
|
+
mizukage export photo.lri ./out --camera B4 --format tiff --exposure +1.0
|
|
52
|
+
|
|
53
|
+
# Raw 16-bit Bayer (no debayering)
|
|
54
|
+
mizukage export photo.lri ./out --raw
|
|
55
|
+
|
|
56
|
+
# High-quality demosaic (requires mizukage[demosaic])
|
|
57
|
+
mizukage export photo.lri ./out --kernel menon
|
|
58
|
+
|
|
59
|
+
# With factory calibration: hot-pixel correction + sigma-matched denoising
|
|
60
|
+
mizukage export photo.lri ./out --calib images/lightcal --denoise bm3d
|
|
61
|
+
|
|
62
|
+
# Full calibration pipeline: hot-pixel + vignetting + undistortion + denoising
|
|
63
|
+
mizukage export photo.lri ./out \
|
|
64
|
+
--calib images/lightcal \
|
|
65
|
+
--denoise bm3d \
|
|
66
|
+
--undistort
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Output filenames follow the pattern `A1.png`, `B4_raw.tiff`, etc.
|
|
70
|
+
|
|
71
|
+
#### Calibration pipeline (`--calib`)
|
|
72
|
+
|
|
73
|
+
When `--calib DIR` points at a `lightcal` directory, corrections are applied in order, all in linear light before gamma:
|
|
74
|
+
|
|
75
|
+
1. **Hot-pixel correction** — per-camera defect maps from `hotpixel.rec`
|
|
76
|
+
2. **Vignetting correction** — multiplicative falloff grid from `calibration.lri`
|
|
77
|
+
3. **Denoising** (if `--denoise`) — sigma is set automatically from the factory VST noise model
|
|
78
|
+
4. **CCM** — factory `forward_matrix` chosen by matching capture AWB gains to the nearest colour profile
|
|
79
|
+
5. **Lens undistortion** (if `--undistort`) — inverse-map radial polynomial from `calibration.lri`
|
|
80
|
+
6. **Gamma / tone mapping**
|
|
81
|
+
|
|
82
|
+
### `mizukage extract`
|
|
83
|
+
|
|
84
|
+
Dump raw Bayer data as NumPy `.npy` files (one `uint16` array per camera).
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
mizukage extract photo.lri ./raw
|
|
88
|
+
mizukage extract photo.lri ./raw --camera B4 --camera C1
|
|
89
|
+
mizukage extract photo.lri ./raw --no-subtract-black # keep sensor black-level offset
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
A `metadata.json` summary is written alongside the arrays unless `--no-metadata` is given.
|
|
93
|
+
|
|
94
|
+
### `mizukage calib`
|
|
95
|
+
|
|
96
|
+
Inspect a `lightcal` calibration directory as text or JSON.
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
mizukage calib images/lightcal
|
|
100
|
+
mizukage calib images/lightcal --json # full calibration data, all cameras
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Reports geometry (intrinsics, distortion, focus bundles), colour matrices, vignetting grids, sensor characteristics, and hot-pixel statistics.
|
|
104
|
+
|
|
105
|
+
### `mizukage calib-view`
|
|
106
|
+
|
|
107
|
+
Interactive GUI explorer for a `lightcal` directory (requires `mizukage[explorer]`).
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
pip install 'mizukage[explorer]'
|
|
111
|
+
mizukage calib-view images/lightcal
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Select a camera from the sidebar to populate six tabs:
|
|
115
|
+
|
|
116
|
+
| Tab | Contents |
|
|
117
|
+
|-----|----------|
|
|
118
|
+
| **Hot pixels** | Sqrt-scaled defect-density heatmap; per-measurement gain, temperature, exposure |
|
|
119
|
+
| **Noise model** | VST sigma-vs-gain curves per channel (R / Gr / Gb / B) |
|
|
120
|
+
| **Vignetting** | Per-camera falloff correction grid; hall-code selector for C-array cameras |
|
|
121
|
+
| **Geometry** | Intrinsics per focus bundle (fx, fy, cx, cy, RMS, sensor temp); radial distortion coefficients; ideal-vs-distorted grid visualisation; rotation matrix and camera world position |
|
|
122
|
+
| **Color** | Factory forward and colour matrices per illuminant; neutral-point locus scatter plot (rg/bg ratios) |
|
|
123
|
+
| **Layout** | Bird's-eye position map for all 16 modules |
|
|
124
|
+
|
|
125
|
+
The sidebar shows sensor black/white levels, device model, and calibration date.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Python API
|
|
130
|
+
|
|
131
|
+
### Opening a file
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
import mizukage
|
|
135
|
+
|
|
136
|
+
lri = mizukage.open_lri("photo.lri")
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Metadata
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
meta = lri.metadata
|
|
143
|
+
print(meta.focal_length_mm) # e.g. 28.0
|
|
144
|
+
print(meta.device_model) # "L16"
|
|
145
|
+
print(meta.gps) # GpsData | None
|
|
146
|
+
print(meta.awb_gains) # AwbGains(r, gr, gb, b) | None
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Accessing camera images
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
for img in lri.images:
|
|
153
|
+
print(img.camera_id, img.width, img.height)
|
|
154
|
+
|
|
155
|
+
img = lri.get_image(mizukage.CameraId.B4)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Exporting
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
# 8-bit PNG — debayer + AWB + sRGB gamma
|
|
162
|
+
img.to_png("B4.png")
|
|
163
|
+
|
|
164
|
+
# 16-bit TIFF, linear light, +0.5 EV
|
|
165
|
+
img.to_tiff("B4.tiff", gamma="linear", exposure=0.5)
|
|
166
|
+
|
|
167
|
+
# Raw Bayer as NumPy array (uint16)
|
|
168
|
+
bayer = img.to_bayer_numpy()
|
|
169
|
+
|
|
170
|
+
# Debayered float32 (H, W, 3) in linear light
|
|
171
|
+
rgb = img.to_debayered_numpy()
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Calibration-aware export
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
from pathlib import Path
|
|
178
|
+
from mizukage._calib import load_hot_pixel_map, load_distortion_params, load_vignetting_grid
|
|
179
|
+
from mizukage._types import CameraId
|
|
180
|
+
|
|
181
|
+
calib_dir = Path("images/lightcal")
|
|
182
|
+
cam = CameraId.B4
|
|
183
|
+
|
|
184
|
+
img.to_png(
|
|
185
|
+
"B4_calib.png",
|
|
186
|
+
hot_pixel_map=load_hot_pixel_map(calib_dir, cam),
|
|
187
|
+
vignetting_grid=load_vignetting_grid(calib_dir, cam),
|
|
188
|
+
distortion_params=load_distortion_params(calib_dir, cam),
|
|
189
|
+
undistort=True,
|
|
190
|
+
)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Depth maps (LRIS)
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
lris = mizukage.open_lris("photo.lris")
|
|
197
|
+
depth = lris.depth_map # float32 NumPy array, metres
|
|
198
|
+
conf = lris.confidence_map # float32, 0-1
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## File format
|
|
204
|
+
|
|
205
|
+
`.lri` and `.lris` files are **LELR block streams**: a sequence of 32-byte headers, each followed by a protobuf payload. The magic bytes `LELR` open every block.
|
|
206
|
+
|
|
207
|
+
| Block type | Content |
|
|
208
|
+
|------------|---------|
|
|
209
|
+
| `LIGHT_HEADER` (0) | Capture metadata, camera settings, colour profiles, calibration data |
|
|
210
|
+
| `VIEW_PREFERENCES` (1) | App-level display preferences |
|
|
211
|
+
| `GPS_DATA` (2) | GPS coordinates and timestamp |
|
|
212
|
+
|
|
213
|
+
Image data (raw Bayer or JPEG-compressed Bayer) is stored as binary blobs with offsets recorded in the `LIGHT_HEADER` protobuf. `mizukage` reads these via direct byte slices without copying the entire payload into protobuf fields.
|
|
214
|
+
|
|
215
|
+
Calibration files use the same LELR format. `calibration.lri` holds per-camera `FactoryModuleCalibration` blocks; `hotpixel.rec` embeds zlib-compressed defect bitmaps.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Camera layout
|
|
220
|
+
|
|
221
|
+
| Array | Cameras | Focal length |
|
|
222
|
+
|-------|---------|--------------|
|
|
223
|
+
| A | A1-A5 | 28 mm eq. |
|
|
224
|
+
| B | B1-B5 | 70 mm eq. |
|
|
225
|
+
| C | C1-C6 | 150 mm eq. |
|
|
226
|
+
|
|
227
|
+
C-array cameras use a movable mirror to extend effective aperture. Their calibration includes per-hall-code vignetting grids and mirror actuator mapping.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Requirements
|
|
232
|
+
|
|
233
|
+
- Python 3.12+
|
|
234
|
+
- NumPy >= 1.26, SciPy >= 1.11, Pillow >= 10, protobuf >= 5, click >= 8.1, rich >= 13
|