interactive-pipe 0.6.1__tar.gz → 0.7.1__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 (61) hide show
  1. {interactive_pipe-0.6.1/src/interactive_pipe.egg-info → interactive_pipe-0.7.1}/PKG-INFO +39 -26
  2. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/pyproject.toml +3 -1
  3. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/readme.md +37 -26
  4. interactive_pipe-0.7.1/src/interactive_pipe/data_objects/audio.py +32 -0
  5. interactive_pipe-0.7.1/src/interactive_pipe/graphical/gradio_control.py +103 -0
  6. interactive_pipe-0.7.1/src/interactive_pipe/graphical/gradio_gui.py +263 -0
  7. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/helper/choose_backend.py +2 -0
  8. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1/src/interactive_pipe.egg-info}/PKG-INFO +39 -26
  9. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe.egg-info/SOURCES.txt +3 -0
  10. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe.egg-info/requires.txt +2 -0
  11. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/LICENSE +0 -0
  12. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/setup.cfg +0 -0
  13. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/__init__.py +0 -0
  14. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/core/__init__.py +0 -0
  15. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/core/cache.py +0 -0
  16. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/core/engine.py +0 -0
  17. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/core/filter.py +0 -0
  18. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/core/graph.py +0 -0
  19. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/core/pipeline.py +0 -0
  20. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/core/signature.py +0 -0
  21. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/data_objects/__init__.py +0 -0
  22. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/data_objects/curves.py +0 -0
  23. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/data_objects/data.py +0 -0
  24. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/data_objects/image.py +0 -0
  25. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/data_objects/parameters.py +0 -0
  26. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/graphical/__init__.py +0 -0
  27. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/graphical/gui.py +0 -0
  28. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/graphical/mpl_control.py +0 -0
  29. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/graphical/mpl_gui.py +0 -0
  30. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/graphical/mpl_window.py +0 -0
  31. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/graphical/nb_control.py +0 -0
  32. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/graphical/nb_gui.py +0 -0
  33. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/graphical/qt_control.py +0 -0
  34. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/graphical/qt_gui.py +0 -0
  35. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/graphical/window.py +0 -0
  36. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/headless/__init__.py +0 -0
  37. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/headless/control.py +0 -0
  38. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/headless/keyboard.py +0 -0
  39. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/headless/pipeline.py +0 -0
  40. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/helper/__init__.py +0 -0
  41. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/helper/_private.py +0 -0
  42. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/helper/control_abbreviation.py +0 -0
  43. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/helper/filter_decorator.py +0 -0
  44. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/helper/keyword_args_analyzer.py +0 -0
  45. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/helper/pipeline_decorator.py +0 -0
  46. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/thirdparty/images_openai_api.py +0 -0
  47. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe/thirdparty/music_spotify.py +0 -0
  48. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe.egg-info/dependency_links.txt +0 -0
  49. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/src/interactive_pipe.egg-info/top_level.txt +0 -0
  50. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/test/test_cache.py +0 -0
  51. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/test/test_control_abbreviations.py +0 -0
  52. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/test/test_controller.py +0 -0
  53. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/test/test_core.py +0 -0
  54. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/test/test_curves.py +0 -0
  55. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/test/test_decorator.py +0 -0
  56. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/test/test_engine.py +0 -0
  57. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/test/test_filter.py +0 -0
  58. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/test/test_headless.py +0 -0
  59. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/test/test_image.py +0 -0
  60. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/test/test_parameters.py +0 -0
  61. {interactive_pipe-0.6.1 → interactive_pipe-0.7.1}/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.1
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.1**
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.1"
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.1**
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,32 @@
1
+ from pathlib import Path
2
+ import numpy as np
3
+ from io import BytesIO
4
+ import base64
5
+ import logging
6
+ from typing import Union, Tuple
7
+ WAVIO_AVAILABLE = False
8
+ try:
9
+ WAVIO_AVAILABLE = True
10
+ import wavio
11
+ except ImportError:
12
+ logging.info("Cannot import wavio")
13
+
14
+
15
+ def audio_to_html(audio: Union[None, str, Path, Tuple[int, np.ndarray]]) -> str:
16
+ if audio is None:
17
+ logging.debug("No audio to display")
18
+ return ""
19
+ if isinstance(audio, str) or isinstance(audio, Path):
20
+ audio_base64 = base64.b64encode(open(audio, "rb").read()).decode("utf-8")
21
+ elif isinstance(audio, tuple):
22
+ assert WAVIO_AVAILABLE, "wavio is not available"
23
+ assert len(audio) == 2, "audio tuple should have 2 elements: (rate, data)"
24
+ assert isinstance(audio[0], int), "audio[0] should be an integer"
25
+ assert isinstance(audio[1], np.ndarray), "audio[1] should be a numpy array"
26
+ audio_bytes = BytesIO()
27
+ wavio.write(audio_bytes, audio[1].astype(np.float32), audio[0], sampwidth=4)
28
+ audio_bytes.seek(0)
29
+ audio_base64 = base64.b64encode(audio_bytes.read()).decode("utf-8")
30
+ audio_player = f'<audio src="data:audio/mpeg;base64,{audio_base64}" controls autoplay></audio>'
31
+
32
+ return audio_player
@@ -0,0 +1,103 @@
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,
53
+ minimum=self.ctrl.value_range[0],
54
+ maximum=self.ctrl.value_range[1],
55
+ label=self.name,
56
+ step=1
57
+ )
58
+ return self.control_widget
59
+
60
+
61
+ class FloatSliderControl(BaseControl):
62
+ def check_control_type(self):
63
+ assert self.ctrl._type == float
64
+
65
+ def create(self) -> gr.Slider:
66
+ self.control_widget = gr.Slider(
67
+ value=self.ctrl.value_default,
68
+ minimum=self.ctrl.value_range[0],
69
+ maximum=self.ctrl.value_range[1],
70
+ label=self.name,
71
+ )
72
+
73
+ return self.control_widget
74
+
75
+
76
+ class TickBoxControl(BaseControl):
77
+ def check_control_type(self):
78
+ assert self.ctrl._type == bool
79
+
80
+ def create(self) -> gr.Checkbox:
81
+ self.control_widget = gr.Checkbox(label=self.name, value=self.ctrl.value)
82
+ return self.control_widget
83
+
84
+ def reset(self):
85
+ self.control_widget.update(value=self.ctrl.default_value)
86
+
87
+
88
+ class DropdownMenuControl(BaseControl):
89
+ def check_control_type(self):
90
+ assert self.ctrl._type == str
91
+ if not hasattr(self.ctrl, 'value_range'):
92
+ raise ValueError("Invalid control type")
93
+
94
+ def create(self) -> gr.Dropdown:
95
+ # Create a horizontal layout to hold the dropdown menu
96
+ self.control_widget = gr.Dropdown(label=self.name, choices=self.ctrl.value_range, value=self.ctrl.value)
97
+ return self.control_widget
98
+
99
+ def reset(self):
100
+ index = self.control_widget.findText(self.ctrl.value)
101
+ if index >= 0:
102
+ self.control_widget.setCurrentIndex(index)
103
+ self.control_widget.setCurrentIndex(index)
@@ -0,0 +1,263 @@
1
+ import gradio as gr
2
+ import numpy as np
3
+ import math
4
+ from typing import List
5
+ from interactive_pipe.headless.pipeline import HeadlessPipeline
6
+ from interactive_pipe.graphical.gradio_control import ControlFactory
7
+ from interactive_pipe.graphical.window import InteractivePipeWindow
8
+ from interactive_pipe.graphical.gui import InteractivePipeGUI
9
+ from interactive_pipe.headless.control import Control
10
+ from interactive_pipe.data_objects.audio import audio_to_html
11
+ import logging
12
+ PYQTVERSION = None
13
+ MPL_SUPPORT = False
14
+ GRADIO_INTERFACE_MODE = False
15
+ try:
16
+ from interactive_pipe.data_objects.curves import Curve
17
+ import matplotlib.pyplot as plt
18
+ MPL_SUPPORT = True
19
+ except ImportError:
20
+ pass
21
+
22
+
23
+ class InteractivePipeGradio(InteractivePipeGUI):
24
+ def init_app(self, **kwargs):
25
+ self.window = MainWindow(controls=self.controls, name=self.name,
26
+ pipeline=self.pipeline, size=self.size, main_gui=self, audio=self.audio, **kwargs)
27
+ self.pipeline.global_params["__pipeline"] = self.pipeline
28
+ if self.audio:
29
+ self.pipeline.global_params["__set_audio"] = self.__set_audio
30
+ self.pipeline.global_params["__play"] = self.__play
31
+ self.pipeline.global_params["__stop"] = self.__stop
32
+ self.pipeline.global_params["__pause"] = self.__pause
33
+ self.__set_audio(None)
34
+
35
+ def __set_audio(self, audio_content):
36
+ self.window.audio_content = audio_content
37
+
38
+ def __play(self):
39
+ pass
40
+
41
+ def __pause(self):
42
+ self.__set_audio(None)
43
+
44
+ def __stop(self):
45
+ self.__set_audio(None)
46
+
47
+ def run(self) -> list:
48
+ assert self.pipeline._PipelineCore__initialized_inputs, "Did you forget to initialize the pipeline inputs?"
49
+ out_list = self.window.process_inputs_fn(*self.window.default_values)
50
+ self.window.refresh_display(out_list)
51
+ out_list_gradio_containers = []
52
+ for idx in range(len(out_list)):
53
+ for idy in range(len(out_list[idx])):
54
+ title = self.window.image_canvas[idx][idy].get("title", f"{idx} {idy}")
55
+ title = title.replace("_", " ")
56
+ if isinstance(out_list[idx][idy], np.ndarray):
57
+ out_list_gradio_containers.append(gr.Image(label=title))
58
+ elif MPL_SUPPORT and isinstance(out_list[idx][idy], Curve):
59
+ # if out_list[idx][idy].title is not None:
60
+ # title = out_list[idx][idy].title
61
+ out_list_gradio_containers.append(gr.Plot(label=title))
62
+ else:
63
+ raise NotImplementedError(
64
+ f"output type {type(out_list[idx][idy])} not supported")
65
+ if self.window.audio:
66
+ self.window.audio = gr.HTML()
67
+ self.pipeline.global_params["__audio"] = self.window.audio
68
+ self.window.instantiate_gradio_interface(out_list_gradio_containers)
69
+ self.window.refresh()
70
+ self.custom_end()
71
+ return self.pipeline.results
72
+
73
+ def print_message(self, message_list: List[str]):
74
+ print("\n".join(message_list))
75
+
76
+
77
+ class MainWindow(InteractivePipeWindow):
78
+ def __init__(self, *args, controls=[], name="", pipeline: HeadlessPipeline = None, size=None, share_gradio_app=False, markdown_description=None, sliders_layout=None, sliders_per_row_layout=None, audio=False, **kwargs):
79
+ InteractivePipeWindow.__init__(
80
+ self, name=name, pipeline=pipeline, size=size)
81
+ self.markdown_description = markdown_description
82
+ self.sliders_layout = sliders_layout
83
+ self.sliders_per_row_layout = sliders_per_row_layout
84
+ self.init_sliders(controls)
85
+ self.size = size
86
+ self.full_screen_flag = False
87
+ self.pipeline = pipeline
88
+ self.share_gradio_app = share_gradio_app
89
+ self.audio = audio
90
+ # Define the functions that will be called when the input changes for gradio. => gr.Interface(fn=process_fn)
91
+
92
+ def process_outputs_fn(out) -> tuple:
93
+ flat_out = []
94
+ for idx in range(len(out)):
95
+ if isinstance(out[idx], list):
96
+ for idy in range(len(out[idx])):
97
+ if MPL_SUPPORT and isinstance(out[idx][idy], Curve):
98
+ curve = out[idx][idy]
99
+ fig, ax = plt.subplots()
100
+ Curve._plot_curve(curve.data, ax=ax)
101
+ flat_out.append(fig)
102
+ elif isinstance(out[idx][idy], np.ndarray):
103
+ logging.info(f"CONVERTING IMAGE {idx} {idy}")
104
+ flat_out.append(self.convert_image(out[idx][idy]))
105
+ else:
106
+ raise NotImplementedError(
107
+ f"output type {type(out[idx][idy])} not supported")
108
+ else:
109
+ logging.info(f"CONVERTING IMAGE {idx} ")
110
+ flat_out.append(self.convert_image(out[idx]))
111
+ if out is None:
112
+ logging.warning("No output to display")
113
+ return
114
+ return tuple(flat_out)
115
+
116
+ def process_inputs_fn(*args) -> list:
117
+ all_keys = list(self.ctrl.keys())
118
+ for idx in range(len(args)):
119
+ self.ctrl[all_keys[idx]].update(args[idx])
120
+ out = self.pipeline.run()
121
+ return out
122
+
123
+ def run_fn(*args) -> tuple:
124
+ out = process_inputs_fn(*args)
125
+ out_tuple = process_outputs_fn(out)
126
+ if self.audio:
127
+ html_audio = audio_to_html(self.audio_content)
128
+ return *out_tuple, html_audio
129
+ return out_tuple
130
+ self.default_values = [self.ctrl[ctrl_key].value for ctrl_key in self.ctrl.keys()]
131
+ self.process_inputs_fn = process_inputs_fn
132
+ self.run_fn = run_fn
133
+
134
+ def instantiate_gradio_interface(self, outputs: List[gr.Blocks]):
135
+ if GRADIO_INTERFACE_MODE:
136
+ # Interface mode, high level wrapper
137
+ # https://www.gradio.app/guides/the-interface-class
138
+ self.io = gr.Interface(
139
+ allow_flagging='never',
140
+ fn=self.run_fn,
141
+ title=self.name,
142
+ inputs=self.widget_list,
143
+ outputs=outputs,
144
+ examples=[self.default_values],
145
+ live=True,
146
+ show_progress="minimal",
147
+ clear_btn=None,
148
+ )
149
+ else:
150
+ # Gradio Blocks mode
151
+ # https://www.gradio.app/guides/blocks-and-event-listeners
152
+ with gr.Blocks() as io:
153
+ if self.audio:
154
+ outputs.append(self.audio)
155
+ with gr.Row(variant="compact"):
156
+ gr.Markdown("### " + self.name.replace("_", " "))
157
+ with gr.Row():
158
+ for elem in outputs:
159
+ elem.render()
160
+
161
+ if self.sliders_layout is None:
162
+ self.sliders_layout = "collapsible"
163
+ if self.sliders_per_row_layout is None:
164
+ self.sliders_per_row_layout = 1
165
+ assert self.sliders_layout in ["compact", "vertical", "collapsible", "smart"]
166
+ ctrl_dict_by_type = {"all": list(range(len(self.ctrl)))}
167
+ categories = ["all"]
168
+ if self.sliders_layout == "compact":
169
+ selected_mode = gr.Row()
170
+ elif self.sliders_layout == "vertical":
171
+ # Use Column to stack elements vertically
172
+ selected_mode = gr.Column()
173
+ elif self.sliders_layout == "collapsible":
174
+ selected_mode = gr.Accordion("Parameters", open=True)
175
+ elif self.sliders_layout == "smart":
176
+ # Group sliders by type
177
+ ctrl_dict_by_type = {}
178
+ for ctrl_index, ctrl_key in enumerate(self.ctrl.keys()):
179
+ ctrl_type = self.ctrl[ctrl_key]._type
180
+ ctrl_type = str(ctrl_type).split("<class '")[1].replace("'>", "")
181
+ if ctrl_type == "int":
182
+ ctrl_type = "float"
183
+ if ctrl_type not in ctrl_dict_by_type:
184
+ ctrl_dict_by_type[ctrl_type] = []
185
+ ctrl_dict_by_type[ctrl_type].append(ctrl_index)
186
+ categories = ["str", "bool", "float"]
187
+ selected_mode = gr.Column()
188
+ else:
189
+ raise NotImplementedError(f"Sliders layout {self.sliders_layout} not supported")
190
+ for ctrl_type in categories:
191
+ ctrl_indices = ctrl_dict_by_type.get(ctrl_type, [])
192
+ if len(ctrl_indices) == 0:
193
+ continue
194
+ if self.sliders_per_row_layout == 1:
195
+ with selected_mode:
196
+ for idx in ctrl_indices:
197
+ elem = self.widget_list[idx]
198
+ elem.render()
199
+ else:
200
+ with selected_mode:
201
+ for split_num in range(math.ceil(len(ctrl_indices)/self.sliders_per_row_layout)):
202
+ with gr.Row():
203
+ start = split_num*self.sliders_per_row_layout
204
+ end = min((split_num+1)*self.sliders_per_row_layout, len(ctrl_indices))
205
+ for idx in ctrl_indices[start:end]:
206
+ elem = self.widget_list[idx]
207
+ elem.render()
208
+
209
+ with gr.Accordion("Reset to default values", open=False):
210
+ gr.Examples([self.default_values], inputs=self.widget_list, label="Presets")
211
+
212
+ if self.markdown_description is not None:
213
+ with gr.Row():
214
+ gr.Markdown(self.markdown_description)
215
+ io.load(fn=self.run_fn, inputs=self.widget_list, outputs=outputs)
216
+ for idx in range(len(self.widget_list)):
217
+ self.widget_list[idx].change(
218
+ fn=self.run_fn, inputs=self.widget_list,
219
+ outputs=outputs,
220
+ show_progress="minimal"
221
+ )
222
+ self.io = io
223
+ self.io.launch(share=self.share_gradio_app)
224
+
225
+ def init_sliders(self, controls: List[Control]):
226
+ self.ctrl = {}
227
+ self.result_label = {}
228
+ self.name_label = {}
229
+ self.widget_list = []
230
+ control_factory = ControlFactory()
231
+ for ctrl in controls:
232
+ if isinstance(ctrl, Control):
233
+ slider_instance = control_factory.create_control(
234
+ ctrl, None)
235
+ control_widget = slider_instance.create()
236
+ self.widget_list.append(control_widget)
237
+ slider_name = ctrl.name
238
+ self.ctrl[slider_name] = ctrl
239
+
240
+ @staticmethod
241
+ def convert_image(out_im):
242
+ if isinstance(out_im, np.ndarray):
243
+ return (out_im.clip(0., 1.) * 255).astype(np.uint8)
244
+ else:
245
+ return out_im
246
+
247
+ def refresh(self):
248
+ if self.pipeline is not None:
249
+ self.io.launch()
250
+
251
+ def reset_sliders(self):
252
+ # Click on default examples in Gradio
253
+ pass
254
+
255
+ def add_image_placeholder(self, row, col):
256
+ ax_placeholder = None
257
+ text_label = self.get_current_style(row, col).get("title", "")
258
+ image_label = None
259
+ self.image_canvas[row][col] = {
260
+ "image": image_label, "title": text_label, "ax_placeholder": ax_placeholder}
261
+
262
+ def update_image(self, content, row, col):
263
+ pass
@@ -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.1
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.1**
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)
@@ -15,11 +15,14 @@ src/interactive_pipe/core/graph.py
15
15
  src/interactive_pipe/core/pipeline.py
16
16
  src/interactive_pipe/core/signature.py
17
17
  src/interactive_pipe/data_objects/__init__.py
18
+ src/interactive_pipe/data_objects/audio.py
18
19
  src/interactive_pipe/data_objects/curves.py
19
20
  src/interactive_pipe/data_objects/data.py
20
21
  src/interactive_pipe/data_objects/image.py
21
22
  src/interactive_pipe/data_objects/parameters.py
22
23
  src/interactive_pipe/graphical/__init__.py
24
+ src/interactive_pipe/graphical/gradio_control.py
25
+ src/interactive_pipe/graphical/gradio_gui.py
23
26
  src/interactive_pipe/graphical/gui.py
24
27
  src/interactive_pipe/graphical/mpl_control.py
25
28
  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