interactive-pipe 0.6.1__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.
Files changed (60) hide show
  1. {interactive_pipe-0.6.1/src/interactive_pipe.egg-info → interactive_pipe-0.7.0}/PKG-INFO +39 -26
  2. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/pyproject.toml +3 -1
  3. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/readme.md +37 -26
  4. interactive_pipe-0.7.0/src/interactive_pipe/graphical/gradio_control.py +95 -0
  5. interactive_pipe-0.7.0/src/interactive_pipe/graphical/gradio_gui.py +173 -0
  6. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/choose_backend.py +2 -0
  7. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0/src/interactive_pipe.egg-info}/PKG-INFO +39 -26
  8. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe.egg-info/SOURCES.txt +2 -0
  9. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe.egg-info/requires.txt +2 -0
  10. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/LICENSE +0 -0
  11. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/setup.cfg +0 -0
  12. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/__init__.py +0 -0
  13. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/core/__init__.py +0 -0
  14. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/core/cache.py +0 -0
  15. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/core/engine.py +0 -0
  16. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/core/filter.py +0 -0
  17. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/core/graph.py +0 -0
  18. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/core/pipeline.py +0 -0
  19. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/core/signature.py +0 -0
  20. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/data_objects/__init__.py +0 -0
  21. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/data_objects/curves.py +0 -0
  22. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/data_objects/data.py +0 -0
  23. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/data_objects/image.py +0 -0
  24. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/data_objects/parameters.py +0 -0
  25. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/__init__.py +0 -0
  26. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/gui.py +0 -0
  27. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/mpl_control.py +0 -0
  28. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/mpl_gui.py +0 -0
  29. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/mpl_window.py +0 -0
  30. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/nb_control.py +0 -0
  31. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/nb_gui.py +0 -0
  32. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/qt_control.py +0 -0
  33. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/qt_gui.py +0 -0
  34. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/graphical/window.py +0 -0
  35. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/headless/__init__.py +0 -0
  36. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/headless/control.py +0 -0
  37. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/headless/keyboard.py +0 -0
  38. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/headless/pipeline.py +0 -0
  39. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/__init__.py +0 -0
  40. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/_private.py +0 -0
  41. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/control_abbreviation.py +0 -0
  42. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/filter_decorator.py +0 -0
  43. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/keyword_args_analyzer.py +0 -0
  44. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/helper/pipeline_decorator.py +0 -0
  45. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/thirdparty/images_openai_api.py +0 -0
  46. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe/thirdparty/music_spotify.py +0 -0
  47. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe.egg-info/dependency_links.txt +0 -0
  48. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/src/interactive_pipe.egg-info/top_level.txt +0 -0
  49. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/test/test_cache.py +0 -0
  50. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/test/test_control_abbreviations.py +0 -0
  51. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/test/test_controller.py +0 -0
  52. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/test/test_core.py +0 -0
  53. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/test/test_curves.py +0 -0
  54. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/test/test_decorator.py +0 -0
  55. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/test/test_engine.py +0 -0
  56. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/test/test_filter.py +0 -0
  57. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/test/test_headless.py +0 -0
  58. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/test/test_image.py +0 -0
  59. {interactive_pipe-0.6.1 → interactive_pipe-0.7.0}/test/test_parameters.py +0 -0
  60. {interactive_pipe-0.6.1 → 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.6.1
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
@@ -21,6 +21,7 @@ Requires-Dist: opencv_python_headless>=4.8.1.78
21
21
  Requires-Dist: pytest>=6.2.5
22
22
  Requires-Dist: ipywidgets>=8.0.7
23
23
  Requires-Dist: pandas
24
+ Requires-Dist: gradio
24
25
  Provides-Extra: qt6
25
26
  Requires-Dist: PyQt6>=6.5.2; extra == "qt6"
26
27
  Requires-Dist: PyQt6_sip>=13.5.2; extra == "qt6"
@@ -39,6 +40,7 @@ Requires-Dist: opencv_python_headless>=4.8.1.78; extra == "full"
39
40
  Requires-Dist: pytest>=6.2.5; extra == "full"
40
41
  Requires-Dist: ipywidgets>=8.0.7; extra == "full"
41
42
  Requires-Dist: pandas; extra == "full"
43
+ Requires-Dist: gradio; extra == "full"
42
44
 
43
45
  # `interactive_pipe`
44
46
 
@@ -93,7 +95,7 @@ pip install -e ".[full]"
93
95
 
94
96
  ## :scroll: Features
95
97
 
96
- **Version 0.6.0**
98
+ **Version 0.7.0**
97
99
  - Modular multi-image processing filters
98
100
  - Declarative: Easily make graphical user interface without having to learn anything about pyQt or matplotlib
99
101
  - Support in jupyter notebooks
@@ -101,6 +103,7 @@ pip install -e ".[full]"
101
103
  - Cache intermediate results in RAM for much faster processing
102
104
  - `KeyboardControl` : no slider on UI but exactly the same internal mechanism, update on key press.
103
105
  - Support Curve plots (2D signals)
106
+ - :new: gradio backend (+allows sharing with others)
104
107
 
105
108
 
106
109
 
@@ -122,7 +125,8 @@ Shortcuts while using the GUI (QT & matplotlib backends)
122
125
  - supported backends
123
126
  - :ok: `gui='qt'` pyQt/pySide
124
127
  - :ok: `gui='mpl'` matplotlib
125
- - :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)
126
130
  - tested platforms
127
131
  - :ok: Linux (Ubuntu / KDE Neon)
128
132
  - :ok: RapsberryPi
@@ -130,25 +134,18 @@ Shortcuts while using the GUI (QT & matplotlib backends)
130
134
 
131
135
 
132
136
 
133
- | :star: | *PyQt / PySide* | *Matplotlib* | *Jupyter notebooks including Google collab* |
134
- |:-----: |:-----:|:------:|:----: |
135
- | Backend name | `qt` | `mpl` | `nb`|
136
- | Preview | ![qt backend](/doc/images/qt_backend.jpg) | ![mpl backend](/doc/images/mpl_backend.jpg) | ![nb backend](/doc/images/notebook_backend.jpg) |
137
- | Plot curves | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
138
- | Auto refreshed layout | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
139
- | Keyboard shortcuts / fullscreen| :heavy_check_mark: | :heavy_check_mark: | :heavy_minus_sign: |
140
- | Audio support | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
141
- | Image buttons| :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
137
+ | :star: | *PyQt / PySide* | *Matplotlib* | *Jupyter notebooks including Google collab* | *Gradio* |
138
+ |:-----: |:-----:|:------:|:----: |:----: |
139
+ | Backend name | `qt` | `mpl` | `nb`| `gradio` |
140
+ | Preview | ![qt backend](/doc/images/qt_backend.jpg) | ![mpl backend](/doc/images/mpl_backend.jpg) | ![nb backend](/doc/images/notebook_backend.jpg) | |
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:|
142
146
 
143
147
 
144
148
 
145
-
146
- #### :test_tube: Experimental features
147
- - Custom events on specific key press
148
- - Display the execution graph of the pipeline `G` key
149
- - [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.
150
- - [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)
151
-
152
149
  # Tutorials
153
150
 
154
151
  ### Learn by examples
@@ -163,12 +160,7 @@ Shortcuts while using the GUI (QT & matplotlib backends)
163
160
  ![Speech processing exploration in a notebook](/doc/images/jupyter_integration_speech.png)
164
161
 
165
162
 
166
- #### [Minimalistic pytorch based ISP ](https://github.com/balthazarneveu/interactive_pipe/tree/sample_interactive_isp/samples/isp)
167
- [ISP means image signal processor](https://en.wikipedia.org/wiki/Image_processor)
168
-
169
- :warning: Work in progess (no proper demosaicking, no denoiser, no tone mapping.)
170
163
 
171
- ![Ultra simplistic ISP](/doc/images/isp_pipeline.png)
172
164
 
173
165
 
174
166
  # Tutorials
@@ -259,7 +251,7 @@ def generate_flat_colored_image(color_choice=["red", "green", "blue", "gray"], g
259
251
  ```
260
252
 
261
253
  - Note that you can also create filters which take no inputs and simply "generate" images.
262
- - The `color_choice` list will be turnt into a nice dropdown menu. Default value here will be red as this is the first element of the list!
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!
263
255
  ----------
264
256
 
265
257
  :bulb: Can filters communicate together?
@@ -313,7 +305,8 @@ if __name__ == '__main__':
313
305
  ### History
314
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.
315
307
  - Later, more contributions were also made by [Giuseppe Moschetti](https://github.com/g-moschetti) and Sylvain Leroy.
316
- - Summer 2023: rewriting the whole core and supporting several graphical backends!
308
+ - August 2023: rewriting the whole core and supporting several graphical backends!
309
+ - September 2024: Gradio backend
317
310
 
318
311
 
319
312
 
@@ -333,3 +326,23 @@ if __name__ == '__main__':
333
326
  - Exploratory backends
334
327
  - Create a [textual](https://github.com/Textualize/textual) backend for simplified GUI (probably no images displayed)
335
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
+ ![Ultra simplistic ISP](/doc/images/isp_pipeline.png)
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.6.1"
8
+ version = "0.7.0"
9
9
  authors = [
10
10
  { name="Balthazar Neveu", email="balthazarneveu@gmail.com" },
11
11
  ]
@@ -20,6 +20,7 @@ dependencies = [
20
20
  "pytest>=6.2.5",
21
21
  "ipywidgets>=8.0.7",
22
22
  "pandas",
23
+ "gradio",
23
24
  ]
24
25
 
25
26
  description = "Library to create flexible interactive image processing pipelines and automatically add a graphical user interface without knowing anything about GUI coding!"
@@ -62,4 +63,5 @@ full=[
62
63
  "pytest>=6.2.5",
63
64
  "ipywidgets>=8.0.7",
64
65
  "pandas",
66
+ "gradio",
65
67
  ]
@@ -51,7 +51,7 @@ pip install -e ".[full]"
51
51
 
52
52
  ## :scroll: Features
53
53
 
54
- **Version 0.6.0**
54
+ **Version 0.7.0**
55
55
  - Modular multi-image processing filters
56
56
  - Declarative: Easily make graphical user interface without having to learn anything about pyQt or matplotlib
57
57
  - Support in jupyter notebooks
@@ -59,6 +59,7 @@ pip install -e ".[full]"
59
59
  - Cache intermediate results in RAM for much faster processing
60
60
  - `KeyboardControl` : no slider on UI but exactly the same internal mechanism, update on key press.
61
61
  - Support Curve plots (2D signals)
62
+ - :new: gradio backend (+allows sharing with others)
62
63
 
63
64
 
64
65
 
@@ -80,7 +81,8 @@ Shortcuts while using the GUI (QT & matplotlib backends)
80
81
  - supported backends
81
82
  - :ok: `gui='qt'` pyQt/pySide
82
83
  - :ok: `gui='mpl'` matplotlib
83
- - :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)
84
86
  - tested platforms
85
87
  - :ok: Linux (Ubuntu / KDE Neon)
86
88
  - :ok: RapsberryPi
@@ -88,25 +90,18 @@ Shortcuts while using the GUI (QT & matplotlib backends)
88
90
 
89
91
 
90
92
 
91
- | :star: | *PyQt / PySide* | *Matplotlib* | *Jupyter notebooks including Google collab* |
92
- |:-----: |:-----:|:------:|:----: |
93
- | Backend name | `qt` | `mpl` | `nb`|
94
- | Preview | ![qt backend](/doc/images/qt_backend.jpg) | ![mpl backend](/doc/images/mpl_backend.jpg) | ![nb backend](/doc/images/notebook_backend.jpg) |
95
- | Plot curves | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
96
- | Auto refreshed layout | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
97
- | Keyboard shortcuts / fullscreen| :heavy_check_mark: | :heavy_check_mark: | :heavy_minus_sign: |
98
- | Audio support | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
99
- | Image buttons| :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
93
+ | :star: | *PyQt / PySide* | *Matplotlib* | *Jupyter notebooks including Google collab* | *Gradio* |
94
+ |:-----: |:-----:|:------:|:----: |:----: |
95
+ | Backend name | `qt` | `mpl` | `nb`| `gradio` |
96
+ | Preview | ![qt backend](/doc/images/qt_backend.jpg) | ![mpl backend](/doc/images/mpl_backend.jpg) | ![nb backend](/doc/images/notebook_backend.jpg) | |
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:|
100
102
 
101
103
 
102
104
 
103
-
104
- #### :test_tube: Experimental features
105
- - Custom events on specific key press
106
- - Display the execution graph of the pipeline `G` key
107
- - [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.
108
- - [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)
109
-
110
105
  # Tutorials
111
106
 
112
107
  ### Learn by examples
@@ -121,12 +116,7 @@ Shortcuts while using the GUI (QT & matplotlib backends)
121
116
  ![Speech processing exploration in a notebook](/doc/images/jupyter_integration_speech.png)
122
117
 
123
118
 
124
- #### [Minimalistic pytorch based ISP ](https://github.com/balthazarneveu/interactive_pipe/tree/sample_interactive_isp/samples/isp)
125
- [ISP means image signal processor](https://en.wikipedia.org/wiki/Image_processor)
126
119
 
127
- :warning: Work in progess (no proper demosaicking, no denoiser, no tone mapping.)
128
-
129
- ![Ultra simplistic ISP](/doc/images/isp_pipeline.png)
130
120
 
131
121
 
132
122
  # Tutorials
@@ -217,7 +207,7 @@ def generate_flat_colored_image(color_choice=["red", "green", "blue", "gray"], g
217
207
  ```
218
208
 
219
209
  - Note that you can also create filters which take no inputs and simply "generate" images.
220
- - The `color_choice` list will be turnt into a nice dropdown menu. Default value here will be red as this is the first element of the list!
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!
221
211
  ----------
222
212
 
223
213
  :bulb: Can filters communicate together?
@@ -271,7 +261,8 @@ if __name__ == '__main__':
271
261
  ### History
272
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.
273
263
  - Later, more contributions were also made by [Giuseppe Moschetti](https://github.com/g-moschetti) and Sylvain Leroy.
274
- - Summer 2023: rewriting the whole core and supporting several graphical backends!
264
+ - August 2023: rewriting the whole core and supporting several graphical backends!
265
+ - September 2024: Gradio backend
275
266
 
276
267
 
277
268
 
@@ -290,4 +281,24 @@ if __name__ == '__main__':
290
281
  - Animations/While loops/Video source (Time slider)
291
282
  - Exploratory backends
292
283
  - Create a [textual](https://github.com/Textualize/textual) backend for simplified GUI (probably no images displayed)
293
- - 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
+ ![Ultra simplistic ISP](/doc/images/isp_pipeline.png)
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}
@@ -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.6.1
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
@@ -21,6 +21,7 @@ Requires-Dist: opencv_python_headless>=4.8.1.78
21
21
  Requires-Dist: pytest>=6.2.5
22
22
  Requires-Dist: ipywidgets>=8.0.7
23
23
  Requires-Dist: pandas
24
+ Requires-Dist: gradio
24
25
  Provides-Extra: qt6
25
26
  Requires-Dist: PyQt6>=6.5.2; extra == "qt6"
26
27
  Requires-Dist: PyQt6_sip>=13.5.2; extra == "qt6"
@@ -39,6 +40,7 @@ Requires-Dist: opencv_python_headless>=4.8.1.78; extra == "full"
39
40
  Requires-Dist: pytest>=6.2.5; extra == "full"
40
41
  Requires-Dist: ipywidgets>=8.0.7; extra == "full"
41
42
  Requires-Dist: pandas; extra == "full"
43
+ Requires-Dist: gradio; extra == "full"
42
44
 
43
45
  # `interactive_pipe`
44
46
 
@@ -93,7 +95,7 @@ pip install -e ".[full]"
93
95
 
94
96
  ## :scroll: Features
95
97
 
96
- **Version 0.6.0**
98
+ **Version 0.7.0**
97
99
  - Modular multi-image processing filters
98
100
  - Declarative: Easily make graphical user interface without having to learn anything about pyQt or matplotlib
99
101
  - Support in jupyter notebooks
@@ -101,6 +103,7 @@ pip install -e ".[full]"
101
103
  - Cache intermediate results in RAM for much faster processing
102
104
  - `KeyboardControl` : no slider on UI but exactly the same internal mechanism, update on key press.
103
105
  - Support Curve plots (2D signals)
106
+ - :new: gradio backend (+allows sharing with others)
104
107
 
105
108
 
106
109
 
@@ -122,7 +125,8 @@ Shortcuts while using the GUI (QT & matplotlib backends)
122
125
  - supported backends
123
126
  - :ok: `gui='qt'` pyQt/pySide
124
127
  - :ok: `gui='mpl'` matplotlib
125
- - :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)
126
130
  - tested platforms
127
131
  - :ok: Linux (Ubuntu / KDE Neon)
128
132
  - :ok: RapsberryPi
@@ -130,25 +134,18 @@ Shortcuts while using the GUI (QT & matplotlib backends)
130
134
 
131
135
 
132
136
 
133
- | :star: | *PyQt / PySide* | *Matplotlib* | *Jupyter notebooks including Google collab* |
134
- |:-----: |:-----:|:------:|:----: |
135
- | Backend name | `qt` | `mpl` | `nb`|
136
- | Preview | ![qt backend](/doc/images/qt_backend.jpg) | ![mpl backend](/doc/images/mpl_backend.jpg) | ![nb backend](/doc/images/notebook_backend.jpg) |
137
- | Plot curves | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
138
- | Auto refreshed layout | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
139
- | Keyboard shortcuts / fullscreen| :heavy_check_mark: | :heavy_check_mark: | :heavy_minus_sign: |
140
- | Audio support | :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
141
- | Image buttons| :heavy_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: |
137
+ | :star: | *PyQt / PySide* | *Matplotlib* | *Jupyter notebooks including Google collab* | *Gradio* |
138
+ |:-----: |:-----:|:------:|:----: |:----: |
139
+ | Backend name | `qt` | `mpl` | `nb`| `gradio` |
140
+ | Preview | ![qt backend](/doc/images/qt_backend.jpg) | ![mpl backend](/doc/images/mpl_backend.jpg) | ![nb backend](/doc/images/notebook_backend.jpg) | |
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:|
142
146
 
143
147
 
144
148
 
145
-
146
- #### :test_tube: Experimental features
147
- - Custom events on specific key press
148
- - Display the execution graph of the pipeline `G` key
149
- - [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.
150
- - [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)
151
-
152
149
  # Tutorials
153
150
 
154
151
  ### Learn by examples
@@ -163,12 +160,7 @@ Shortcuts while using the GUI (QT & matplotlib backends)
163
160
  ![Speech processing exploration in a notebook](/doc/images/jupyter_integration_speech.png)
164
161
 
165
162
 
166
- #### [Minimalistic pytorch based ISP ](https://github.com/balthazarneveu/interactive_pipe/tree/sample_interactive_isp/samples/isp)
167
- [ISP means image signal processor](https://en.wikipedia.org/wiki/Image_processor)
168
-
169
- :warning: Work in progess (no proper demosaicking, no denoiser, no tone mapping.)
170
163
 
171
- ![Ultra simplistic ISP](/doc/images/isp_pipeline.png)
172
164
 
173
165
 
174
166
  # Tutorials
@@ -259,7 +251,7 @@ def generate_flat_colored_image(color_choice=["red", "green", "blue", "gray"], g
259
251
  ```
260
252
 
261
253
  - Note that you can also create filters which take no inputs and simply "generate" images.
262
- - The `color_choice` list will be turnt into a nice dropdown menu. Default value here will be red as this is the first element of the list!
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!
263
255
  ----------
264
256
 
265
257
  :bulb: Can filters communicate together?
@@ -313,7 +305,8 @@ if __name__ == '__main__':
313
305
  ### History
314
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.
315
307
  - Later, more contributions were also made by [Giuseppe Moschetti](https://github.com/g-moschetti) and Sylvain Leroy.
316
- - Summer 2023: rewriting the whole core and supporting several graphical backends!
308
+ - August 2023: rewriting the whole core and supporting several graphical backends!
309
+ - September 2024: Gradio backend
317
310
 
318
311
 
319
312
 
@@ -333,3 +326,23 @@ if __name__ == '__main__':
333
326
  - Exploratory backends
334
327
  - Create a [textual](https://github.com/Textualize/textual) backend for simplified GUI (probably no images displayed)
335
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
+ ![Ultra simplistic ISP](/doc/images/isp_pipeline.png)
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
@@ -8,6 +8,7 @@ opencv_python_headless>=4.8.1.78
8
8
  pytest>=6.2.5
9
9
  ipywidgets>=8.0.7
10
10
  pandas
11
+ gradio
11
12
 
12
13
  [full]
13
14
  PyQt6>=6.5.2
@@ -16,6 +17,7 @@ opencv_python_headless>=4.8.1.78
16
17
  pytest>=6.2.5
17
18
  ipywidgets>=8.0.7
18
19
  pandas
20
+ gradio
19
21
 
20
22
  [notebook]
21
23
  ipywidgets>=8.0.7