wildflow-splat 0.1.3__tar.gz → 0.1.4__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 (51) hide show
  1. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/Cargo.lock +32 -32
  2. wildflow_splat-0.1.4/PKG-INFO +74 -0
  3. wildflow_splat-0.1.4/README.md +43 -0
  4. wildflow_splat-0.1.4/examples/patches_example.py +140 -0
  5. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/meta-package/pyproject.toml +2 -2
  6. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/native/lib.rs +6 -0
  7. wildflow_splat-0.1.4/native/patches.rs +562 -0
  8. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/pyproject.toml +1 -1
  9. wildflow_splat-0.1.4/requirements-dev.txt +2 -0
  10. wildflow_splat-0.1.4/requirements.txt +3 -0
  11. wildflow_splat-0.1.4/tests/__init__.py +1 -0
  12. wildflow_splat-0.1.4/tests/test_patches.py +301 -0
  13. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/wildflow/__init__.py +1 -1
  14. wildflow_splat-0.1.4/wildflow/splat/__init__.py +24 -0
  15. wildflow_splat-0.1.4/wildflow/splat/patches.py +65 -0
  16. wildflow_splat-0.1.3/PKG-INFO +0 -170
  17. wildflow_splat-0.1.3/README.md +0 -139
  18. wildflow_splat-0.1.3/configs/q5.yaml +0 -21
  19. wildflow_splat-0.1.3/requirements-dev.txt +0 -1
  20. wildflow_splat-0.1.3/setup.cfg +0 -2
  21. wildflow_splat-0.1.3/wildflow/splat/__init__.py +0 -9
  22. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/.gitattributes +0 -0
  23. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/.github/workflows/build-wheels.yml +0 -0
  24. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/.github/workflows/publish.yml +0 -0
  25. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/.gitignore +0 -0
  26. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/Cargo.toml +0 -0
  27. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/LICENSE +0 -0
  28. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/images/wildflow-3dgs-wf.svg +0 -0
  29. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/meta-package/.gitignore +0 -0
  30. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/meta-package/README.md +0 -0
  31. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/meta-package/wildflow/__init__.py +0 -0
  32. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/native/split.rs +0 -0
  33. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/clean.go +0 -0
  34. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/cleanup_splats.py +0 -0
  35. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/copy_cell.py +0 -0
  36. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/core/cell.py +0 -0
  37. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/core/colmap_reader.py +0 -0
  38. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/core/crop_colmap.py +0 -0
  39. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/core/grid.py +0 -0
  40. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/core/ply_reader.py +0 -0
  41. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/core/processor.py +0 -0
  42. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/core/types.py +0 -0
  43. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/core/visualizer.py +0 -0
  44. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/export_cell.py +0 -0
  45. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/export_cells.py +0 -0
  46. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/plan.py +0 -0
  47. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/plot_colmap.py +0 -0
  48. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/plot_ply.py +0 -0
  49. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/ply_to_colmap_bin.py +0 -0
  50. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4/refurbish}/run.py +0 -0
  51. {wildflow_splat-0.1.3 → wildflow_splat-0.1.4}/wildflow/splat/split.py +0 -0
@@ -4,21 +4,21 @@ version = 4
4
4
 
5
5
  [[package]]
6
6
  name = "autocfg"
7
- version = "1.4.0"
7
+ version = "1.5.0"
8
8
  source = "registry+https://github.com/rust-lang/crates.io-index"
9
- checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
9
+ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
10
10
 
11
11
  [[package]]
12
12
  name = "bumpalo"
13
- version = "3.18.0"
13
+ version = "3.19.0"
14
14
  source = "registry+https://github.com/rust-lang/crates.io-index"
15
- checksum = "c1b094a32014c3d1f3944e4808e0e7c70e97dae0660886a8eb6dbc52d745badc"
15
+ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
16
16
 
17
17
  [[package]]
18
18
  name = "cfg-if"
19
- version = "1.0.0"
19
+ version = "1.0.1"
20
20
  source = "registry+https://github.com/rust-lang/crates.io-index"
21
- checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
21
+ checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
22
22
 
23
23
  [[package]]
24
24
  name = "console"
@@ -93,9 +93,9 @@ dependencies = [
93
93
 
94
94
  [[package]]
95
95
  name = "libc"
96
- version = "0.2.172"
96
+ version = "0.2.174"
97
97
  source = "registry+https://github.com/rust-lang/crates.io-index"
98
- checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
98
+ checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
99
99
 
100
100
  [[package]]
101
101
  name = "log"
@@ -105,9 +105,9 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
105
105
 
106
106
  [[package]]
107
107
  name = "memchr"
108
- version = "2.7.4"
108
+ version = "2.7.5"
109
109
  source = "registry+https://github.com/rust-lang/crates.io-index"
110
- checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
110
+ checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
111
111
 
112
112
  [[package]]
113
113
  name = "memoffset"
@@ -132,9 +132,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
132
132
 
133
133
  [[package]]
134
134
  name = "portable-atomic"
135
- version = "1.11.0"
135
+ version = "1.11.1"
136
136
  source = "registry+https://github.com/rust-lang/crates.io-index"
137
- checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
137
+ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
138
138
 
139
139
  [[package]]
140
140
  name = "ppv-lite86"
@@ -156,9 +156,9 @@ dependencies = [
156
156
 
157
157
  [[package]]
158
158
  name = "pyo3"
159
- version = "0.25.0"
159
+ version = "0.25.1"
160
160
  source = "registry+https://github.com/rust-lang/crates.io-index"
161
- checksum = "f239d656363bcee73afef85277f1b281e8ac6212a1d42aa90e55b90ed43c47a4"
161
+ checksum = "8970a78afe0628a3e3430376fc5fd76b6b45c4d43360ffd6cdd40bdde72b682a"
162
162
  dependencies = [
163
163
  "indoc",
164
164
  "libc",
@@ -173,9 +173,9 @@ dependencies = [
173
173
 
174
174
  [[package]]
175
175
  name = "pyo3-build-config"
176
- version = "0.25.0"
176
+ version = "0.25.1"
177
177
  source = "registry+https://github.com/rust-lang/crates.io-index"
178
- checksum = "755ea671a1c34044fa165247aaf6f419ca39caa6003aee791a0df2713d8f1b6d"
178
+ checksum = "458eb0c55e7ece017adeba38f2248ff3ac615e53660d7c71a238d7d2a01c7598"
179
179
  dependencies = [
180
180
  "once_cell",
181
181
  "target-lexicon",
@@ -183,9 +183,9 @@ dependencies = [
183
183
 
184
184
  [[package]]
185
185
  name = "pyo3-ffi"
186
- version = "0.25.0"
186
+ version = "0.25.1"
187
187
  source = "registry+https://github.com/rust-lang/crates.io-index"
188
- checksum = "fc95a2e67091e44791d4ea300ff744be5293f394f1bafd9f78c080814d35956e"
188
+ checksum = "7114fe5457c61b276ab77c5055f206295b812608083644a5c5b2640c3102565c"
189
189
  dependencies = [
190
190
  "libc",
191
191
  "pyo3-build-config",
@@ -193,9 +193,9 @@ dependencies = [
193
193
 
194
194
  [[package]]
195
195
  name = "pyo3-macros"
196
- version = "0.25.0"
196
+ version = "0.25.1"
197
197
  source = "registry+https://github.com/rust-lang/crates.io-index"
198
- checksum = "a179641d1b93920829a62f15e87c0ed791b6c8db2271ba0fd7c2686090510214"
198
+ checksum = "a8725c0a622b374d6cb051d11a0983786448f7785336139c3c94f5aa6bef7e50"
199
199
  dependencies = [
200
200
  "proc-macro2",
201
201
  "pyo3-macros-backend",
@@ -205,9 +205,9 @@ dependencies = [
205
205
 
206
206
  [[package]]
207
207
  name = "pyo3-macros-backend"
208
- version = "0.25.0"
208
+ version = "0.25.1"
209
209
  source = "registry+https://github.com/rust-lang/crates.io-index"
210
- checksum = "9dff85ebcaab8c441b0e3f7ae40a6963ecea8a9f5e74f647e33fcf5ec9a1e89e"
210
+ checksum = "4109984c22491085343c05b0dbc54ddc405c3cf7b4374fc533f5c3313a572ccc"
211
211
  dependencies = [
212
212
  "heck",
213
213
  "proc-macro2",
@@ -295,9 +295,9 @@ dependencies = [
295
295
 
296
296
  [[package]]
297
297
  name = "syn"
298
- version = "2.0.101"
298
+ version = "2.0.104"
299
299
  source = "registry+https://github.com/rust-lang/crates.io-index"
300
- checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
300
+ checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
301
301
  dependencies = [
302
302
  "proc-macro2",
303
303
  "quote",
@@ -318,9 +318,9 @@ checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
318
318
 
319
319
  [[package]]
320
320
  name = "unicode-width"
321
- version = "0.2.0"
321
+ version = "0.2.1"
322
322
  source = "registry+https://github.com/rust-lang/crates.io-index"
323
- checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
323
+ checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
324
324
 
325
325
  [[package]]
326
326
  name = "unindent"
@@ -330,9 +330,9 @@ checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
330
330
 
331
331
  [[package]]
332
332
  name = "wasi"
333
- version = "0.11.0+wasi-snapshot-preview1"
333
+ version = "0.11.1+wasi-snapshot-preview1"
334
334
  source = "registry+https://github.com/rust-lang/crates.io-index"
335
- checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
335
+ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
336
336
 
337
337
  [[package]]
338
338
  name = "wasm-bindgen"
@@ -487,18 +487,18 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
487
487
 
488
488
  [[package]]
489
489
  name = "zerocopy"
490
- version = "0.8.25"
490
+ version = "0.8.26"
491
491
  source = "registry+https://github.com/rust-lang/crates.io-index"
492
- checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
492
+ checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
493
493
  dependencies = [
494
494
  "zerocopy-derive",
495
495
  ]
496
496
 
497
497
  [[package]]
498
498
  name = "zerocopy-derive"
499
- version = "0.8.25"
499
+ version = "0.8.26"
500
500
  source = "registry+https://github.com/rust-lang/crates.io-index"
501
- checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
501
+ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
502
502
  dependencies = [
503
503
  "proc-macro2",
504
504
  "quote",
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.4
2
+ Name: wildflow-splat
3
+ Version: 0.1.4
4
+ Classifier: Development Status :: 4 - Beta
5
+ Classifier: Intended Audience :: Developers
6
+ Classifier: Intended Audience :: Science/Research
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.8
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Rust
15
+ Classifier: Topic :: Scientific/Engineering
16
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Requires-Dist: maturin>=1.0 ; extra == 'dev'
19
+ Requires-Dist: pytest>=7.0 ; extra == 'dev'
20
+ Provides-Extra: dev
21
+ License-File: LICENSE
22
+ Summary: Fast PLY point cloud processing for 3D Gaussian splatting workflows
23
+ Keywords: ply,point-cloud,3d-gaussian-splatting,colmap,photogrammetry,computer-vision
24
+ Author-email: Wildflow AI <info@wildflow.ai>
25
+ License: MIT
26
+ Requires-Python: >=3.8
27
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
28
+ Project-URL: repository, https://github.com/wildflowai/wildflow-splat
29
+ Project-URL: documentation, https://docs.wildflow.ai
30
+
31
+ Super hacky library to work with coral reef splats.
32
+
33
+ You can swim with a few GoPros around a reef (e.g. [wildflow.ai/protocol](https://wildflow.ai/protocol)) and then turn the footage into 3D models (e.g. [wildflow.ai/demo](https://wildflow.ai/demo)) to track changes over time, run different analysis on top of it, and ultimately see which conservation/restoration methods work best.
34
+
35
+ This is a bunch of primitives to process the data.
36
+
37
+ # Usage
38
+ Install with
39
+ ```
40
+ pip install wildflow
41
+ ```
42
+ So you can play with it from python:
43
+ ```py
44
+ from wildflow import splat
45
+ splat.split(...)
46
+ ```
47
+ # Workflow
48
+
49
+ ## SfM workflow
50
+ Turns images from cameras 3D point cloud and
51
+
52
+ ![](/images/wildflow-3dgs-wf.svg)
53
+
54
+ # Local Development
55
+
56
+ This library uses Rust extensions built with Maturin. To set up locally:
57
+
58
+ ```bash
59
+ # Create virtual environment
60
+ python3 -m venv venv
61
+ source venv/bin/activate
62
+
63
+ # Install Rust (if not already installed)
64
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
65
+ source "$HOME/.cargo/env"
66
+
67
+ # Install dependencies and build
68
+ pip install maturin
69
+ pip install -r requirements.txt
70
+ maturin develop
71
+ ```
72
+
73
+ After making changes to Rust code, rebuild with `maturin develop`.
74
+
@@ -0,0 +1,43 @@
1
+ Super hacky library to work with coral reef splats.
2
+
3
+ You can swim with a few GoPros around a reef (e.g. [wildflow.ai/protocol](https://wildflow.ai/protocol)) and then turn the footage into 3D models (e.g. [wildflow.ai/demo](https://wildflow.ai/demo)) to track changes over time, run different analysis on top of it, and ultimately see which conservation/restoration methods work best.
4
+
5
+ This is a bunch of primitives to process the data.
6
+
7
+ # Usage
8
+ Install with
9
+ ```
10
+ pip install wildflow
11
+ ```
12
+ So you can play with it from python:
13
+ ```py
14
+ from wildflow import splat
15
+ splat.split(...)
16
+ ```
17
+ # Workflow
18
+
19
+ ## SfM workflow
20
+ Turns images from cameras 3D point cloud and
21
+
22
+ ![](/images/wildflow-3dgs-wf.svg)
23
+
24
+ # Local Development
25
+
26
+ This library uses Rust extensions built with Maturin. To set up locally:
27
+
28
+ ```bash
29
+ # Create virtual environment
30
+ python3 -m venv venv
31
+ source venv/bin/activate
32
+
33
+ # Install Rust (if not already installed)
34
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
35
+ source "$HOME/.cargo/env"
36
+
37
+ # Install dependencies and build
38
+ pip install maturin
39
+ pip install -r requirements.txt
40
+ maturin develop
41
+ ```
42
+
43
+ After making changes to Rust code, rebuild with `maturin develop`.
@@ -0,0 +1,140 @@
1
+ """
2
+ Example usage of wildflow.splat.patches library for COLMAP camera partitioning.
3
+ Interactive sliders allow you to explore how different parameters affect the partitioning.
4
+ """
5
+
6
+ import pycolmap
7
+ import matplotlib.pyplot as plt
8
+ import matplotlib.patches as patches
9
+ from matplotlib.widgets import Slider
10
+ import math
11
+ from wildflow.splat import patches as splat_patches, BoundingBox
12
+
13
+ # Constants
14
+ COLMAP_FOLDER = "/Users/nsv/corals/soneva/0/"
15
+ MAX_CAMERAS = 50
16
+ BUFFER_METERS = 0.0
17
+ TARGET_BINS = 100
18
+
19
+ def rotate30(cameras: list[tuple[float, float]]) -> list[tuple[float, float]]:
20
+ """Rotate camera positions by 30 degrees counter-clockwise."""
21
+ angle_rad = math.radians(30)
22
+ cos_angle = math.cos(angle_rad)
23
+ sin_angle = math.sin(angle_rad)
24
+
25
+ rotated = []
26
+ for x, y in cameras:
27
+ x_rot = x * cos_angle - y * sin_angle
28
+ y_rot = x * sin_angle + y * cos_angle
29
+ rotated.append((x_rot, y_rot))
30
+
31
+ return rotated
32
+
33
+ def create_interactive_plot(cameras: list[tuple[float, float]]) -> None:
34
+ """Create interactive plot with sliders for parameter adjustment."""
35
+ # Create figure with space for sliders at bottom (smaller to fit on screen)
36
+ fig = plt.figure(figsize=(12, 9))
37
+
38
+ # Main plot takes up most of the space
39
+ ax_main = plt.axes((0.1, 0.3, 0.8, 0.6))
40
+
41
+ # Create slider axes with proper spacing
42
+ ax_max_cameras = plt.axes((0.2, 0.2, 0.6, 0.03))
43
+ ax_buffer = plt.axes((0.2, 0.15, 0.6, 0.03))
44
+ ax_target_bins = plt.axes((0.2, 0.1, 0.6, 0.03))
45
+
46
+ # Create sliders with nice snapping values
47
+ slider_max_cameras = Slider(ax_max_cameras, 'Max Cameras', 1, 2000, valinit=MAX_CAMERAS, valfmt='%d')
48
+ # Buffer slider with 100 beautiful steps (0.02 increments)
49
+ slider_buffer = Slider(ax_buffer, 'Buffer (m)', 0.0, 2.0, valinit=BUFFER_METERS, valfmt='%.2f',
50
+ valstep=0.02)
51
+ slider_target_bins = Slider(ax_target_bins, 'Target Bins', 10, 300, valinit=TARGET_BINS, valfmt='%d')
52
+
53
+ def update_plot(val=None):
54
+ """Update the plot when sliders change."""
55
+ # Clear the main plot
56
+ ax_main.clear()
57
+
58
+ # Get current slider values
59
+ max_cameras = int(slider_max_cameras.val)
60
+ buffer_meters = slider_buffer.val
61
+ target_bins = int(slider_target_bins.val)
62
+
63
+ # Run partitioning with current parameters
64
+ try:
65
+ bboxes = splat_patches(
66
+ cameras,
67
+ max_cameras=max_cameras,
68
+ buffer_meters=buffer_meters,
69
+ target_bins=target_bins
70
+ )
71
+
72
+ # Plot camera positions
73
+ x_coords = [pos[0] for pos in cameras]
74
+ y_coords = [pos[1] for pos in cameras]
75
+ ax_main.scatter(x_coords, y_coords, c='red', s=20, alpha=0.7,
76
+ edgecolors='black', linewidth=0.3, zorder=2)
77
+
78
+ # Draw bounding boxes
79
+ for i, bbox in enumerate(bboxes):
80
+ rect = patches.Rectangle(
81
+ (bbox.min_x, bbox.min_y), bbox.width, bbox.height,
82
+ linewidth=2, edgecolor='blue', facecolor='lightblue', alpha=0.3, zorder=1
83
+ )
84
+ ax_main.add_patch(rect)
85
+
86
+ # Add box number
87
+ center_x = bbox.min_x + bbox.width / 2
88
+ center_y = bbox.min_y + bbox.height / 2
89
+ ax_main.text(center_x, center_y, str(i+1),
90
+ horizontalalignment='center', verticalalignment='center',
91
+ fontsize=12, color='blue', fontweight='bold', zorder=3,
92
+ bbox=dict(boxstyle="round,pad=0.3", facecolor='white', alpha=0.8))
93
+
94
+ # Update title with current parameters
95
+ ax_main.set_title(f'Camera Partitioning: {len(bboxes)} patches '
96
+ f'(max_cameras={max_cameras}, buffer={buffer_meters:.2f}m, bins={target_bins})')
97
+
98
+ except Exception as e:
99
+ # Show error message if partitioning fails
100
+ ax_main.text(0.5, 0.5, f'Error: {str(e)}',
101
+ transform=ax_main.transAxes, ha='center', va='center',
102
+ fontsize=14, color='red', bbox=dict(boxstyle="round", facecolor='yellow', alpha=0.8))
103
+ ax_main.set_title('Partitioning Failed - Try Different Parameters')
104
+
105
+ ax_main.set_xlabel('X Position')
106
+ ax_main.set_ylabel('Y Position')
107
+ ax_main.grid(True, alpha=0.3)
108
+ ax_main.set_aspect('equal')
109
+
110
+ # Redraw
111
+ fig.canvas.draw()
112
+
113
+ # Connect sliders to update function
114
+ slider_max_cameras.on_changed(update_plot)
115
+ slider_buffer.on_changed(update_plot)
116
+ slider_target_bins.on_changed(update_plot)
117
+
118
+ # Initial plot
119
+ update_plot()
120
+
121
+ plt.show()
122
+
123
+ def main():
124
+ # Load camera positions using the exact pattern from docstring
125
+ print("Loading camera positions...")
126
+ model = pycolmap.Reconstruction(COLMAP_FOLDER)
127
+ cameras = [(img.projection_center()[0], img.projection_center()[1])
128
+ for img in model.images.values()]
129
+ print(f"Loaded {len(cameras)} camera positions")
130
+
131
+ # Rotate cameras (can be commented out easily)
132
+ cameras = rotate30(cameras)
133
+
134
+ # Create interactive visualization
135
+ print("Creating interactive visualization...")
136
+ print("Use the sliders to adjust parameters and see how they affect the partitioning!")
137
+ create_interactive_plot(cameras)
138
+
139
+ if __name__ == "__main__":
140
+ main()
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "wildflow"
7
- version = "0.1.3"
7
+ version = "0.1.4"
8
8
  description = "Modeling natural ecosystems"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -28,7 +28,7 @@ classifiers = [
28
28
  "Topic :: Software Development :: Libraries :: Python Modules",
29
29
  ]
30
30
  dependencies = [
31
- "wildflow-splat>=0.1.3",
31
+ "wildflow-splat>=0.1.4",
32
32
  ]
33
33
 
34
34
  [project.urls]
@@ -1,6 +1,7 @@
1
1
  use pyo3::prelude::*;
2
2
 
3
3
  mod split;
4
+ mod patches;
4
5
 
5
6
  /// The main PyO3 module for wildflow.splat
6
7
  #[pymodule]
@@ -9,5 +10,10 @@ fn _core(m: &Bound<'_, PyModule>) -> PyResult<()> {
9
10
  m.add_class::<split::Config>()?;
10
11
  m.add_class::<split::Patch>()?;
11
12
  m.add_function(wrap_pyfunction!(split::split_ply, m)?)?;
13
+
14
+ // Export patches functionality
15
+ m.add_class::<patches::BoundingBox>()?;
16
+ m.add_function(wrap_pyfunction!(patches::patches, m)?)?;
17
+
12
18
  Ok(())
13
19
  }