interactive-pipe 0.6.0__tar.gz → 0.7.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.
- {interactive_pipe-0.6.0/src/interactive_pipe.egg-info → interactive_pipe-0.7.0}/PKG-INFO +53 -31
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/pyproject.toml +10 -2
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/readme.md +45 -31
- interactive_pipe-0.7.0/src/interactive_pipe/graphical/gradio_control.py +95 -0
- interactive_pipe-0.7.0/src/interactive_pipe/graphical/gradio_gui.py +173 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/choose_backend.py +2 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0/src/interactive_pipe.egg-info}/PKG-INFO +53 -31
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe.egg-info/SOURCES.txt +2 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe.egg-info/requires.txt +8 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/LICENSE +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/setup.cfg +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/__init__.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/core/__init__.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/core/cache.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/core/engine.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/core/filter.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/core/graph.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/core/pipeline.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/core/signature.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/data_objects/__init__.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/data_objects/curves.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/data_objects/data.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/data_objects/image.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/data_objects/parameters.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/__init__.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/gui.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/mpl_control.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/mpl_gui.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/mpl_window.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/nb_control.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/nb_gui.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/qt_control.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/qt_gui.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/window.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/headless/__init__.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/headless/control.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/headless/keyboard.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/headless/pipeline.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/__init__.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/_private.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/control_abbreviation.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/filter_decorator.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/keyword_args_analyzer.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/pipeline_decorator.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/thirdparty/images_openai_api.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/thirdparty/music_spotify.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe.egg-info/dependency_links.txt +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe.egg-info/top_level.txt +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/test/test_cache.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/test/test_control_abbreviations.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/test/test_controller.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/test/test_core.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/test/test_curves.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/test/test_decorator.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/test/test_engine.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/test/test_filter.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/test/test_headless.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/test/test_image.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/test/test_parameters.py +0 -0
- {interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/test/test_recorder.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: interactive_pipe
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Library to create flexible interactive image processing pipelines and automatically add a graphical user interface without knowing anything about GUI coding!
|
|
5
5
|
Author-email: Balthazar Neveu <balthazarneveu@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/balthazarneveu/interactive_pipe
|
|
@@ -15,6 +15,13 @@ Requires-Dist: matplotlib>=3.5.3
|
|
|
15
15
|
Requires-Dist: numpy>=1.21.6
|
|
16
16
|
Requires-Dist: Pillow>=9.0.1
|
|
17
17
|
Requires-Dist: PyYAML>=5.4.1
|
|
18
|
+
Requires-Dist: PyQt6>=6.5.2
|
|
19
|
+
Requires-Dist: PyQt6_sip>=13.5.2
|
|
20
|
+
Requires-Dist: opencv_python_headless>=4.8.1.78
|
|
21
|
+
Requires-Dist: pytest>=6.2.5
|
|
22
|
+
Requires-Dist: ipywidgets>=8.0.7
|
|
23
|
+
Requires-Dist: pandas
|
|
24
|
+
Requires-Dist: gradio
|
|
18
25
|
Provides-Extra: qt6
|
|
19
26
|
Requires-Dist: PyQt6>=6.5.2; extra == "qt6"
|
|
20
27
|
Requires-Dist: PyQt6_sip>=13.5.2; extra == "qt6"
|
|
@@ -33,11 +40,12 @@ Requires-Dist: opencv_python_headless>=4.8.1.78; extra == "full"
|
|
|
33
40
|
Requires-Dist: pytest>=6.2.5; extra == "full"
|
|
34
41
|
Requires-Dist: ipywidgets>=8.0.7; extra == "full"
|
|
35
42
|
Requires-Dist: pandas; extra == "full"
|
|
43
|
+
Requires-Dist: gradio; extra == "full"
|
|
36
44
|
|
|
37
45
|
# `interactive_pipe`
|
|
38
46
|
|
|
39
47
|
Quick setup
|
|
40
|
-
`pip install interactive-pipe
|
|
48
|
+
`pip install interactive-pipe`
|
|
41
49
|
|
|
42
50
|
### Concept
|
|
43
51
|
- Develop an algorithm while debugging visually with plots, while checking robustness & continuity to parameters change.
|
|
@@ -58,8 +66,12 @@ Quick setup
|
|
|
58
66
|
|
|
59
67
|
----------------------
|
|
60
68
|
|
|
61
|
-
###
|
|
62
|
-
|
|
69
|
+
### Local setup
|
|
70
|
+
```
|
|
71
|
+
git clone git@github.com:balthazarneveu/interactive_pipe.git
|
|
72
|
+
cd interactive-pipe
|
|
73
|
+
pip install -e ".[full]"
|
|
74
|
+
```
|
|
63
75
|
|
|
64
76
|
----------------------
|
|
65
77
|
|
|
@@ -82,7 +94,8 @@ Quick setup
|
|
|
82
94
|
----------------------
|
|
83
95
|
|
|
84
96
|
## :scroll: Features
|
|
85
|
-
|
|
97
|
+
|
|
98
|
+
**Version 0.7.0**
|
|
86
99
|
- Modular multi-image processing filters
|
|
87
100
|
- Declarative: Easily make graphical user interface without having to learn anything about pyQt or matplotlib
|
|
88
101
|
- Support in jupyter notebooks
|
|
@@ -90,16 +103,9 @@ Quick setup
|
|
|
90
103
|
- Cache intermediate results in RAM for much faster processing
|
|
91
104
|
- `KeyboardControl` : no slider on UI but exactly the same internal mechanism, update on key press.
|
|
92
105
|
- Support Curve plots (2D signals)
|
|
93
|
-
|
|
94
|
-
#### :soon: Upcoming features:
|
|
95
|
-
- :soon: Scientific visual debugging: Display both colored images, heatmaps & graphs
|
|
106
|
+
- :new: gradio backend (+allows sharing with others)
|
|
96
107
|
|
|
97
108
|
|
|
98
|
-
#### :test_tube: Experimental features
|
|
99
|
-
- custom events on specific key press
|
|
100
|
-
- Display the execution graph of the pipeline
|
|
101
|
-
- [thirdparty/music](/src/interactive_pipe/thirdparty/music.py) Play audio (Qt backend only). Play songs on spotify (linux only) when the spotify app is running.
|
|
102
|
-
- [thirdparty/images_openai_api](/src/interactive_pipe/thirdparty/images_openai_api.py) Generate images from prompt using OpenAI API image generation DALL-E Model (:dollar: paid service ~ 2cents/image)
|
|
103
109
|
|
|
104
110
|
#### :keyboard: Keyboard shortcuts
|
|
105
111
|
Shortcuts while using the GUI (QT & matplotlib backends)
|
|
@@ -119,7 +125,8 @@ Shortcuts while using the GUI (QT & matplotlib backends)
|
|
|
119
125
|
- supported backends
|
|
120
126
|
- :ok: `gui='qt'` pyQt/pySide
|
|
121
127
|
- :ok: `gui='mpl'` matplotlib
|
|
122
|
-
- :ok: `gui='nb'` ipywidget for jupyter notebooks
|
|
128
|
+
- :ok: `gui='nb'` ipywidget for jupyter notebooks
|
|
129
|
+
- :test_tube: `gui='gradio'` gradio wrapping (+use `share_gradio_app=True` to share your app with others)
|
|
123
130
|
- tested platforms
|
|
124
131
|
- :ok: Linux (Ubuntu / KDE Neon)
|
|
125
132
|
- :ok: RapsberryPi
|
|
@@ -127,16 +134,15 @@ Shortcuts while using the GUI (QT & matplotlib backends)
|
|
|
127
134
|
|
|
128
135
|
|
|
129
136
|
|
|
130
|
-
| :star: | *PyQt / PySide* | *Matplotlib* | *Jupyter notebooks including Google collab* |
|
|
131
|
-
|:-----: |:-----:|:------:|:----: |
|
|
132
|
-
| Backend name | `qt` | `mpl` | `nb`|
|
|
133
|
-
| Preview |  |  |  |
|
|
134
|
-
| Plot curves | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
|
135
|
-
| Auto refreshed layout | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
|
136
|
-
| Keyboard shortcuts / fullscreen| :heavy_check_mark: | :heavy_check_mark: | :heavy_minus_sign: |
|
|
137
|
-
| Audio support | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
|
|
138
|
-
| Image buttons| :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
|
|
139
|
-
|
|
137
|
+
| :star: | *PyQt / PySide* | *Matplotlib* | *Jupyter notebooks including Google collab* | *Gradio* |
|
|
138
|
+
|:-----: |:-----:|:------:|:----: |:----: |
|
|
139
|
+
| Backend name | `qt` | `mpl` | `nb`| `gradio` |
|
|
140
|
+
| Preview |  |  |  | |
|
|
141
|
+
| Plot curves | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark:|
|
|
142
|
+
| Auto refreshed layout | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_minus_sign: |
|
|
143
|
+
| Keyboard shortcuts / fullscreen| :heavy_check_mark: | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
|
|
144
|
+
| Audio support | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: |
|
|
145
|
+
| Image buttons| :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign:|
|
|
140
146
|
|
|
141
147
|
|
|
142
148
|
|
|
@@ -154,12 +160,7 @@ Shortcuts while using the GUI (QT & matplotlib backends)
|
|
|
154
160
|

|
|
155
161
|
|
|
156
162
|
|
|
157
|
-
#### [Minimalistic pytorch based ISP ](https://github.com/balthazarneveu/interactive_pipe/tree/sample_interactive_isp/samples/isp)
|
|
158
|
-
[ISP means image signal processor](https://en.wikipedia.org/wiki/Image_processor)
|
|
159
163
|
|
|
160
|
-
:warning: Work in progess (no proper demosaicking, no denoiser, no tone mapping.)
|
|
161
|
-
|
|
162
|
-

|
|
163
164
|
|
|
164
165
|
|
|
165
166
|
# Tutorials
|
|
@@ -250,7 +251,7 @@ def generate_flat_colored_image(color_choice=["red", "green", "blue", "gray"], g
|
|
|
250
251
|
```
|
|
251
252
|
|
|
252
253
|
- Note that you can also create filters which take no inputs and simply "generate" images.
|
|
253
|
-
- The `color_choice` list will be
|
|
254
|
+
- The `color_choice` list will be turned into a nice dropdown menu. Default value here will be red as this is the first element of the list!
|
|
254
255
|
----------
|
|
255
256
|
|
|
256
257
|
:bulb: Can filters communicate together?
|
|
@@ -304,7 +305,8 @@ if __name__ == '__main__':
|
|
|
304
305
|
### History
|
|
305
306
|
- Interactive pipe was initially developped by [Balthazar Neveu](https://github.com/balthazarneveu) as part of the [irdrone project](https://github.com/wisescootering/infrareddrone/tree/master/interactive) based on matplotlib.
|
|
306
307
|
- Later, more contributions were also made by [Giuseppe Moschetti](https://github.com/g-moschetti) and Sylvain Leroy.
|
|
307
|
-
-
|
|
308
|
+
- August 2023: rewriting the whole core and supporting several graphical backends!
|
|
309
|
+
- September 2024: Gradio backend
|
|
308
310
|
|
|
309
311
|
|
|
310
312
|
|
|
@@ -324,3 +326,23 @@ if __name__ == '__main__':
|
|
|
324
326
|
- Exploratory backends
|
|
325
327
|
- Create a [textual](https://github.com/Textualize/textual) backend for simplified GUI (probably no images displayed)
|
|
326
328
|
- Create a [Kivy](https://kivy.org/) backend
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
### Further examples
|
|
332
|
+
|
|
333
|
+
#### [Minimalistic pytorch based ISP ](https://github.com/balthazarneveu/interactive_pipe/tree/sample_interactive_isp/samples/isp)
|
|
334
|
+
[ISP means image signal processor](https://en.wikipedia.org/wiki/Image_processor)
|
|
335
|
+
|
|
336
|
+
:warning: Work in progess (no proper demosaicking, no denoiser, no tone mapping.)
|
|
337
|
+
|
|
338
|
+

|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
#### :test_tube: Experimental features
|
|
345
|
+
- Custom events on specific key press
|
|
346
|
+
- Display the execution graph of the pipeline `G` key
|
|
347
|
+
- [thirdparty/music](/src/interactive_pipe/thirdparty/music.py) Play audio (Qt backend only). Play songs on spotify (linux only) when the spotify app is running.
|
|
348
|
+
- [thirdparty/images_openai_api](/src/interactive_pipe/thirdparty/images_openai_api.py) Generate images from prompt using OpenAI API image generation DALL-E Model (:dollar: paid service ~ 2cents/image)
|
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
|
|
6
6
|
[project]
|
|
7
7
|
name = "interactive_pipe"
|
|
8
|
-
version = "0.
|
|
8
|
+
version = "0.7.0"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name="Balthazar Neveu", email="balthazarneveu@gmail.com" },
|
|
11
11
|
]
|
|
@@ -14,6 +14,13 @@ dependencies = [
|
|
|
14
14
|
"numpy>=1.21.6",
|
|
15
15
|
"Pillow>=9.0.1",
|
|
16
16
|
"PyYAML>=5.4.1",
|
|
17
|
+
"PyQt6>=6.5.2",
|
|
18
|
+
"PyQt6_sip>=13.5.2",
|
|
19
|
+
"opencv_python_headless>=4.8.1.78",
|
|
20
|
+
"pytest>=6.2.5",
|
|
21
|
+
"ipywidgets>=8.0.7",
|
|
22
|
+
"pandas",
|
|
23
|
+
"gradio",
|
|
17
24
|
]
|
|
18
25
|
|
|
19
26
|
description = "Library to create flexible interactive image processing pipelines and automatically add a graphical user interface without knowing anything about GUI coding!"
|
|
@@ -56,4 +63,5 @@ full=[
|
|
|
56
63
|
"pytest>=6.2.5",
|
|
57
64
|
"ipywidgets>=8.0.7",
|
|
58
65
|
"pandas",
|
|
59
|
-
|
|
66
|
+
"gradio",
|
|
67
|
+
]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# `interactive_pipe`
|
|
2
2
|
|
|
3
3
|
Quick setup
|
|
4
|
-
`pip install interactive-pipe
|
|
4
|
+
`pip install interactive-pipe`
|
|
5
5
|
|
|
6
6
|
### Concept
|
|
7
7
|
- Develop an algorithm while debugging visually with plots, while checking robustness & continuity to parameters change.
|
|
@@ -22,8 +22,12 @@ Quick setup
|
|
|
22
22
|
|
|
23
23
|
----------------------
|
|
24
24
|
|
|
25
|
-
###
|
|
26
|
-
|
|
25
|
+
### Local setup
|
|
26
|
+
```
|
|
27
|
+
git clone git@github.com:balthazarneveu/interactive_pipe.git
|
|
28
|
+
cd interactive-pipe
|
|
29
|
+
pip install -e ".[full]"
|
|
30
|
+
```
|
|
27
31
|
|
|
28
32
|
----------------------
|
|
29
33
|
|
|
@@ -46,7 +50,8 @@ Quick setup
|
|
|
46
50
|
----------------------
|
|
47
51
|
|
|
48
52
|
## :scroll: Features
|
|
49
|
-
|
|
53
|
+
|
|
54
|
+
**Version 0.7.0**
|
|
50
55
|
- Modular multi-image processing filters
|
|
51
56
|
- Declarative: Easily make graphical user interface without having to learn anything about pyQt or matplotlib
|
|
52
57
|
- Support in jupyter notebooks
|
|
@@ -54,17 +59,10 @@ Quick setup
|
|
|
54
59
|
- Cache intermediate results in RAM for much faster processing
|
|
55
60
|
- `KeyboardControl` : no slider on UI but exactly the same internal mechanism, update on key press.
|
|
56
61
|
- Support Curve plots (2D signals)
|
|
62
|
+
- :new: gradio backend (+allows sharing with others)
|
|
57
63
|
|
|
58
|
-
#### :soon: Upcoming features:
|
|
59
|
-
- :soon: Scientific visual debugging: Display both colored images, heatmaps & graphs
|
|
60
64
|
|
|
61
65
|
|
|
62
|
-
#### :test_tube: Experimental features
|
|
63
|
-
- custom events on specific key press
|
|
64
|
-
- Display the execution graph of the pipeline
|
|
65
|
-
- [thirdparty/music](/src/interactive_pipe/thirdparty/music.py) Play audio (Qt backend only). Play songs on spotify (linux only) when the spotify app is running.
|
|
66
|
-
- [thirdparty/images_openai_api](/src/interactive_pipe/thirdparty/images_openai_api.py) Generate images from prompt using OpenAI API image generation DALL-E Model (:dollar: paid service ~ 2cents/image)
|
|
67
|
-
|
|
68
66
|
#### :keyboard: Keyboard shortcuts
|
|
69
67
|
Shortcuts while using the GUI (QT & matplotlib backends)
|
|
70
68
|
|
|
@@ -83,7 +81,8 @@ Shortcuts while using the GUI (QT & matplotlib backends)
|
|
|
83
81
|
- supported backends
|
|
84
82
|
- :ok: `gui='qt'` pyQt/pySide
|
|
85
83
|
- :ok: `gui='mpl'` matplotlib
|
|
86
|
-
- :ok: `gui='nb'` ipywidget for jupyter notebooks
|
|
84
|
+
- :ok: `gui='nb'` ipywidget for jupyter notebooks
|
|
85
|
+
- :test_tube: `gui='gradio'` gradio wrapping (+use `share_gradio_app=True` to share your app with others)
|
|
87
86
|
- tested platforms
|
|
88
87
|
- :ok: Linux (Ubuntu / KDE Neon)
|
|
89
88
|
- :ok: RapsberryPi
|
|
@@ -91,16 +90,15 @@ Shortcuts while using the GUI (QT & matplotlib backends)
|
|
|
91
90
|
|
|
92
91
|
|
|
93
92
|
|
|
94
|
-
| :star: | *PyQt / PySide* | *Matplotlib* | *Jupyter notebooks including Google collab* |
|
|
95
|
-
|:-----: |:-----:|:------:|:----: |
|
|
96
|
-
| Backend name | `qt` | `mpl` | `nb`|
|
|
97
|
-
| Preview |  |  |  |
|
|
98
|
-
| Plot curves | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
|
99
|
-
| Auto refreshed layout | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
|
100
|
-
| Keyboard shortcuts / fullscreen| :heavy_check_mark: | :heavy_check_mark: | :heavy_minus_sign: |
|
|
101
|
-
| Audio support | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
|
|
102
|
-
| Image buttons| :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
|
|
103
|
-
|
|
93
|
+
| :star: | *PyQt / PySide* | *Matplotlib* | *Jupyter notebooks including Google collab* | *Gradio* |
|
|
94
|
+
|:-----: |:-----:|:------:|:----: |:----: |
|
|
95
|
+
| Backend name | `qt` | `mpl` | `nb`| `gradio` |
|
|
96
|
+
| Preview |  |  |  | |
|
|
97
|
+
| Plot curves | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark:|
|
|
98
|
+
| Auto refreshed layout | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_minus_sign: |
|
|
99
|
+
| Keyboard shortcuts / fullscreen| :heavy_check_mark: | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
|
|
100
|
+
| Audio support | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: |
|
|
101
|
+
| Image buttons| :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign:|
|
|
104
102
|
|
|
105
103
|
|
|
106
104
|
|
|
@@ -118,12 +116,7 @@ Shortcuts while using the GUI (QT & matplotlib backends)
|
|
|
118
116
|

|
|
119
117
|
|
|
120
118
|
|
|
121
|
-
#### [Minimalistic pytorch based ISP ](https://github.com/balthazarneveu/interactive_pipe/tree/sample_interactive_isp/samples/isp)
|
|
122
|
-
[ISP means image signal processor](https://en.wikipedia.org/wiki/Image_processor)
|
|
123
119
|
|
|
124
|
-
:warning: Work in progess (no proper demosaicking, no denoiser, no tone mapping.)
|
|
125
|
-
|
|
126
|
-

|
|
127
120
|
|
|
128
121
|
|
|
129
122
|
# Tutorials
|
|
@@ -214,7 +207,7 @@ def generate_flat_colored_image(color_choice=["red", "green", "blue", "gray"], g
|
|
|
214
207
|
```
|
|
215
208
|
|
|
216
209
|
- Note that you can also create filters which take no inputs and simply "generate" images.
|
|
217
|
-
- The `color_choice` list will be
|
|
210
|
+
- The `color_choice` list will be turned into a nice dropdown menu. Default value here will be red as this is the first element of the list!
|
|
218
211
|
----------
|
|
219
212
|
|
|
220
213
|
:bulb: Can filters communicate together?
|
|
@@ -268,7 +261,8 @@ if __name__ == '__main__':
|
|
|
268
261
|
### History
|
|
269
262
|
- Interactive pipe was initially developped by [Balthazar Neveu](https://github.com/balthazarneveu) as part of the [irdrone project](https://github.com/wisescootering/infrareddrone/tree/master/interactive) based on matplotlib.
|
|
270
263
|
- Later, more contributions were also made by [Giuseppe Moschetti](https://github.com/g-moschetti) and Sylvain Leroy.
|
|
271
|
-
-
|
|
264
|
+
- August 2023: rewriting the whole core and supporting several graphical backends!
|
|
265
|
+
- September 2024: Gradio backend
|
|
272
266
|
|
|
273
267
|
|
|
274
268
|
|
|
@@ -287,4 +281,24 @@ if __name__ == '__main__':
|
|
|
287
281
|
- Animations/While loops/Video source (Time slider)
|
|
288
282
|
- Exploratory backends
|
|
289
283
|
- Create a [textual](https://github.com/Textualize/textual) backend for simplified GUI (probably no images displayed)
|
|
290
|
-
- Create a [Kivy](https://kivy.org/) backend
|
|
284
|
+
- Create a [Kivy](https://kivy.org/) backend
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
### Further examples
|
|
288
|
+
|
|
289
|
+
#### [Minimalistic pytorch based ISP ](https://github.com/balthazarneveu/interactive_pipe/tree/sample_interactive_isp/samples/isp)
|
|
290
|
+
[ISP means image signal processor](https://en.wikipedia.org/wiki/Image_processor)
|
|
291
|
+
|
|
292
|
+
:warning: Work in progess (no proper demosaicking, no denoiser, no tone mapping.)
|
|
293
|
+
|
|
294
|
+

|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
#### :test_tube: Experimental features
|
|
301
|
+
- Custom events on specific key press
|
|
302
|
+
- Display the execution graph of the pipeline `G` key
|
|
303
|
+
- [thirdparty/music](/src/interactive_pipe/thirdparty/music.py) Play audio (Qt backend only). Play songs on spotify (linux only) when the spotify app is running.
|
|
304
|
+
- [thirdparty/images_openai_api](/src/interactive_pipe/thirdparty/images_openai_api.py) Generate images from prompt using OpenAI API image generation DALL-E Model (:dollar: paid service ~ 2cents/image)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
|
|
2
|
+
from functools import partial
|
|
3
|
+
from interactive_pipe.headless.control import Control
|
|
4
|
+
import logging
|
|
5
|
+
import gradio as gr
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BaseControl():
|
|
9
|
+
def __init__(self, name, ctrl: Control, update_func):
|
|
10
|
+
super().__init__()
|
|
11
|
+
self.name = name
|
|
12
|
+
self.ctrl = ctrl
|
|
13
|
+
self.update_func = update_func
|
|
14
|
+
self.check_control_type()
|
|
15
|
+
|
|
16
|
+
def create(self):
|
|
17
|
+
raise NotImplementedError(
|
|
18
|
+
"This method should be overridden by subclass")
|
|
19
|
+
|
|
20
|
+
def check_control_type(self):
|
|
21
|
+
raise NotImplementedError(
|
|
22
|
+
"This method should be overridden by subclass to check the right slider control type")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ControlFactory:
|
|
26
|
+
@staticmethod
|
|
27
|
+
def create_control(control: Control, update_func):
|
|
28
|
+
control_type = control._type
|
|
29
|
+
name = control.name
|
|
30
|
+
control_class_map = {
|
|
31
|
+
bool: TickBoxControl,
|
|
32
|
+
int: IntSliderControl,
|
|
33
|
+
float: FloatSliderControl,
|
|
34
|
+
str: DropdownMenuControl
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if control_type not in control_class_map:
|
|
38
|
+
logging.warning(
|
|
39
|
+
f"Unsupported control type: {control_type} for control named {name}")
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
control_class = control_class_map[control_type]
|
|
43
|
+
return control_class(name, control, update_func)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class IntSliderControl(BaseControl):
|
|
47
|
+
def check_control_type(self):
|
|
48
|
+
assert self.ctrl._type == int
|
|
49
|
+
|
|
50
|
+
def create(self) -> gr.Slider:
|
|
51
|
+
self.control_widget = gr.Slider(
|
|
52
|
+
value=self.ctrl.value_default, minimum=self.ctrl.value_range[0], maximum=self.ctrl.value_range[1], label=self.name, step=1)
|
|
53
|
+
return self.control_widget
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class FloatSliderControl(BaseControl):
|
|
57
|
+
def check_control_type(self):
|
|
58
|
+
assert self.ctrl._type == float
|
|
59
|
+
|
|
60
|
+
def create(self) -> gr.Slider:
|
|
61
|
+
self.control_widget = gr.Slider(
|
|
62
|
+
value=self.ctrl.value_default,
|
|
63
|
+
minimum=self.ctrl.value_range[0], maximum=self.ctrl.value_range[1], label=self.name)
|
|
64
|
+
|
|
65
|
+
return self.control_widget
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class TickBoxControl(BaseControl):
|
|
69
|
+
def check_control_type(self):
|
|
70
|
+
assert self.ctrl._type == bool
|
|
71
|
+
|
|
72
|
+
def create(self) -> gr.Checkbox:
|
|
73
|
+
self.control_widget = gr.Checkbox(label=self.name, value=self.ctrl.value)
|
|
74
|
+
return self.control_widget
|
|
75
|
+
|
|
76
|
+
def reset(self):
|
|
77
|
+
self.control_widget.update(value=self.ctrl.default_value)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class DropdownMenuControl(BaseControl):
|
|
81
|
+
def check_control_type(self):
|
|
82
|
+
assert self.ctrl._type == str
|
|
83
|
+
if not hasattr(self.ctrl, 'value_range'):
|
|
84
|
+
raise ValueError("Invalid control type")
|
|
85
|
+
|
|
86
|
+
def create(self) -> gr.Dropdown:
|
|
87
|
+
# Create a horizontal layout to hold the dropdown menu
|
|
88
|
+
self.control_widget = gr.Dropdown(label=self.name, choices=self.ctrl.value_range, value=self.ctrl.value)
|
|
89
|
+
return self.control_widget
|
|
90
|
+
|
|
91
|
+
def reset(self):
|
|
92
|
+
index = self.control_widget.findText(self.ctrl.value)
|
|
93
|
+
if index >= 0:
|
|
94
|
+
self.control_widget.setCurrentIndex(index)
|
|
95
|
+
self.control_widget.setCurrentIndex(index)
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import gradio as gr
|
|
2
|
+
import numpy as np
|
|
3
|
+
from typing import List
|
|
4
|
+
from interactive_pipe.headless.pipeline import HeadlessPipeline
|
|
5
|
+
from interactive_pipe.graphical.gradio_control import ControlFactory
|
|
6
|
+
from interactive_pipe.graphical.window import InteractivePipeWindow
|
|
7
|
+
from interactive_pipe.graphical.gui import InteractivePipeGUI
|
|
8
|
+
from interactive_pipe.headless.control import Control
|
|
9
|
+
import logging
|
|
10
|
+
PYQTVERSION = None
|
|
11
|
+
MPL_SUPPORT = False
|
|
12
|
+
GRADIO_INTERFACE_MODE = False
|
|
13
|
+
try:
|
|
14
|
+
from interactive_pipe.data_objects.curves import Curve
|
|
15
|
+
import matplotlib.pyplot as plt
|
|
16
|
+
MPL_SUPPORT = True
|
|
17
|
+
except ImportError:
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class InteractivePipeGradio(InteractivePipeGUI):
|
|
22
|
+
def init_app(self, **kwargs):
|
|
23
|
+
self.window = MainWindow(controls=self.controls, name=self.name,
|
|
24
|
+
pipeline=self.pipeline, size=self.size, main_gui=self, **kwargs)
|
|
25
|
+
self.pipeline.global_params["__pipeline"] = self.pipeline
|
|
26
|
+
# self.set_default_key_bindings()
|
|
27
|
+
|
|
28
|
+
def run(self) -> list:
|
|
29
|
+
assert self.pipeline._PipelineCore__initialized_inputs, "Did you forget to initialize the pipeline inputs?"
|
|
30
|
+
out_list = self.window.process_inputs_fn(*self.window.default_values)
|
|
31
|
+
out_list_gradio_containers = []
|
|
32
|
+
for idx in range(len(out_list)):
|
|
33
|
+
for idy in range(len(out_list[idx])):
|
|
34
|
+
if isinstance(out_list[idx][idy], np.ndarray):
|
|
35
|
+
out_list_gradio_containers.append(gr.Image())
|
|
36
|
+
elif MPL_SUPPORT and isinstance(out_list[idx][idy], Curve):
|
|
37
|
+
out_list_gradio_containers.append(gr.Plot())
|
|
38
|
+
else:
|
|
39
|
+
raise NotImplementedError(
|
|
40
|
+
f"output type {type(out_list[idx][idy])} not supported")
|
|
41
|
+
self.window.instantiate_gradio_interface(out_list_gradio_containers)
|
|
42
|
+
self.window.refresh()
|
|
43
|
+
self.custom_end()
|
|
44
|
+
return self.pipeline.results
|
|
45
|
+
|
|
46
|
+
def print_message(self, message_list: List[str]):
|
|
47
|
+
print("\n".join(message_list))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class MainWindow(InteractivePipeWindow):
|
|
51
|
+
def __init__(self, *args, controls=[], name="", pipeline: HeadlessPipeline = None, size=None, share_gradio_app=False, **kwargs):
|
|
52
|
+
InteractivePipeWindow.__init__(
|
|
53
|
+
self, name=name, pipeline=pipeline, size=size)
|
|
54
|
+
self.init_sliders(controls)
|
|
55
|
+
self.size = size
|
|
56
|
+
self.full_screen_flag = False
|
|
57
|
+
self.pipeline = pipeline
|
|
58
|
+
self.share_gradio_app = share_gradio_app
|
|
59
|
+
# Define the functions that will be called when the input changes for gradio. => gr.Interface(fn=process_fn)
|
|
60
|
+
|
|
61
|
+
def process_outputs_fn(out) -> tuple:
|
|
62
|
+
flat_out = []
|
|
63
|
+
for idx in range(len(out)):
|
|
64
|
+
if isinstance(out[idx], list):
|
|
65
|
+
for idy in range(len(out[idx])):
|
|
66
|
+
if MPL_SUPPORT and isinstance(out[idx][idy], Curve):
|
|
67
|
+
curve = out[idx][idy]
|
|
68
|
+
fig, ax = plt.subplots()
|
|
69
|
+
Curve._plot_curve(curve.data, ax=ax)
|
|
70
|
+
flat_out.append(fig)
|
|
71
|
+
elif isinstance(out[idx][idy], np.ndarray):
|
|
72
|
+
logging.info(f"CONVERTING IMAGE {idx} {idy}")
|
|
73
|
+
flat_out.append(self.convert_image(out[idx][idy]))
|
|
74
|
+
else:
|
|
75
|
+
raise NotImplementedError(
|
|
76
|
+
f"output type {type(out[idx][idy])} not supported")
|
|
77
|
+
else:
|
|
78
|
+
logging.info(f"CONVERTING IMAGE {idx} ")
|
|
79
|
+
flat_out.append(self.convert_image(out[idx]))
|
|
80
|
+
if out is None:
|
|
81
|
+
logging.warning("No output to display")
|
|
82
|
+
return
|
|
83
|
+
return tuple(flat_out)
|
|
84
|
+
|
|
85
|
+
def process_inputs_fn(*args) -> list:
|
|
86
|
+
all_keys = list(self.ctrl.keys())
|
|
87
|
+
for idx in range(len(args)):
|
|
88
|
+
self.ctrl[all_keys[idx]].update(args[idx])
|
|
89
|
+
out = self.pipeline.run()
|
|
90
|
+
return out
|
|
91
|
+
|
|
92
|
+
def run_fn(*args) -> tuple:
|
|
93
|
+
out = process_inputs_fn(*args)
|
|
94
|
+
out_tuple = process_outputs_fn(out)
|
|
95
|
+
return out_tuple
|
|
96
|
+
self.default_values = [self.ctrl[ctrl_key].value for ctrl_key in self.ctrl.keys()]
|
|
97
|
+
self.process_inputs_fn = process_inputs_fn
|
|
98
|
+
self.run_fn = run_fn
|
|
99
|
+
|
|
100
|
+
def instantiate_gradio_interface(self, outputs: List[gr.Blocks]):
|
|
101
|
+
if GRADIO_INTERFACE_MODE:
|
|
102
|
+
# Interface mode, high level wrapper
|
|
103
|
+
# https://www.gradio.app/guides/the-interface-class
|
|
104
|
+
self.io = gr.Interface(
|
|
105
|
+
allow_flagging='never',
|
|
106
|
+
fn=self.run_fn,
|
|
107
|
+
title=self.name,
|
|
108
|
+
inputs=self.widget_list,
|
|
109
|
+
outputs=outputs,
|
|
110
|
+
examples=[self.default_values],
|
|
111
|
+
live=True,
|
|
112
|
+
show_progress="minimal",
|
|
113
|
+
clear_btn=None,
|
|
114
|
+
)
|
|
115
|
+
else:
|
|
116
|
+
# Gradio Blocks mode
|
|
117
|
+
# https://www.gradio.app/guides/blocks-and-event-listeners
|
|
118
|
+
with gr.Blocks() as io:
|
|
119
|
+
with gr.Row():
|
|
120
|
+
for elem in outputs:
|
|
121
|
+
elem.render()
|
|
122
|
+
with gr.Row():
|
|
123
|
+
for elem in self.widget_list:
|
|
124
|
+
with gr.Row():
|
|
125
|
+
elem.render()
|
|
126
|
+
with gr.Row():
|
|
127
|
+
gr.Examples([self.default_values], inputs=self.widget_list)
|
|
128
|
+
io.load(fn=self.run_fn, inputs=self.widget_list, outputs=outputs)
|
|
129
|
+
for idx in range(len(self.widget_list)):
|
|
130
|
+
self.widget_list[idx].change(
|
|
131
|
+
fn=self.run_fn, inputs=self.widget_list,
|
|
132
|
+
outputs=outputs,
|
|
133
|
+
show_progress="minimal"
|
|
134
|
+
)
|
|
135
|
+
self.io = io
|
|
136
|
+
self.io.launch(share=self.share_gradio_app)
|
|
137
|
+
|
|
138
|
+
def init_sliders(self, controls: List[Control]):
|
|
139
|
+
self.ctrl = {}
|
|
140
|
+
self.result_label = {}
|
|
141
|
+
self.name_label = {}
|
|
142
|
+
self.widget_list = []
|
|
143
|
+
control_factory = ControlFactory()
|
|
144
|
+
for ctrl in controls:
|
|
145
|
+
if isinstance(ctrl, Control):
|
|
146
|
+
slider_instance = control_factory.create_control(
|
|
147
|
+
ctrl, None)
|
|
148
|
+
control_widget = slider_instance.create()
|
|
149
|
+
self.widget_list.append(control_widget)
|
|
150
|
+
slider_name = ctrl.name
|
|
151
|
+
self.ctrl[slider_name] = ctrl
|
|
152
|
+
|
|
153
|
+
@staticmethod
|
|
154
|
+
def convert_image(out_im):
|
|
155
|
+
if isinstance(out_im, np.ndarray):
|
|
156
|
+
return (out_im.clip(0., 1.) * 255).astype(np.uint8)
|
|
157
|
+
else:
|
|
158
|
+
return out_im
|
|
159
|
+
|
|
160
|
+
def refresh(self):
|
|
161
|
+
if self.pipeline is not None:
|
|
162
|
+
self.io.launch()
|
|
163
|
+
|
|
164
|
+
def reset_sliders(self):
|
|
165
|
+
# Click on default examples in Gradio
|
|
166
|
+
pass
|
|
167
|
+
|
|
168
|
+
def add_image_placeholder(self, row, col):
|
|
169
|
+
ax_placeholder = None
|
|
170
|
+
text_label = None
|
|
171
|
+
image_label = None
|
|
172
|
+
self.image_canvas[row][col] = {
|
|
173
|
+
"image": image_label, "title": text_label, "ax_placeholder": ax_placeholder}
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/choose_backend.py
RENAMED
|
@@ -35,6 +35,8 @@ def get_interactive_pipeline_class(gui="auto"):
|
|
|
35
35
|
from interactive_pipe.graphical.mpl_gui import InteractivePipeMatplotlib as ChosenGui
|
|
36
36
|
elif selected_gui == "nb":
|
|
37
37
|
from interactive_pipe.graphical.nb_gui import InteractivePipeJupyter as ChosenGui
|
|
38
|
+
elif selected_gui == "gradio":
|
|
39
|
+
from interactive_pipe.graphical.gradio_gui import InteractivePipeGradio as ChosenGui
|
|
38
40
|
else:
|
|
39
41
|
raise NotImplementedError(f"Gui {gui} not available")
|
|
40
42
|
return ChosenGui
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: interactive_pipe
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Library to create flexible interactive image processing pipelines and automatically add a graphical user interface without knowing anything about GUI coding!
|
|
5
5
|
Author-email: Balthazar Neveu <balthazarneveu@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/balthazarneveu/interactive_pipe
|
|
@@ -15,6 +15,13 @@ Requires-Dist: matplotlib>=3.5.3
|
|
|
15
15
|
Requires-Dist: numpy>=1.21.6
|
|
16
16
|
Requires-Dist: Pillow>=9.0.1
|
|
17
17
|
Requires-Dist: PyYAML>=5.4.1
|
|
18
|
+
Requires-Dist: PyQt6>=6.5.2
|
|
19
|
+
Requires-Dist: PyQt6_sip>=13.5.2
|
|
20
|
+
Requires-Dist: opencv_python_headless>=4.8.1.78
|
|
21
|
+
Requires-Dist: pytest>=6.2.5
|
|
22
|
+
Requires-Dist: ipywidgets>=8.0.7
|
|
23
|
+
Requires-Dist: pandas
|
|
24
|
+
Requires-Dist: gradio
|
|
18
25
|
Provides-Extra: qt6
|
|
19
26
|
Requires-Dist: PyQt6>=6.5.2; extra == "qt6"
|
|
20
27
|
Requires-Dist: PyQt6_sip>=13.5.2; extra == "qt6"
|
|
@@ -33,11 +40,12 @@ Requires-Dist: opencv_python_headless>=4.8.1.78; extra == "full"
|
|
|
33
40
|
Requires-Dist: pytest>=6.2.5; extra == "full"
|
|
34
41
|
Requires-Dist: ipywidgets>=8.0.7; extra == "full"
|
|
35
42
|
Requires-Dist: pandas; extra == "full"
|
|
43
|
+
Requires-Dist: gradio; extra == "full"
|
|
36
44
|
|
|
37
45
|
# `interactive_pipe`
|
|
38
46
|
|
|
39
47
|
Quick setup
|
|
40
|
-
`pip install interactive-pipe
|
|
48
|
+
`pip install interactive-pipe`
|
|
41
49
|
|
|
42
50
|
### Concept
|
|
43
51
|
- Develop an algorithm while debugging visually with plots, while checking robustness & continuity to parameters change.
|
|
@@ -58,8 +66,12 @@ Quick setup
|
|
|
58
66
|
|
|
59
67
|
----------------------
|
|
60
68
|
|
|
61
|
-
###
|
|
62
|
-
|
|
69
|
+
### Local setup
|
|
70
|
+
```
|
|
71
|
+
git clone git@github.com:balthazarneveu/interactive_pipe.git
|
|
72
|
+
cd interactive-pipe
|
|
73
|
+
pip install -e ".[full]"
|
|
74
|
+
```
|
|
63
75
|
|
|
64
76
|
----------------------
|
|
65
77
|
|
|
@@ -82,7 +94,8 @@ Quick setup
|
|
|
82
94
|
----------------------
|
|
83
95
|
|
|
84
96
|
## :scroll: Features
|
|
85
|
-
|
|
97
|
+
|
|
98
|
+
**Version 0.7.0**
|
|
86
99
|
- Modular multi-image processing filters
|
|
87
100
|
- Declarative: Easily make graphical user interface without having to learn anything about pyQt or matplotlib
|
|
88
101
|
- Support in jupyter notebooks
|
|
@@ -90,16 +103,9 @@ Quick setup
|
|
|
90
103
|
- Cache intermediate results in RAM for much faster processing
|
|
91
104
|
- `KeyboardControl` : no slider on UI but exactly the same internal mechanism, update on key press.
|
|
92
105
|
- Support Curve plots (2D signals)
|
|
93
|
-
|
|
94
|
-
#### :soon: Upcoming features:
|
|
95
|
-
- :soon: Scientific visual debugging: Display both colored images, heatmaps & graphs
|
|
106
|
+
- :new: gradio backend (+allows sharing with others)
|
|
96
107
|
|
|
97
108
|
|
|
98
|
-
#### :test_tube: Experimental features
|
|
99
|
-
- custom events on specific key press
|
|
100
|
-
- Display the execution graph of the pipeline
|
|
101
|
-
- [thirdparty/music](/src/interactive_pipe/thirdparty/music.py) Play audio (Qt backend only). Play songs on spotify (linux only) when the spotify app is running.
|
|
102
|
-
- [thirdparty/images_openai_api](/src/interactive_pipe/thirdparty/images_openai_api.py) Generate images from prompt using OpenAI API image generation DALL-E Model (:dollar: paid service ~ 2cents/image)
|
|
103
109
|
|
|
104
110
|
#### :keyboard: Keyboard shortcuts
|
|
105
111
|
Shortcuts while using the GUI (QT & matplotlib backends)
|
|
@@ -119,7 +125,8 @@ Shortcuts while using the GUI (QT & matplotlib backends)
|
|
|
119
125
|
- supported backends
|
|
120
126
|
- :ok: `gui='qt'` pyQt/pySide
|
|
121
127
|
- :ok: `gui='mpl'` matplotlib
|
|
122
|
-
- :ok: `gui='nb'` ipywidget for jupyter notebooks
|
|
128
|
+
- :ok: `gui='nb'` ipywidget for jupyter notebooks
|
|
129
|
+
- :test_tube: `gui='gradio'` gradio wrapping (+use `share_gradio_app=True` to share your app with others)
|
|
123
130
|
- tested platforms
|
|
124
131
|
- :ok: Linux (Ubuntu / KDE Neon)
|
|
125
132
|
- :ok: RapsberryPi
|
|
@@ -127,16 +134,15 @@ Shortcuts while using the GUI (QT & matplotlib backends)
|
|
|
127
134
|
|
|
128
135
|
|
|
129
136
|
|
|
130
|
-
| :star: | *PyQt / PySide* | *Matplotlib* | *Jupyter notebooks including Google collab* |
|
|
131
|
-
|:-----: |:-----:|:------:|:----: |
|
|
132
|
-
| Backend name | `qt` | `mpl` | `nb`|
|
|
133
|
-
| Preview |  |  |  |
|
|
134
|
-
| Plot curves | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
|
135
|
-
| Auto refreshed layout | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
|
|
136
|
-
| Keyboard shortcuts / fullscreen| :heavy_check_mark: | :heavy_check_mark: | :heavy_minus_sign: |
|
|
137
|
-
| Audio support | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
|
|
138
|
-
| Image buttons| :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
|
|
139
|
-
|
|
137
|
+
| :star: | *PyQt / PySide* | *Matplotlib* | *Jupyter notebooks including Google collab* | *Gradio* |
|
|
138
|
+
|:-----: |:-----:|:------:|:----: |:----: |
|
|
139
|
+
| Backend name | `qt` | `mpl` | `nb`| `gradio` |
|
|
140
|
+
| Preview |  |  |  | |
|
|
141
|
+
| Plot curves | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark:|
|
|
142
|
+
| Auto refreshed layout | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_minus_sign: |
|
|
143
|
+
| Keyboard shortcuts / fullscreen| :heavy_check_mark: | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
|
|
144
|
+
| Audio support | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign: |
|
|
145
|
+
| Image buttons| :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :heavy_minus_sign:|
|
|
140
146
|
|
|
141
147
|
|
|
142
148
|
|
|
@@ -154,12 +160,7 @@ Shortcuts while using the GUI (QT & matplotlib backends)
|
|
|
154
160
|

|
|
155
161
|
|
|
156
162
|
|
|
157
|
-
#### [Minimalistic pytorch based ISP ](https://github.com/balthazarneveu/interactive_pipe/tree/sample_interactive_isp/samples/isp)
|
|
158
|
-
[ISP means image signal processor](https://en.wikipedia.org/wiki/Image_processor)
|
|
159
163
|
|
|
160
|
-
:warning: Work in progess (no proper demosaicking, no denoiser, no tone mapping.)
|
|
161
|
-
|
|
162
|
-

|
|
163
164
|
|
|
164
165
|
|
|
165
166
|
# Tutorials
|
|
@@ -250,7 +251,7 @@ def generate_flat_colored_image(color_choice=["red", "green", "blue", "gray"], g
|
|
|
250
251
|
```
|
|
251
252
|
|
|
252
253
|
- Note that you can also create filters which take no inputs and simply "generate" images.
|
|
253
|
-
- The `color_choice` list will be
|
|
254
|
+
- The `color_choice` list will be turned into a nice dropdown menu. Default value here will be red as this is the first element of the list!
|
|
254
255
|
----------
|
|
255
256
|
|
|
256
257
|
:bulb: Can filters communicate together?
|
|
@@ -304,7 +305,8 @@ if __name__ == '__main__':
|
|
|
304
305
|
### History
|
|
305
306
|
- Interactive pipe was initially developped by [Balthazar Neveu](https://github.com/balthazarneveu) as part of the [irdrone project](https://github.com/wisescootering/infrareddrone/tree/master/interactive) based on matplotlib.
|
|
306
307
|
- Later, more contributions were also made by [Giuseppe Moschetti](https://github.com/g-moschetti) and Sylvain Leroy.
|
|
307
|
-
-
|
|
308
|
+
- August 2023: rewriting the whole core and supporting several graphical backends!
|
|
309
|
+
- September 2024: Gradio backend
|
|
308
310
|
|
|
309
311
|
|
|
310
312
|
|
|
@@ -324,3 +326,23 @@ if __name__ == '__main__':
|
|
|
324
326
|
- Exploratory backends
|
|
325
327
|
- Create a [textual](https://github.com/Textualize/textual) backend for simplified GUI (probably no images displayed)
|
|
326
328
|
- Create a [Kivy](https://kivy.org/) backend
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
### Further examples
|
|
332
|
+
|
|
333
|
+
#### [Minimalistic pytorch based ISP ](https://github.com/balthazarneveu/interactive_pipe/tree/sample_interactive_isp/samples/isp)
|
|
334
|
+
[ISP means image signal processor](https://en.wikipedia.org/wiki/Image_processor)
|
|
335
|
+
|
|
336
|
+
:warning: Work in progess (no proper demosaicking, no denoiser, no tone mapping.)
|
|
337
|
+
|
|
338
|
+

|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
#### :test_tube: Experimental features
|
|
345
|
+
- Custom events on specific key press
|
|
346
|
+
- Display the execution graph of the pipeline `G` key
|
|
347
|
+
- [thirdparty/music](/src/interactive_pipe/thirdparty/music.py) Play audio (Qt backend only). Play songs on spotify (linux only) when the spotify app is running.
|
|
348
|
+
- [thirdparty/images_openai_api](/src/interactive_pipe/thirdparty/images_openai_api.py) Generate images from prompt using OpenAI API image generation DALL-E Model (:dollar: paid service ~ 2cents/image)
|
|
@@ -20,6 +20,8 @@ src/interactive_pipe/data_objects/data.py
|
|
|
20
20
|
src/interactive_pipe/data_objects/image.py
|
|
21
21
|
src/interactive_pipe/data_objects/parameters.py
|
|
22
22
|
src/interactive_pipe/graphical/__init__.py
|
|
23
|
+
src/interactive_pipe/graphical/gradio_control.py
|
|
24
|
+
src/interactive_pipe/graphical/gradio_gui.py
|
|
23
25
|
src/interactive_pipe/graphical/gui.py
|
|
24
26
|
src/interactive_pipe/graphical/mpl_control.py
|
|
25
27
|
src/interactive_pipe/graphical/mpl_gui.py
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe.egg-info/requires.txt
RENAMED
|
@@ -2,6 +2,13 @@ matplotlib>=3.5.3
|
|
|
2
2
|
numpy>=1.21.6
|
|
3
3
|
Pillow>=9.0.1
|
|
4
4
|
PyYAML>=5.4.1
|
|
5
|
+
PyQt6>=6.5.2
|
|
6
|
+
PyQt6_sip>=13.5.2
|
|
7
|
+
opencv_python_headless>=4.8.1.78
|
|
8
|
+
pytest>=6.2.5
|
|
9
|
+
ipywidgets>=8.0.7
|
|
10
|
+
pandas
|
|
11
|
+
gradio
|
|
5
12
|
|
|
6
13
|
[full]
|
|
7
14
|
PyQt6>=6.5.2
|
|
@@ -10,6 +17,7 @@ opencv_python_headless>=4.8.1.78
|
|
|
10
17
|
pytest>=6.2.5
|
|
11
18
|
ipywidgets>=8.0.7
|
|
12
19
|
pandas
|
|
20
|
+
gradio
|
|
13
21
|
|
|
14
22
|
[notebook]
|
|
15
23
|
ipywidgets>=8.0.7
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/data_objects/__init__.py
RENAMED
|
File without changes
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/data_objects/curves.py
RENAMED
|
File without changes
|
|
File without changes
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/data_objects/image.py
RENAMED
|
File without changes
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/data_objects/parameters.py
RENAMED
|
File without changes
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/mpl_control.py
RENAMED
|
File without changes
|
|
File without changes
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/mpl_window.py
RENAMED
|
File without changes
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/nb_control.py
RENAMED
|
File without changes
|
|
File without changes
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/qt_control.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/filter_decorator.py
RENAMED
|
File without changes
|
|
File without changes
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/pipeline_decorator.py
RENAMED
|
File without changes
|
|
File without changes
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe/thirdparty/music_spotify.py
RENAMED
|
File without changes
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{interactive_pipe-0.6.0 → interactive_pipe-0.7.0}/src/interactive_pipe.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|