img-phy-sim 0.4__tar.gz → 0.8__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.
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: img-phy-sim
3
- Version: 0.4
3
+ Version: 0.8
4
4
  Summary: Physical Simulations on Images.
5
5
  Home-page: https://github.com/M-106/Image-Physics-Simulation
6
- Download-URL: https://github.com/M-106/Image-Physics-Simulation/archive/v_03.tar.gz
6
+ Download-URL: https://github.com/M-106/Image-Physics-Simulation/archive/v_04.tar.gz
7
7
  Author: Tobia Ippolito
8
8
  Project-URL: Documentation, https://M-106.github.io/Image-Physics-Simulation/img_phy_sim
9
9
  Project-URL: Source, https://github.com/M-106/Image-Physics-Simulation
@@ -21,6 +21,13 @@ Requires-Dist: numpy
21
21
  Requires-Dist: opencv-python
22
22
  Requires-Dist: matplotlib
23
23
  Requires-Dist: scikit-image
24
+ Requires-Dist: joblib
25
+ Requires-Dist: shapely
26
+ Provides-Extra: full
27
+ Requires-Dist: torch; extra == "full"
28
+ Requires-Dist: torchvision; extra == "full"
29
+ Requires-Dist: datasets==3.6.0; extra == "full"
30
+ Requires-Dist: prime_printer; extra == "full"
24
31
  Dynamic: author
25
32
  Dynamic: classifier
26
33
  Dynamic: description
@@ -29,6 +36,7 @@ Dynamic: download-url
29
36
  Dynamic: home-page
30
37
  Dynamic: keywords
31
38
  Dynamic: project-url
39
+ Dynamic: provides-extra
32
40
  Dynamic: requires-dist
33
41
  Dynamic: summary
34
42
 
@@ -44,10 +52,14 @@ Contents:
44
52
  - [Raytracing Computation](#raytracing-computation)
45
53
  - [Raytracing Tutorial](#raytracing-tutorial)
46
54
  - [Performance Test](#performance-test)
55
+ - [Ray-Tracing Formats](#ray-tracing-formats)
47
56
 
48
57
  [> Documentation <](https://M-106.github.io/Image-Physics-Simulation/img_phy_sim.html)
49
58
 
50
- <img src="https://github.com/M-106/Image-Physics-Simulation/raw/main/img_phy_sim/raytracing_example.png"></img>
59
+ <img src="https://github.com/M-106/Image-Physics-Simulation/raw/main/img_phy_sim/raytracing_example.png" width="46%"></img>
60
+ <img src="https://github.com/M-106/Image-Physics-Simulation/raw/main/img_phy_sim/ism_example.png" width="46%"></img>
61
+
62
+ > Ray-Beams and ISM
51
63
 
52
64
  <br><br>
53
65
 
@@ -58,18 +70,27 @@ This repo only need some basic libraries:
58
70
  - `matplotlib`
59
71
  - `opencv-python`
60
72
  - `scikit-image`
73
+ - `joblib`
74
+
75
+ If you want to use the `data` module then this package needs also:
76
+ - `torch`
77
+ - `torchvision`
78
+ - `datasets`
79
+ - `prime_printer`
61
80
 
62
81
  You can download / clone this repo and run the example notebook via following Python/Anaconda setup:
63
82
  ```bash
64
83
  conda create -n img-phy-sim python=3.13 pip -y
65
84
  conda activate img-phy-sim
66
- pip install numpy matplotlib opencv-python ipython jupyter shapely prime_printer datasets==3.6.0 scikit-image
85
+ pip install numpy matplotlib opencv-python ipython jupyter shapely prime_printer datasets==3.6.0 scikit-image joblib shapely
67
86
  pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
68
87
  ```
69
88
 
70
89
  You can also use this repo via [Python Package Index (PyPI)](https://pypi.org/) as a package:
71
90
  ```bash
72
91
  pip install img-phy-sim
92
+ # or for using `data` module:
93
+ pip install img-phy-sim[full]
73
94
  ```
74
95
 
75
96
  Here the instructions to use the package version of `ips` and an anconda setup:
@@ -77,11 +98,13 @@ Here the instructions to use the package version of `ips` and an anconda setup:
77
98
  conda create -n img-phy-sim python=3.13 pip -y
78
99
  conda activate img-phy-sim
79
100
  pip install img-phy-sim
101
+ # or for using `data` module:
102
+ pip install img-phy-sim[full]
80
103
  ```
81
104
 
82
- To run the example code you still need:
105
+ To run the example code you also need (this is included in `img-phy-sim[full]`):
83
106
  ```bash
84
- pip install prime_printer shapely datasets==3.6.0
107
+ pip install prime_printer datasets==3.6.0
85
108
  pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
86
109
  ```
87
110
 
@@ -89,20 +112,20 @@ pip install torch torchvision torchaudio --index-url https://download.pytorch.or
89
112
 
90
113
  ### Download Example Data
91
114
 
92
- You can download Physgen data if wanted via the `physgen_dataset.py` using following commands:
115
+ You can download Physgen data if wanted via the `data.py` using following commands:
93
116
 
94
117
  ```bash
95
118
  conda activate img-phy-sim
96
- cd "D:\Informatik\Projekte\Image-Physics-Simulation" && D:
97
- python physgen_dataset.py --output_real_path ./datasets/physgen_train_raw/real --output_osm_path ./datasets/physgen_train_raw/osm --variation sound_reflection --input_type osm --output_type standard --data_mode train
119
+ cd "D:\Informatik\Projekte\Image-Physics-Simulation\img_phy_sim" && D:
120
+ python data.py --output_real_path ./datasets/physgen_train_raw/real --output_osm_path ./datasets/physgen_train_raw/osm --variation sound_reflection --input_type osm --output_type standard --data_mode train
98
121
  ```
99
122
 
100
123
  ```bash
101
- python physgen_dataset.py --output_real_path ./datasets/physgen_test_raw/real --output_osm_path ./datasets/physgen_test_raw/osm --variation sound_reflection --input_type osm --output_type standard --data_mode test
124
+ python data.py --output_real_path ./datasets/physgen_test_raw/real --output_osm_path ./datasets/physgen_test_raw/osm --variation sound_reflection --input_type osm --output_type standard --data_mode test
102
125
  ```
103
126
 
104
127
  ```bash
105
- python physgen_dataset.py --output_real_path ./datasets/physgen_val_raw/real --output_osm_path ./datasets/physgen_val_raw/osm --variation sound_reflection --input_type osm --output_type standard --data_mode validation
128
+ python data.py --output_real_path ./datasets/physgen_val_raw/real --output_osm_path ./datasets/physgen_val_raw/osm --variation sound_reflection --input_type osm --output_type standard --data_mode validation
106
129
  ```
107
130
 
108
131
  <br><br>
@@ -196,6 +219,23 @@ class PhysGenDataset(Dataset):
196
219
  - `open`: load your saved rays txt file
197
220
  - `get_linear_degree_range`: get a range for your beam-directions -> example beams between 0-360 with stepsize 10
198
221
  - `merge_rays`: merge 2 rays to one 'object'
222
+ - `ism`
223
+ - `reflect_point_across_infinite_line`: Reflects a point across the infinite line defined by two endpoints
224
+ - `paths_to_rays`: Converts polyline paths into your ray/segment representation, optionally normalizing points to ([0,1]) image space
225
+ - `reflection_map_to_img`: Normalizes a float reflection/energy map to a uint8 visualization image in ([0,255])
226
+ - `Segment`: Immutable dataclass representing a 2D line segment with convenience access to its endpoints
227
+ - `_seg_seg_intersection`: Computes the unique intersection point of two finite 2D segments, returning None for parallel/colinear/no-hit cases
228
+ - `_bresenham_points`: Generates all integer grid points along a line between two pixels using Bresenham’s algorithm
229
+ - `is_visible_raster`: Tests line-of-sight between two points by checking whether Bresenham-sampled pixels hit an occlusion raster
230
+ - `build_wall_mask`: Builds a binary 0/255 wall mask from an input image using explicit wall labels or mask-like heuristics
231
+ - `get_wall_segments_from_mask`: Extracts wall boundary contours from a binary mask and converts them into geometric Segment primitives
232
+ - `build_occlusion_from_wallmask`: Produces a binary occlusion raster (optionally dilated) used for fast visibility checks
233
+ - `enumerate_wall_sequences_indices`: Enumerates all reflection sequences (as wall-index tuples) up to a maximum reflection order
234
+ - `precompute_image_sources`: Computes image-source positions for each reflection sequence by iteratively mirroring the source across the corresponding walls
235
+ - `build_path_for_sequence`: Reconstructs the specular reflection polyline for a given wall sequence by backtracking virtual receivers and segment intersections
236
+ - `path_energy`: Computes a simple physically-inspired path contribution based on total path length and per-reflection losses
237
+ - `check_path_visibility_raster`: Verifies that every segment of a candidate path is unobstructed using raster line-of-sight tests
238
+ - `compute_reflection_map`: Evaluates all valid ISM paths from one source to a receiver grid and accumulates path counts
199
239
  - `img`
200
240
  - `open`: load an image via Open-CV
201
241
  - `save`: save an image
@@ -203,6 +243,21 @@ class PhysGenDataset(Dataset):
203
243
  - `advanced_imshow`: show multiple images with many options
204
244
  - `show_image_with_line_and_profile`: show an image with a red line + the values of the image on this line
205
245
  - `plot_image_with_values`: plot an image with it's value plotted and averaged to see your image in values
246
+ - `math`
247
+ - `get_linear_degree_range`: generate evenly spaced degrees within a range
248
+ - `degree_to_vector`: convert a degree angle to a 2D unit vector
249
+ - `vector_to_degree`: convert a 2D vector into its corresponding degree
250
+ - `normalize_point`: Normalize a 2D point to [0, 1] range
251
+ - `denormalize_point`: Denormalize a 2D point to pixel coordinates
252
+ - `numpy_info`: Get statistics about an numpy array
253
+ - `eval`
254
+ - `calc_metrices`: calculate F1, Recall and Precision between rays (or optinal an image) and an image
255
+ - `data`
256
+ - `PhysGenDataset()`: PyTorch dataset wrapper for PhysGen with flexible input/output configuration
257
+ - `resize_tensor_to_divisible_by_14`: resize tensors so height and width are divisible by 14
258
+ - `get_dataloader`: create a PyTorch DataLoader for the PhysGen dataset
259
+ - `get_image`: retrieve a single dataset sample (optionally as NumPy arrays)
260
+ - `save_dataset`: export PhysGen inputs and targets as PNG images to disk
206
261
 
207
262
 
208
263
  That are not all functions but the ones which should be most useful. Check out the documentation for all functions.
@@ -225,14 +280,9 @@ That are not all functions but the ones which should be most useful. Check out t
225
280
  [See also the example notebook 👀](./example/physgen.ipynb)
226
281
 
227
282
  In general you need to do:
228
- 1. **Load your Image** -> using `ips.img.open`
229
- 2. **Calculate the Wall-Map** -> using `ips.ray_tracing.get_wall_map`
230
- 3. **Calculate the Beams** -> using `ips.img.open`
231
- 4. **Draw (Export) the Beams** -> using `ips.img.open`
283
+ 1. Load your Image + Calculate the Wall-Map + **Calculate the Beams** -> using `ips.ray_tracing.trace_beams`
284
+ 2. **Draw (Export) the Beams on a image** -> using `ips.ray_tracing.draw_rays`
232
285
 
233
- Using this lib, this is reduced to:
234
- 1. **Calculate the Beams** (including Wall-Map and loading your Image) -> using `ips.img.open`
235
- 2. **Draw (Export) the Beams** -> using `ips.img.open`
236
286
 
237
287
  See this example:
238
288
 
@@ -361,7 +411,17 @@ I hope this little tutorial could be helpful. Good luck with your project <3
361
411
 
362
412
  <br>
363
413
 
364
- [> See the notebook/code <](./example/physgen_performance.ipynb)
414
+ [> See the notebook/code <](./example/physgen_performance.ipynb) [(or parallel notebook)](./example/physgen_parallel_performance.ipynb)
415
+
416
+ <br><br>
417
+
418
+ Comparison no parallel vs parallel computing:
419
+ - Parallel Mean Experiment time: 3.48 seconds (mean first experiment: 8.85 seconds)
420
+ - Standard Mean Experiment time: 4.53 seconds (mean first experiment: 16.00 seconds)
421
+
422
+ <br><br>
423
+
424
+ Parameter Experiments:
365
425
 
366
426
  Executed with 50 random images.
367
427
 
@@ -481,6 +541,123 @@ The Stepsize/amount of rays have the biggest impact on the performance. The othe
481
541
  | **3. Reflection Order** | 6 | 0.93 ± 0.74 s | 0.90 ± 0.72 s | 0.029 ± 0.016 s | **227.71 %** | Increasing (+0.37 s/exp) | Performance changes **significantly** |
482
542
  | **4. Detail Draw** | 2 | 0.63 ± 0.05 s | 0.56 ± 0.00 s | 0.071 ± 0.050 s | **16.39 %** | Increasing (+0.10 s/exp) | Performance changes **slightly** |
483
543
 
544
+ <!--
545
+ <br><br>
546
+
547
+ ### Optimization
548
+
549
+ <br>
550
+
551
+ Speed comparison between `standard`, `with joblib` and `joblib + CPython`.
552
+
553
+ FIXME -> table
554
+
555
+
556
+ <br>
557
+
558
+ Cython is Pyhon code which is closer to C. Instead of compiling to Python-Bytecode (`.pyc`), your code will be compiled as C-Extension (`.so`/`.pyd`).
559
+
560
+ There are 3 layers of Cython optimization:
561
+ 1. Writing in `.pyx` files not `.py` files -> you can just rename your file<br>
562
+ - +5% to +30% speedup
563
+ 2. Set `cdef` for local variables + helper-functions + `cpdef` for API-functions -> add types<br>
564
+ Example:
565
+ ```python
566
+ cdef double x0, y0, dx, dy
567
+ cdef int cell_x, cell_y, steps
568
+ ```
569
+ - +5x to +50x speedup
570
+ 3. Add types everywhere, especially in numpy arrays. <br>
571
+ Example:
572
+ ```python
573
+ cimport numpy as cnp
574
+
575
+ def trace(..., cnp.ndarray[double, ndim=2] img):
576
+ cdef double value = img[y, x]
577
+ ```
578
+ - +20× to +500×
579
+
580
+
581
+
582
+ | **Optimization Layer** | **Effort** | **Speedup** | **What It Does** |
583
+ |---|---|---|---|
584
+ | **1. `.py` → `.pyx`** | minimal | **+5–30%** | Reduces Python interpreter overhead and applies basic Cython optimizations |
585
+ | **2. `cdef` variables & `cpdef` functions** | medium | **+5×–50×** | Moves loops and math into pure C, eliminating Python object overhead |
586
+ | **3. `cimport numpy` + typed NumPy arrays** | high | **+20×–500×** | Enables direct C‑level memory access with zero Python indexing overhead |
587
+
588
+
589
+
590
+ > Use `pip install cypthon` to install it.
591
+
592
+ In `setup.py` you need following changes:
593
+ ```python
594
+ from setuptools import setup, find_packages, Extension
595
+ from Cython.Build import cythonize
596
+
597
+ ...
598
+
599
+ ext_1 = Extension(
600
+ name="img_phy_sim.ray_tracing",
601
+ sources=["img_phy_sim/ray_tracing.pyx"],
602
+ include_dirs=[],
603
+ extra_compile_args=["-O3"],
604
+ )
605
+
606
+ ext_2 = Extension(
607
+ name="img_phy_sim.math",
608
+ sources=["img_phy_sim/math.pyx"],
609
+ include_dirs=[],
610
+ extra_compile_args=["-O3"],
611
+ )
612
+
613
+ setup(
614
+ ext_modules=cythonize(
615
+ [ext_1, ext_2],
616
+ compiler_directives={
617
+ "language_level": "3",
618
+ "boundscheck": False,
619
+ "wraparound": False,
620
+ "initializedcheck": False,
621
+ "nonecheck": False,
622
+ "cdivision": True,
623
+ },
624
+ annotate=True,
625
+ ),
626
+ ...
627
+ )
628
+ ```
629
+
630
+ -->
631
+
632
+ <br><br>
633
+
634
+ ### Ray-Tracing Formats
635
+
636
+ <br>
637
+
638
+
639
+ **Your current approach (DDA / Pixel Ray Marching)**
640
+ * **Forward integration**: Ray is propagated step by step through a **discrete grid** (pixel/grid).
641
+ * **Collision model**: A "hit" occurs when the ray enters a **wall cell** (quantization).
642
+ * **Reflection**: Occurs **locally at the collision pixel** with a (often quantized) normal/orientation.
643
+ * Result: good for "many rays" / field of view, but **not deterministic with regard to reflection paths** (you need directions/sampling).
644
+
645
+ **Noise modeling style (image source method / geometric acoustics)**
646
+ * **Path construction**: Reflection paths are constructed **deterministically** via **mirror sources** (virtual sources).
647
+ * **Continuous geometry**: works in $\mathbb{R}^2 / \mathbb{R}^3$ with lines/segments/polygons ("infinity-based" in the sense of *continuous space*, not raster).
648
+ * **Validation**: Path is then accepted/rejected via **visibility/occlusion checks**.
649
+ * Result: Delivers **all specular paths up to order N** without angle sampling.
650
+
651
+ Short form:
652
+
653
+ * **Pixel-based + stochastic/directed** (original approach here) vs. **continuous + deterministically constructed** (noise modelling).
654
+
655
+
656
+ <br>
657
+
658
+ How to use which of them in `img-phy-sim`:
659
+
660
+ FIXME
484
661
 
485
662
 
486
663
 
@@ -10,10 +10,14 @@ Contents:
10
10
  - [Raytracing Computation](#raytracing-computation)
11
11
  - [Raytracing Tutorial](#raytracing-tutorial)
12
12
  - [Performance Test](#performance-test)
13
+ - [Ray-Tracing Formats](#ray-tracing-formats)
13
14
 
14
15
  [> Documentation <](https://M-106.github.io/Image-Physics-Simulation/img_phy_sim.html)
15
16
 
16
- <img src="./img_phy_sim/raytracing_example.png"></img>
17
+ <img src="./img_phy_sim/raytracing_example.png" width="46%"></img>
18
+ <img src="./img_phy_sim/ism_example.png" width="46%"></img>
19
+
20
+ > Ray-Beams and ISM
17
21
 
18
22
  <br><br>
19
23
 
@@ -24,18 +28,27 @@ This repo only need some basic libraries:
24
28
  - `matplotlib`
25
29
  - `opencv-python`
26
30
  - `scikit-image`
31
+ - `joblib`
32
+
33
+ If you want to use the `data` module then this package needs also:
34
+ - `torch`
35
+ - `torchvision`
36
+ - `datasets`
37
+ - `prime_printer`
27
38
 
28
39
  You can download / clone this repo and run the example notebook via following Python/Anaconda setup:
29
40
  ```bash
30
41
  conda create -n img-phy-sim python=3.13 pip -y
31
42
  conda activate img-phy-sim
32
- pip install numpy matplotlib opencv-python ipython jupyter shapely prime_printer datasets==3.6.0 scikit-image
43
+ pip install numpy matplotlib opencv-python ipython jupyter shapely prime_printer datasets==3.6.0 scikit-image joblib shapely
33
44
  pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
34
45
  ```
35
46
 
36
47
  You can also use this repo via [Python Package Index (PyPI)](https://pypi.org/) as a package:
37
48
  ```bash
38
49
  pip install img-phy-sim
50
+ # or for using `data` module:
51
+ pip install img-phy-sim[full]
39
52
  ```
40
53
 
41
54
  Here the instructions to use the package version of `ips` and an anconda setup:
@@ -43,11 +56,13 @@ Here the instructions to use the package version of `ips` and an anconda setup:
43
56
  conda create -n img-phy-sim python=3.13 pip -y
44
57
  conda activate img-phy-sim
45
58
  pip install img-phy-sim
59
+ # or for using `data` module:
60
+ pip install img-phy-sim[full]
46
61
  ```
47
62
 
48
- To run the example code you still need:
63
+ To run the example code you also need (this is included in `img-phy-sim[full]`):
49
64
  ```bash
50
- pip install prime_printer shapely datasets==3.6.0
65
+ pip install prime_printer datasets==3.6.0
51
66
  pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
52
67
  ```
53
68
 
@@ -55,20 +70,20 @@ pip install torch torchvision torchaudio --index-url https://download.pytorch.or
55
70
 
56
71
  ### Download Example Data
57
72
 
58
- You can download Physgen data if wanted via the `physgen_dataset.py` using following commands:
73
+ You can download Physgen data if wanted via the `data.py` using following commands:
59
74
 
60
75
  ```bash
61
76
  conda activate img-phy-sim
62
- cd "D:\Informatik\Projekte\Image-Physics-Simulation" && D:
63
- python physgen_dataset.py --output_real_path ./datasets/physgen_train_raw/real --output_osm_path ./datasets/physgen_train_raw/osm --variation sound_reflection --input_type osm --output_type standard --data_mode train
77
+ cd "D:\Informatik\Projekte\Image-Physics-Simulation\img_phy_sim" && D:
78
+ python data.py --output_real_path ./datasets/physgen_train_raw/real --output_osm_path ./datasets/physgen_train_raw/osm --variation sound_reflection --input_type osm --output_type standard --data_mode train
64
79
  ```
65
80
 
66
81
  ```bash
67
- python physgen_dataset.py --output_real_path ./datasets/physgen_test_raw/real --output_osm_path ./datasets/physgen_test_raw/osm --variation sound_reflection --input_type osm --output_type standard --data_mode test
82
+ python data.py --output_real_path ./datasets/physgen_test_raw/real --output_osm_path ./datasets/physgen_test_raw/osm --variation sound_reflection --input_type osm --output_type standard --data_mode test
68
83
  ```
69
84
 
70
85
  ```bash
71
- python physgen_dataset.py --output_real_path ./datasets/physgen_val_raw/real --output_osm_path ./datasets/physgen_val_raw/osm --variation sound_reflection --input_type osm --output_type standard --data_mode validation
86
+ python data.py --output_real_path ./datasets/physgen_val_raw/real --output_osm_path ./datasets/physgen_val_raw/osm --variation sound_reflection --input_type osm --output_type standard --data_mode validation
72
87
  ```
73
88
 
74
89
  <br><br>
@@ -162,6 +177,23 @@ class PhysGenDataset(Dataset):
162
177
  - `open`: load your saved rays txt file
163
178
  - `get_linear_degree_range`: get a range for your beam-directions -> example beams between 0-360 with stepsize 10
164
179
  - `merge_rays`: merge 2 rays to one 'object'
180
+ - `ism`
181
+ - `reflect_point_across_infinite_line`: Reflects a point across the infinite line defined by two endpoints
182
+ - `paths_to_rays`: Converts polyline paths into your ray/segment representation, optionally normalizing points to ([0,1]) image space
183
+ - `reflection_map_to_img`: Normalizes a float reflection/energy map to a uint8 visualization image in ([0,255])
184
+ - `Segment`: Immutable dataclass representing a 2D line segment with convenience access to its endpoints
185
+ - `_seg_seg_intersection`: Computes the unique intersection point of two finite 2D segments, returning None for parallel/colinear/no-hit cases
186
+ - `_bresenham_points`: Generates all integer grid points along a line between two pixels using Bresenham’s algorithm
187
+ - `is_visible_raster`: Tests line-of-sight between two points by checking whether Bresenham-sampled pixels hit an occlusion raster
188
+ - `build_wall_mask`: Builds a binary 0/255 wall mask from an input image using explicit wall labels or mask-like heuristics
189
+ - `get_wall_segments_from_mask`: Extracts wall boundary contours from a binary mask and converts them into geometric Segment primitives
190
+ - `build_occlusion_from_wallmask`: Produces a binary occlusion raster (optionally dilated) used for fast visibility checks
191
+ - `enumerate_wall_sequences_indices`: Enumerates all reflection sequences (as wall-index tuples) up to a maximum reflection order
192
+ - `precompute_image_sources`: Computes image-source positions for each reflection sequence by iteratively mirroring the source across the corresponding walls
193
+ - `build_path_for_sequence`: Reconstructs the specular reflection polyline for a given wall sequence by backtracking virtual receivers and segment intersections
194
+ - `path_energy`: Computes a simple physically-inspired path contribution based on total path length and per-reflection losses
195
+ - `check_path_visibility_raster`: Verifies that every segment of a candidate path is unobstructed using raster line-of-sight tests
196
+ - `compute_reflection_map`: Evaluates all valid ISM paths from one source to a receiver grid and accumulates path counts
165
197
  - `img`
166
198
  - `open`: load an image via Open-CV
167
199
  - `save`: save an image
@@ -169,6 +201,21 @@ class PhysGenDataset(Dataset):
169
201
  - `advanced_imshow`: show multiple images with many options
170
202
  - `show_image_with_line_and_profile`: show an image with a red line + the values of the image on this line
171
203
  - `plot_image_with_values`: plot an image with it's value plotted and averaged to see your image in values
204
+ - `math`
205
+ - `get_linear_degree_range`: generate evenly spaced degrees within a range
206
+ - `degree_to_vector`: convert a degree angle to a 2D unit vector
207
+ - `vector_to_degree`: convert a 2D vector into its corresponding degree
208
+ - `normalize_point`: Normalize a 2D point to [0, 1] range
209
+ - `denormalize_point`: Denormalize a 2D point to pixel coordinates
210
+ - `numpy_info`: Get statistics about an numpy array
211
+ - `eval`
212
+ - `calc_metrices`: calculate F1, Recall and Precision between rays (or optinal an image) and an image
213
+ - `data`
214
+ - `PhysGenDataset()`: PyTorch dataset wrapper for PhysGen with flexible input/output configuration
215
+ - `resize_tensor_to_divisible_by_14`: resize tensors so height and width are divisible by 14
216
+ - `get_dataloader`: create a PyTorch DataLoader for the PhysGen dataset
217
+ - `get_image`: retrieve a single dataset sample (optionally as NumPy arrays)
218
+ - `save_dataset`: export PhysGen inputs and targets as PNG images to disk
172
219
 
173
220
 
174
221
  That are not all functions but the ones which should be most useful. Check out the documentation for all functions.
@@ -191,14 +238,9 @@ That are not all functions but the ones which should be most useful. Check out t
191
238
  [See also the example notebook 👀](./example/physgen.ipynb)
192
239
 
193
240
  In general you need to do:
194
- 1. **Load your Image** -> using `ips.img.open`
195
- 2. **Calculate the Wall-Map** -> using `ips.ray_tracing.get_wall_map`
196
- 3. **Calculate the Beams** -> using `ips.img.open`
197
- 4. **Draw (Export) the Beams** -> using `ips.img.open`
241
+ 1. Load your Image + Calculate the Wall-Map + **Calculate the Beams** -> using `ips.ray_tracing.trace_beams`
242
+ 2. **Draw (Export) the Beams on a image** -> using `ips.ray_tracing.draw_rays`
198
243
 
199
- Using this lib, this is reduced to:
200
- 1. **Calculate the Beams** (including Wall-Map and loading your Image) -> using `ips.img.open`
201
- 2. **Draw (Export) the Beams** -> using `ips.img.open`
202
244
 
203
245
  See this example:
204
246
 
@@ -327,7 +369,17 @@ I hope this little tutorial could be helpful. Good luck with your project <3
327
369
 
328
370
  <br>
329
371
 
330
- [> See the notebook/code <](./example/physgen_performance.ipynb)
372
+ [> See the notebook/code <](./example/physgen_performance.ipynb) [(or parallel notebook)](./example/physgen_parallel_performance.ipynb)
373
+
374
+ <br><br>
375
+
376
+ Comparison no parallel vs parallel computing:
377
+ - Parallel Mean Experiment time: 3.48 seconds (mean first experiment: 8.85 seconds)
378
+ - Standard Mean Experiment time: 4.53 seconds (mean first experiment: 16.00 seconds)
379
+
380
+ <br><br>
381
+
382
+ Parameter Experiments:
331
383
 
332
384
  Executed with 50 random images.
333
385
 
@@ -447,6 +499,123 @@ The Stepsize/amount of rays have the biggest impact on the performance. The othe
447
499
  | **3. Reflection Order** | 6 | 0.93 ± 0.74 s | 0.90 ± 0.72 s | 0.029 ± 0.016 s | **227.71 %** | Increasing (+0.37 s/exp) | Performance changes **significantly** |
448
500
  | **4. Detail Draw** | 2 | 0.63 ± 0.05 s | 0.56 ± 0.00 s | 0.071 ± 0.050 s | **16.39 %** | Increasing (+0.10 s/exp) | Performance changes **slightly** |
449
501
 
502
+ <!--
503
+ <br><br>
504
+
505
+ ### Optimization
506
+
507
+ <br>
508
+
509
+ Speed comparison between `standard`, `with joblib` and `joblib + CPython`.
510
+
511
+ FIXME -> table
512
+
513
+
514
+ <br>
515
+
516
+ Cython is Pyhon code which is closer to C. Instead of compiling to Python-Bytecode (`.pyc`), your code will be compiled as C-Extension (`.so`/`.pyd`).
517
+
518
+ There are 3 layers of Cython optimization:
519
+ 1. Writing in `.pyx` files not `.py` files -> you can just rename your file<br>
520
+ - +5% to +30% speedup
521
+ 2. Set `cdef` for local variables + helper-functions + `cpdef` for API-functions -> add types<br>
522
+ Example:
523
+ ```python
524
+ cdef double x0, y0, dx, dy
525
+ cdef int cell_x, cell_y, steps
526
+ ```
527
+ - +5x to +50x speedup
528
+ 3. Add types everywhere, especially in numpy arrays. <br>
529
+ Example:
530
+ ```python
531
+ cimport numpy as cnp
532
+
533
+ def trace(..., cnp.ndarray[double, ndim=2] img):
534
+ cdef double value = img[y, x]
535
+ ```
536
+ - +20× to +500×
537
+
538
+
539
+
540
+ | **Optimization Layer** | **Effort** | **Speedup** | **What It Does** |
541
+ |---|---|---|---|
542
+ | **1. `.py` → `.pyx`** | minimal | **+5–30%** | Reduces Python interpreter overhead and applies basic Cython optimizations |
543
+ | **2. `cdef` variables & `cpdef` functions** | medium | **+5×–50×** | Moves loops and math into pure C, eliminating Python object overhead |
544
+ | **3. `cimport numpy` + typed NumPy arrays** | high | **+20×–500×** | Enables direct C‑level memory access with zero Python indexing overhead |
545
+
546
+
547
+
548
+ > Use `pip install cypthon` to install it.
549
+
550
+ In `setup.py` you need following changes:
551
+ ```python
552
+ from setuptools import setup, find_packages, Extension
553
+ from Cython.Build import cythonize
554
+
555
+ ...
556
+
557
+ ext_1 = Extension(
558
+ name="img_phy_sim.ray_tracing",
559
+ sources=["img_phy_sim/ray_tracing.pyx"],
560
+ include_dirs=[],
561
+ extra_compile_args=["-O3"],
562
+ )
563
+
564
+ ext_2 = Extension(
565
+ name="img_phy_sim.math",
566
+ sources=["img_phy_sim/math.pyx"],
567
+ include_dirs=[],
568
+ extra_compile_args=["-O3"],
569
+ )
570
+
571
+ setup(
572
+ ext_modules=cythonize(
573
+ [ext_1, ext_2],
574
+ compiler_directives={
575
+ "language_level": "3",
576
+ "boundscheck": False,
577
+ "wraparound": False,
578
+ "initializedcheck": False,
579
+ "nonecheck": False,
580
+ "cdivision": True,
581
+ },
582
+ annotate=True,
583
+ ),
584
+ ...
585
+ )
586
+ ```
587
+
588
+ -->
589
+
590
+ <br><br>
591
+
592
+ ### Ray-Tracing Formats
593
+
594
+ <br>
595
+
596
+
597
+ **Your current approach (DDA / Pixel Ray Marching)**
598
+ * **Forward integration**: Ray is propagated step by step through a **discrete grid** (pixel/grid).
599
+ * **Collision model**: A "hit" occurs when the ray enters a **wall cell** (quantization).
600
+ * **Reflection**: Occurs **locally at the collision pixel** with a (often quantized) normal/orientation.
601
+ * Result: good for "many rays" / field of view, but **not deterministic with regard to reflection paths** (you need directions/sampling).
602
+
603
+ **Noise modeling style (image source method / geometric acoustics)**
604
+ * **Path construction**: Reflection paths are constructed **deterministically** via **mirror sources** (virtual sources).
605
+ * **Continuous geometry**: works in $\mathbb{R}^2 / \mathbb{R}^3$ with lines/segments/polygons ("infinity-based" in the sense of *continuous space*, not raster).
606
+ * **Validation**: Path is then accepted/rejected via **visibility/occlusion checks**.
607
+ * Result: Delivers **all specular paths up to order N** without angle sampling.
608
+
609
+ Short form:
610
+
611
+ * **Pixel-based + stochastic/directed** (original approach here) vs. **continuous + deterministically constructed** (noise modelling).
612
+
613
+
614
+ <br>
615
+
616
+ How to use which of them in `img-phy-sim`:
617
+
618
+ FIXME
450
619
 
451
620
 
452
621
 
@@ -38,6 +38,19 @@ Submodules:
38
38
  - plot_image_with_values / show_image_with_line_and_profile
39
39
  - get_width_height / get_bit_depth
40
40
 
41
+ - `eval`<br>
42
+ Accuracy measurement utilities.<br>
43
+ Key functionalities:
44
+ - calc_metrices
45
+
46
+ - `data`<br>
47
+ Loading utilities for PhysGen Dataset.<br>
48
+ Key functionalities:
49
+ - PhysGenDataset()
50
+ - get_dataloader
51
+ - save_dataset
52
+
53
+
41
54
  Typical workflow:
42
55
  1. Prepare an environment image using `img.open()` or generate it programmatically.
43
56
  2. Trace beams using `ray_tracing.trace_beams()` with specified start positions,
@@ -81,6 +94,9 @@ Tobia Ippolito, 2025
81
94
 
82
95
  from . import img
83
96
  from . import ray_tracing
97
+ from . import ism
84
98
  from . import math
99
+ from . import eval
100
+ from . import data
85
101
  # from . import data
86
102