balthou commited on
Commit
4f6789c
Β·
1 Parent(s): 2815cec

split tutorial into several files

Browse files
Files changed (4) hide show
  1. app.py +13 -63
  2. interactivity.py +32 -0
  3. library.py +58 -0
  4. tutorial.md +55 -0
app.py CHANGED
@@ -1,59 +1,6 @@
1
- from interactive_pipe import interactive_pipeline, interactive
2
- from interactive_pipe import Curve, SingleCurve
3
  import argparse
4
- import numpy as np
5
-
6
-
7
- @interactive(frequency=(80, [1, 100]), isotropy=(0.8, [0.1, 1.]))
8
- def gen_color(frequency=0, isotropy=0.):
9
- lin_coord = np.linspace(0, 1., 256)
10
- X, Y = np.meshgrid(lin_coord, isotropy*lin_coord)
11
- radius = 0.5+0.5*np.cos(frequency*np.sqrt(X**2 + Y**2))
12
- return np.stack([np.abs(X), np.abs(Y), radius], axis=-1).clip(0, 1)
13
-
14
-
15
- @interactive(effect=("flip", ["flip", "mirror", "flip+mirror", "identity"]))
16
- def modify_geometry(img, effect="flip"):
17
- img = img[::-1] if "flip" in effect else img
18
- img = img[:, ::-1] if "mirror" in effect else img
19
- return img
20
-
21
-
22
- @interactive(bnw=(True, "Black and White"))
23
- def change_color(img, bnw=True):
24
- if bnw:
25
- return np.mean(img, axis=-1, keepdims=True).repeat(3, axis=-1)
26
- return img
27
-
28
-
29
- @interactive(ratio=(0.5, [0., 1.], "Side by Side comparison"))
30
- def split(img_1, img_2, ratio=0.5):
31
- out = np.zeros_like(img_1)
32
- split = int(ratio*img_1.shape[1])
33
- out[:, :split] = img_2[:, :split]
34
- out[:, split+5:] = img_1[:, split+5:]
35
- return out
36
-
37
-
38
- def profile(img):
39
- luma = img.mean(axis=-1)
40
- h_profile = SingleCurve(y=luma[0, :], label="H profile")
41
- v_profile = SingleCurve(y=luma[:, 0], label="V profile")
42
- return Curve(
43
- [h_profile, v_profile],
44
- xlabel="Position", ylabel="Luminance",
45
- grid=True
46
- )
47
-
48
-
49
- def tutorial_pipeline():
50
- inp = gen_color()
51
- out_geometry = modify_geometry(inp)
52
- out_bnw = change_color(inp)
53
- out_image = split(out_geometry, out_bnw)
54
- out_profile = profile(out_image)
55
- return [[inp, out_geometry], [out_profile, out_image]]
56
-
57
 
58
  if __name__ == "__main__":
59
  BACKEND_OPTIONS = ["gradio", "qt"]
@@ -61,11 +8,14 @@ if __name__ == "__main__":
61
  parser.add_argument("-b", "--backend", type=str,
62
  choices=BACKEND_OPTIONS, default=BACKEND_OPTIONS[0])
63
  args = parser.parse_args()
64
- markdown_description = "# Source code \n"
65
- markdown_description += "```python\n"+open(__file__, 'r').read()+"```"
66
- playable_tutorial_pipeline = interactive_pipeline(
67
- gui=args.backend,
68
- cache=True,
69
- markdown_description=markdown_description
70
- )(tutorial_pipeline)
71
- playable_tutorial_pipeline()
 
 
 
 
1
+ # Interactive code
 
2
  import argparse
3
+ from interactivity import run_interactive_pipeline
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
  if __name__ == "__main__":
6
  BACKEND_OPTIONS = ["gradio", "qt"]
 
8
  parser.add_argument("-b", "--backend", type=str,
9
  choices=BACKEND_OPTIONS, default=BACKEND_OPTIONS[0])
10
  args = parser.parse_args()
11
+ backend = args.backend
12
+ extra_markdown = open("tutorial.md", 'r').read()
13
+ markdown_description = "# πŸ” READ TUTORIAL HERE \n"
14
+ markdown_description += "# Source code for this tutorial \n"
15
+ markdown_description += "## Processing blocks & pipeline (~ production code, no interactivity) \n"
16
+ markdown_description += "```python\n"+open("library.py", 'r').read()+"```\n"
17
+ markdown_description += "## Add interactivity \n"
18
+ markdown_description += "```python\n"+open("interactivity.py", 'r').read()+"```\n"
19
+ markdown_description += "\n"+extra_markdown
20
+ run_interactive_pipeline(
21
+ backend=backend, markdown_description=markdown_description)
interactivity.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from interactive_pipe import interactive_pipeline, interactive
2
+ from library import (gen_color, modify_geometry, change_color,
3
+ compare_by_splitting, tutorial_pipeline)
4
+ # --------------------------------------------------------------
5
+
6
+
7
+ def add_interactivity():
8
+ # Depending on the level of control you want,
9
+ # you can add more or less controls to the pipeline
10
+ interactive(
11
+ ratio=(0.5, [0., 1.], "Side by Side comparison")
12
+ )(compare_by_splitting)
13
+ interactive(
14
+ bnw=(True, "Black and White")
15
+ )(change_color)
16
+ interactive(
17
+ effect=("flip", ["flip", "mirror", "flip+mirror", "identity"])
18
+ )(modify_geometry)
19
+ interactive(
20
+ frequency=(80, [1, 100]),
21
+ isotropy=(0.8, [0.1, 1.])
22
+ )(gen_color)
23
+
24
+
25
+ def run_interactive_pipeline(backend="gradio", markdown_description="# Tutorial"):
26
+ add_interactivity()
27
+ playable_tutorial_pipeline = interactive_pipeline(
28
+ gui=backend,
29
+ cache=True,
30
+ markdown_description=markdown_description
31
+ )(tutorial_pipeline)
32
+ playable_tutorial_pipeline()
library.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # "Production code"
2
+ import numpy as np
3
+ from interactive_pipe import Curve, SingleCurve
4
+
5
+ # -----------------
6
+ # Processing blocks
7
+ # -----------------
8
+
9
+
10
+ def gen_color(frequency=0, isotropy=0.):
11
+ lin_coord = np.linspace(0, 1., 256)
12
+ X, Y = np.meshgrid(lin_coord, isotropy*lin_coord)
13
+ radius = 0.5+0.5*np.cos(frequency*np.sqrt(X**2 + Y**2))
14
+ return np.stack([np.abs(X), np.abs(Y), radius], axis=-1).clip(0, 1)
15
+
16
+
17
+ def modify_geometry(img, effect="flip"):
18
+ img = img[::-1] if "flip" in effect else img
19
+ img = img[:, ::-1] if "mirror" in effect else img
20
+ return img
21
+
22
+
23
+ def change_color(img, bnw=True):
24
+ if bnw:
25
+ return np.mean(img, axis=-1, keepdims=True).repeat(3, axis=-1)
26
+ return img
27
+
28
+
29
+ def compare_by_splitting(img_1, img_2, ratio=0.5):
30
+ out = np.zeros_like(img_1)
31
+ split = int(ratio*img_1.shape[1])
32
+ out[:, :split] = img_2[:, :split]
33
+ out[:, split+5:] = img_1[:, split+5:]
34
+ return out
35
+
36
+
37
+ def extract_profile(img):
38
+ luma = img.mean(axis=-1)
39
+ h_profile = SingleCurve(y=luma[0, :], label="H profile")
40
+ v_profile = SingleCurve(y=luma[:, 0], label="V profile")
41
+ return Curve(
42
+ [h_profile, v_profile],
43
+ xlabel="Position", ylabel="Luminance",
44
+ grid=True
45
+ )
46
+
47
+ # -------------------
48
+ # Pipeline definition
49
+ # -------------------
50
+
51
+
52
+ def tutorial_pipeline():
53
+ inp = gen_color()
54
+ out_geometry = modify_geometry(inp)
55
+ out_bnw = change_color(inp)
56
+ out_image = compare_by_splitting(out_geometry, out_bnw)
57
+ out_profile = extract_profile(out_image)
58
+ return [[inp, out_geometry], [out_profile, out_image]]
tutorial.md ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Tutorial
2
+
3
+ ## Keep separation between "production code" (library / not interactive) & interactivity
4
+ - πŸ’‘ One of the strength of interactive pipe is to avoid adding hundreds of lines of code dedicated to GUI (graphical user interfaces).
5
+ - With interactive pipe, you have the choice to keep this design choice. Each processing block can be defined as a regular function, without even importing the `interactive` decorator. In a separate file, you'll add sliders.
6
+
7
+ ### Several ways to decorate building blocks
8
+
9
+
10
+ #### 1.Decorate afterward πŸ† *= Recommended approach*
11
+ - βž– Less elegant to read (`add_interactivity` may be in a different file)
12
+ - βž• The decorated function can't be re-used somewhere else.
13
+ - βž• Possibility to add conditions (`debug` flag)
14
+
15
+ ```python
16
+ def gen_color(frequency=0, isotropy=0.):
17
+ ...
18
+
19
+
20
+ def add_interactivity(debug=True):
21
+ interactive(
22
+ frequency=(80, [1, 100]),
23
+ isotropy=(0.8, [0.1, 1.]) if debug else 0.8
24
+ )(gen_color)
25
+ ```
26
+
27
+
28
+ #### 2.Decorate using `@`
29
+
30
+
31
+ ```python
32
+ @interactive(
33
+ frequency=(80, [1, 100]),
34
+ isotropy=(0.8, [0.1, 1.])
35
+ )
36
+ def gen_color(frequency=0, isotropy=0.):
37
+ ...
38
+ ```
39
+ - βž• Easy to read
40
+ - βž– The decorated function can't be re-used somewhere else.
41
+ - βž– No possibility to add condition to hide/show slider. To hide the slider, you need to comment!
42
+
43
+
44
+ #### 3. Shorter code using `@`
45
+
46
+ ```python
47
+ @interactive()
48
+ def gen_color(
49
+ frequency=(80, [1, 100]),
50
+ isotropy=(0.8, [0.1, 1.])
51
+ ):
52
+ ```
53
+
54
+ - βž• Shortest code
55
+ - βž– The decorated function can't be re-used somewhere else