balthou commited on
Commit
f67bbda
·
1 Parent(s): 365143f

add basic image editing pipeline with tone mapping

Browse files
Files changed (4) hide show
  1. app.py +71 -0
  2. global_tone_mapping.py +44 -0
  3. image_sample.png +0 -0
  4. requirements.txt +1 -0
app.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from interactive_pipe import interactive_pipeline, interactive
2
+ from interactive_pipe.data_objects.curves import SingleCurve, Curve
3
+ from interactive_pipe.data_objects.image import Image
4
+ from global_tone_mapping import apply_s_curve_tone_mapping
5
+ import numpy as np
6
+
7
+
8
+ def histogram(img: np.ndarray) -> Curve:
9
+ hist_curves = []
10
+ for ch in range(img.shape[-1]):
11
+ hist, bins = np.histogram(
12
+ img[..., ch].flatten(), bins=128, range=(0, 1))
13
+ hist_curves.append(SingleCurve(bins[:-1], hist, style='rgb'[ch]+"-"))
14
+ hist_curve = Curve(hist_curves,
15
+ xlabel="Intensity", ylabel="Frequency")
16
+ return hist_curve
17
+
18
+
19
+ @interactive()
20
+ def set_tone_mapping_params(
21
+ shadow_boost: float = (0., [-1., 1.]),
22
+ highlight_boost: float = (0., [-1., 1.]),
23
+ exposure: float = (0., [-1., 1.]),
24
+ global_params: dict = {}
25
+ ) -> None:
26
+ global_params["shadow_boost"] = shadow_boost
27
+ global_params["highlight_boost"] = highlight_boost
28
+ global_params["exposure"] = exposure
29
+
30
+
31
+ def s_curve_tone_mapping(img: np.ndarray, global_params={}) -> np.ndarray:
32
+ exposure = global_params.get("exposure", 0.)
33
+ shadow_boost = global_params.get("shadow_boost", 0.)
34
+ highlight_boost = global_params.get("highlight_boost", 0.)
35
+ return apply_s_curve_tone_mapping(
36
+ img,
37
+ shadow_boost,
38
+ highlight_boost,
39
+ exposure
40
+ )
41
+
42
+
43
+ def s_curve_visualization(global_params={}) -> Curve:
44
+ exposure = global_params.get("exposure", 0.)
45
+ shadow_boost = global_params.get("shadow_boost", 0.)
46
+ highlight_boost = global_params.get("highlight_boost", 0.)
47
+ x = np.linspace(0, 1, 256)
48
+ y = apply_s_curve_tone_mapping(x, shadow_boost,
49
+ highlight_boost,
50
+ exposure)
51
+ return Curve(
52
+ [
53
+ SingleCurve(x, y, style='m-'),
54
+ SingleCurve(x, x, style='k--'),
55
+ ],
56
+ xlabel="Input", ylabel="Output"
57
+ )
58
+
59
+
60
+ @ interactive_pipeline(gui="gradio")
61
+ def image_editing_pipeline(input_image):
62
+ set_tone_mapping_params()
63
+ tc_image = s_curve_tone_mapping(input_image)
64
+ tone_curve = s_curve_visualization()
65
+ histogram_curve = histogram(tc_image)
66
+ return tc_image, histogram_curve, tone_curve
67
+
68
+
69
+ if __name__ == "__main__":
70
+ img = Image.load_image("image_sample.png")
71
+ image_editing_pipeline(img)
global_tone_mapping.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+
4
+ def apply_s_curve_tone_mapping(
5
+ x: np.ndarray,
6
+ shadow_boost: float = 0.,
7
+ highlight_boost: float = 0.,
8
+ exposure: float = 0.,
9
+ ) -> np.ndarray:
10
+ """
11
+ Apply an S-curve tone mapping to input x with given parameters.
12
+
13
+ Parameters:
14
+ x : array-like
15
+ Input values in the range [0, 1].
16
+ shadow_boost : float
17
+ Shadow boost parameter (tangent).
18
+ Positive values decreases the steepness in shadows.
19
+ highlight_boost : float
20
+ Highlight boost parameter (tangent).
21
+ Positive values increase the steepness in highlights.
22
+ exposure : float
23
+ Exposure adjustment parameter. When exposure=0, 0.5 maps to 0.5.
24
+
25
+ Returns:
26
+ y : array-like
27
+ Tone-mapped output values in the range [0, 1].
28
+ """
29
+ x_expo = np.clip(x * 2 ** exposure, 0, 1)
30
+
31
+ # Adjust s and h parameters
32
+ s = 1 - shadow_boost
33
+ h = 1 + highlight_boost
34
+
35
+ # Compute numerator and denominator for the S-curve formula
36
+ numerator = x_expo ** s
37
+ denominator = numerator + (1 - x_expo) ** h
38
+
39
+ # Avoid division by zero
40
+ with np.errstate(divide='ignore', invalid='ignore'):
41
+ y = numerator / denominator
42
+ y = np.nan_to_num(y)
43
+
44
+ return y
image_sample.png ADDED
requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ interactive-pipe