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.
Files changed (113) hide show
  1. mizukage-0.1.0/.github/workflows/build.yml +26 -0
  2. mizukage-0.1.0/.github/workflows/publish.yml +32 -0
  3. mizukage-0.1.0/.gitignore +13 -0
  4. mizukage-0.1.0/.python-version +1 -0
  5. mizukage-0.1.0/PKG-INFO +259 -0
  6. mizukage-0.1.0/README.md +234 -0
  7. mizukage-0.1.0/doc/api-reference.md +351 -0
  8. mizukage-0.1.0/doc/architecture.md +205 -0
  9. mizukage-0.1.0/doc/camera-hardware.md +144 -0
  10. mizukage-0.1.0/doc/cli-reference.md +275 -0
  11. mizukage-0.1.0/doc/format-lri.md +191 -0
  12. mizukage-0.1.0/doc/format-lris.md +100 -0
  13. mizukage-0.1.0/doc/format-pixels.md +178 -0
  14. mizukage-0.1.0/doc/index.md +52 -0
  15. mizukage-0.1.0/doc/internal/explorer-plan.md +257 -0
  16. mizukage-0.1.0/doc/protobuf-schema.md +204 -0
  17. mizukage-0.1.0/doc/quickstart.md +134 -0
  18. mizukage-0.1.0/known-documentation/calibration-data-applications.md +308 -0
  19. mizukage-0.1.0/known-documentation/calibration-data-guide.md +459 -0
  20. mizukage-0.1.0/known-documentation/denoising-networks.md +371 -0
  21. mizukage-0.1.0/known-documentation/next-steps.md +264 -0
  22. mizukage-0.1.0/known-documentation/scene-reconstruction.md +344 -0
  23. mizukage-0.1.0/known-documentation/shader-denoising.md +296 -0
  24. mizukage-0.1.0/main.py +4 -0
  25. mizukage-0.1.0/mizukage/__init__.py +78 -0
  26. mizukage-0.1.0/mizukage/_block.py +70 -0
  27. mizukage-0.1.0/mizukage/_calib.py +542 -0
  28. mizukage-0.1.0/mizukage/_debayer.py +186 -0
  29. mizukage-0.1.0/mizukage/_denoise.py +416 -0
  30. mizukage-0.1.0/mizukage/_image.py +545 -0
  31. mizukage-0.1.0/mizukage/_lri.py +253 -0
  32. mizukage-0.1.0/mizukage/_lris.py +96 -0
  33. mizukage-0.1.0/mizukage/_proto.py +300 -0
  34. mizukage-0.1.0/mizukage/_types.py +200 -0
  35. mizukage-0.1.0/mizukage/_unpack.py +106 -0
  36. mizukage-0.1.0/mizukage/calib_viewer/__init__.py +133 -0
  37. mizukage-0.1.0/mizukage/calib_viewer/_color.py +164 -0
  38. mizukage-0.1.0/mizukage/calib_viewer/_data.py +292 -0
  39. mizukage-0.1.0/mizukage/calib_viewer/_geometry.py +315 -0
  40. mizukage-0.1.0/mizukage/calib_viewer/_hotpixels.py +126 -0
  41. mizukage-0.1.0/mizukage/calib_viewer/_layout.py +117 -0
  42. mizukage-0.1.0/mizukage/calib_viewer/_noise.py +124 -0
  43. mizukage-0.1.0/mizukage/calib_viewer/_vignetting.py +122 -0
  44. mizukage-0.1.0/mizukage/cli/__init__.py +1 -0
  45. mizukage-0.1.0/mizukage/cli/commands/__init__.py +1 -0
  46. mizukage-0.1.0/mizukage/cli/commands/calib.py +421 -0
  47. mizukage-0.1.0/mizukage/cli/commands/calib_view.py +46 -0
  48. mizukage-0.1.0/mizukage/cli/commands/export.py +521 -0
  49. mizukage-0.1.0/mizukage/cli/commands/extract.py +155 -0
  50. mizukage-0.1.0/mizukage/cli/commands/info.py +311 -0
  51. mizukage-0.1.0/mizukage/cli/main.py +25 -0
  52. mizukage-0.1.0/mizukage/proto/__init__.py +7 -0
  53. mizukage-0.1.0/mizukage/proto/camera_id_pb2.py +36 -0
  54. mizukage-0.1.0/mizukage/proto/camera_module_pb2.py +47 -0
  55. mizukage-0.1.0/mizukage/proto/color_calibration_pb2.py +49 -0
  56. mizukage-0.1.0/mizukage/proto/dead_pixel_map_pb2.py +36 -0
  57. mizukage-0.1.0/mizukage/proto/device_temp_pb2.py +36 -0
  58. mizukage-0.1.0/mizukage/proto/distortion_pb2.py +44 -0
  59. mizukage-0.1.0/mizukage/proto/face_data_pb2.py +40 -0
  60. mizukage-0.1.0/mizukage/proto/flash_calibration_pb2.py +36 -0
  61. mizukage-0.1.0/mizukage/proto/geometric_calibration_pb2.py +57 -0
  62. mizukage-0.1.0/mizukage/proto/gps_data_pb2.py +48 -0
  63. mizukage-0.1.0/mizukage/proto/hot_pixel_map_pb2.py +38 -0
  64. mizukage-0.1.0/mizukage/proto/hw_info_pb2.py +54 -0
  65. mizukage-0.1.0/mizukage/proto/imu_data_pb2.py +39 -0
  66. mizukage-0.1.0/mizukage/proto/lightheader_pb2.py +71 -0
  67. mizukage-0.1.0/mizukage/proto/matrix3x3f_pb2.py +36 -0
  68. mizukage-0.1.0/mizukage/proto/matrix4x4f_pb2.py +36 -0
  69. mizukage-0.1.0/mizukage/proto/mirror_system_pb2.py +49 -0
  70. mizukage-0.1.0/mizukage/proto/point2f_pb2.py +36 -0
  71. mizukage-0.1.0/mizukage/proto/point2i_pb2.py +36 -0
  72. mizukage-0.1.0/mizukage/proto/point3f_pb2.py +36 -0
  73. mizukage-0.1.0/mizukage/proto/proximity_sensors_pb2.py +36 -0
  74. mizukage-0.1.0/mizukage/proto/range2f_pb2.py +36 -0
  75. mizukage-0.1.0/mizukage/proto/rectanglei_pb2.py +36 -0
  76. mizukage-0.1.0/mizukage/proto/sensor_characterization_pb2.py +40 -0
  77. mizukage-0.1.0/mizukage/proto/sensor_type_pb2.py +36 -0
  78. mizukage-0.1.0/mizukage/proto/time_stamp_pb2.py +36 -0
  79. mizukage-0.1.0/mizukage/proto/tof_calibration_pb2.py +36 -0
  80. mizukage-0.1.0/mizukage/proto/view_preferences_pb2.py +53 -0
  81. mizukage-0.1.0/mizukage/proto/vignetting_characterization_pb2.py +47 -0
  82. mizukage-0.1.0/protobuf/camera_id.proto +22 -0
  83. mizukage-0.1.0/protobuf/camera_module.proto +67 -0
  84. mizukage-0.1.0/protobuf/color_calibration.proto +47 -0
  85. mizukage-0.1.0/protobuf/dead_pixel_map.proto +9 -0
  86. mizukage-0.1.0/protobuf/device_temp.proto +11 -0
  87. mizukage-0.1.0/protobuf/distortion.proto +31 -0
  88. mizukage-0.1.0/protobuf/face_data.proto +18 -0
  89. mizukage-0.1.0/protobuf/flash_calibration.proto +12 -0
  90. mizukage-0.1.0/protobuf/geometric_calibration.proto +64 -0
  91. mizukage-0.1.0/protobuf/gps_data.proto +49 -0
  92. mizukage-0.1.0/protobuf/hot_pixel_map.proto +16 -0
  93. mizukage-0.1.0/protobuf/hw_info.proto +64 -0
  94. mizukage-0.1.0/protobuf/imu_data.proto +17 -0
  95. mizukage-0.1.0/protobuf/lightheader.proto +106 -0
  96. mizukage-0.1.0/protobuf/matrix3x3f.proto +15 -0
  97. mizukage-0.1.0/protobuf/matrix4x4f.proto +22 -0
  98. mizukage-0.1.0/protobuf/mirror_system.proto +50 -0
  99. mizukage-0.1.0/protobuf/point2f.proto +8 -0
  100. mizukage-0.1.0/protobuf/point2i.proto +8 -0
  101. mizukage-0.1.0/protobuf/point3f.proto +9 -0
  102. mizukage-0.1.0/protobuf/proximity_sensors.proto +11 -0
  103. mizukage-0.1.0/protobuf/range2f.proto +8 -0
  104. mizukage-0.1.0/protobuf/rectanglei.proto +10 -0
  105. mizukage-0.1.0/protobuf/sensor_characterization.proto +26 -0
  106. mizukage-0.1.0/protobuf/sensor_type.proto +12 -0
  107. mizukage-0.1.0/protobuf/time_stamp.proto +13 -0
  108. mizukage-0.1.0/protobuf/tof_calibration.proto +10 -0
  109. mizukage-0.1.0/protobuf/view_preferences.proto +94 -0
  110. mizukage-0.1.0/protobuf/vignetting_characterization.proto +30 -0
  111. mizukage-0.1.0/pyproject.toml +45 -0
  112. mizukage-0.1.0/scripts/compile_protos.py +47 -0
  113. 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
@@ -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
@@ -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