trojblue commited on
Commit
c12da26
·
verified ·
1 Parent(s): 4c37b75

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +90 -0
app.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ # Hugging Face Space (Gradio) for color correction:
3
+ # Takes two images: (1) image to correct, (2) reference image.
4
+ # Returns a single, color-corrected image.
5
+
6
+ import gradio as gr
7
+ from PIL import Image
8
+ import numpy as np
9
+ import cv2
10
+ from skimage import exposure
11
+
12
+
13
+ def _to_rgb_np(img: Image.Image) -> np.ndarray:
14
+ """PIL -> RGB numpy uint8"""
15
+ if img.mode != "RGB":
16
+ img = img.convert("RGB")
17
+ return np.array(img)
18
+
19
+
20
+ def _lab_histogram_match(src_rgb: np.ndarray, ref_rgb: np.ndarray) -> np.ndarray:
21
+ """
22
+ Match histogram of src to ref in LAB space and return as RGB uint8.
23
+ """
24
+ src_lab = cv2.cvtColor(src_rgb, cv2.COLOR_RGB2LAB)
25
+ ref_lab = cv2.cvtColor(ref_rgb, cv2.COLOR_RGB2LAB)
26
+
27
+ matched_lab = exposure.match_histograms(src_lab, ref_lab, channel_axis=2)
28
+ matched_lab = np.clip(matched_lab, 0, 255).astype(np.uint8)
29
+
30
+ matched_rgb = cv2.cvtColor(matched_lab, cv2.COLOR_LAB2RGB)
31
+ return matched_rgb
32
+
33
+
34
+ def _luminosity_blend(base_rgb: np.ndarray, blend_rgb: np.ndarray) -> np.ndarray:
35
+ """
36
+ Photoshop-like 'Luminosity' blend: keep hue/saturation from base,
37
+ take luminance from blend. Implemented via HLS space.
38
+ """
39
+ base_hls = cv2.cvtColor(base_rgb, cv2.COLOR_RGB2HLS)
40
+ blend_hls = cv2.cvtColor(blend_rgb, cv2.COLOR_RGB2HLS)
41
+
42
+ out_hls = base_hls.copy()
43
+ out_hls[..., 1] = blend_hls[..., 1] # replace Lightness channel
44
+
45
+ out_rgb = cv2.cvtColor(out_hls, cv2.COLOR_HLS2RGB)
46
+ return out_rgb
47
+
48
+
49
+ def color_correct(img_to_correct: Image.Image, reference_img: Image.Image) -> Image.Image:
50
+ """
51
+ Color-correct `img_to_correct` to match the look of `reference_img`.
52
+ Steps:
53
+ 1) Histogram match in LAB space.
54
+ 2) Luminosity blend to preserve original hue/saturation.
55
+ """
56
+ if img_to_correct is None or reference_img is None:
57
+ return None
58
+
59
+ src = _to_rgb_np(img_to_correct)
60
+ ref = _to_rgb_np(reference_img)
61
+
62
+ matched = _lab_histogram_match(src, ref)
63
+ result = _luminosity_blend(src, matched)
64
+
65
+ return Image.fromarray(result)
66
+
67
+
68
+ title = "Color Correction (Histogram Match + Luminosity Blend)"
69
+ description = (
70
+ "Upload the image you want to correct (left) and a reference image (right). "
71
+ "The output transfers the overall tonal feel of the reference while preserving "
72
+ "the original image's colors via a luminosity blend."
73
+ )
74
+
75
+ with gr.Blocks() as demo:
76
+ gr.Markdown(f"# {title}\n{description}")
77
+
78
+ with gr.Row():
79
+ with gr.Column():
80
+ img_a = gr.Image(type="pil", label="Image to Correct")
81
+ with gr.Column():
82
+ img_b = gr.Image(type="pil", label="Reference Image")
83
+
84
+ out = gr.Image(type="pil", label="Corrected Image")
85
+
86
+ btn = gr.Button("Run Color Correction")
87
+ btn.click(color_correct, inputs=[img_a, img_b], outputs=[out])
88
+
89
+ if __name__ == "__main__":
90
+ demo.launch()