itsgokul02 commited on
Commit
938621c
·
verified ·
1 Parent(s): c8f29f3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +164 -164
app.py CHANGED
@@ -1,164 +1,164 @@
1
- import cv2
2
- import numpy as np
3
- import gradio as gr
4
-
5
- # ================= FIXED CONFIG =================
6
- RUST_SCORE_THRESH = 0.45
7
-
8
- # GrabCut rectangle (tower prior)
9
- GC_LEFT = 0.20
10
- GC_RIGHT = 0.80
11
- GC_TOP = 0.02
12
- GC_BOTTOM = 0.98
13
-
14
- # Sky HSV bounds
15
- SKY_LOWER = (80, 20, 40)
16
- SKY_UPPER = (140, 255, 255)
17
-
18
- GROUND_FRAC = 0.15
19
- GRABCUT_ITERS = 10
20
- TOWER_MORPH_K = 5
21
- RUST_MORPH_K = 7
22
-
23
- # Rust scoring weights
24
- RUST_HUE_CENTER = 15
25
- HUE_WIDTH = 0.20
26
- W_A, W_H, W_S, W_T, W_L = 0.38, 0.22, 0.15, 0.20, 0.05
27
- # ================================================
28
-
29
-
30
- def remove_sky_mask(img):
31
- hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
32
- sky = cv2.inRange(hsv, np.array(SKY_LOWER), np.array(SKY_UPPER))
33
- return (sky == 0).astype(np.uint8)
34
-
35
-
36
- def remove_ground_mask(img):
37
- h, w = img.shape[:2]
38
- m = np.ones((h, w), np.uint8)
39
- cut = int(h * GROUND_FRAC)
40
- m[h - cut:h, :] = 0
41
- return m
42
-
43
-
44
- def grabcut_tower_mask(img, non_sky, non_ground):
45
- h, w = img.shape[:2]
46
-
47
- mask = np.full((h, w), cv2.GC_PR_BGD, np.uint8)
48
- mask[non_sky == 0] = cv2.GC_BGD
49
- mask[non_ground == 0] = cv2.GC_BGD
50
-
51
- x1, x2 = int(w * GC_LEFT), int(w * GC_RIGHT)
52
- y1, y2 = int(h * GC_TOP), int(h * GC_BOTTOM)
53
-
54
- area = mask[y1:y2, x1:x2]
55
- area[non_ground[y1:y2, x1:x2] == 1] = cv2.GC_PR_FGD
56
- mask[y1:y2, x1:x2] = area
57
-
58
- bgdModel = np.zeros((1, 65), np.float64)
59
- fgdModel = np.zeros((1, 65), np.float64)
60
-
61
- cv2.grabCut(img, mask, None, bgdModel, fgdModel, GRABCUT_ITERS, cv2.GC_INIT_WITH_MASK)
62
-
63
- fg = ((mask == cv2.GC_FGD) | (mask == cv2.GC_PR_FGD)).astype(np.uint8)
64
-
65
- k = np.ones((TOWER_MORPH_K, TOWER_MORPH_K), np.uint8)
66
- fg = cv2.morphologyEx(fg, cv2.MORPH_CLOSE, k, iterations=2)
67
- fg = cv2.morphologyEx(fg, cv2.MORPH_OPEN, k, iterations=1)
68
-
69
- return fg
70
-
71
-
72
- def rust_score_map(img):
73
- lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB).astype(np.float32)
74
- L, A = lab[:, :, 0], lab[:, :, 1]
75
-
76
- A_n = (A - A.min()) / (A.max() - A.min() + 1e-6)
77
- L_n = (L - L.min()) / (L.max() - L.min() + 1e-6)
78
-
79
- hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV).astype(np.float32)
80
- H, S = hsv[:, :, 0] / 179.0, hsv[:, :, 1] / 255.0
81
-
82
- rust_center = RUST_HUE_CENTER / 179.0
83
- hue_score = 1.0 - np.clip(np.abs(H - rust_center) / HUE_WIDTH, 0, 1)
84
-
85
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
86
- tex = np.abs(cv2.Laplacian(gray, cv2.CV_32F))
87
- tex_n = (tex - tex.min()) / (tex.max() - tex.min() + 1e-6)
88
-
89
- score = (
90
- W_A * A_n +
91
- W_H * hue_score +
92
- W_S * S +
93
- W_T * tex_n +
94
- W_L * (1.0 - np.abs(L_n - 0.55))
95
- )
96
-
97
- return np.clip(score, 0, 1)
98
-
99
-
100
- def postprocess(m):
101
- k = np.ones((RUST_MORPH_K, RUST_MORPH_K), np.uint8)
102
- m = cv2.morphologyEx(m, cv2.MORPH_CLOSE, k, iterations=2)
103
- m = cv2.morphologyEx(m, cv2.MORPH_OPEN, k, iterations=1)
104
- return m
105
-
106
-
107
- def run(img_rgb):
108
- if img_rgb is None:
109
- return None, None, None, None, "Upload an image."
110
-
111
- img = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2BGR)
112
-
113
- non_sky = remove_sky_mask(img)
114
- non_ground = remove_ground_mask(img)
115
- tower = grabcut_tower_mask(img, non_sky, non_ground)
116
-
117
- roi = tower * non_sky * non_ground
118
- score = rust_score_map(img)
119
-
120
- rust = ((score >= RUST_SCORE_THRESH).astype(np.uint8)) * roi
121
- rust = postprocess(rust)
122
-
123
- overlay = img.copy()
124
- overlay[rust == 1] = [0, 0, 255]
125
-
126
- rust_px = int(rust.sum())
127
- roi_px = int(roi.sum())
128
- pct = 100 * rust_px / max(1, roi_px)
129
-
130
- stats = (
131
- f"Rust threshold: {RUST_SCORE_THRESH}\n"
132
- f"Rust pixels: {rust_px}\n"
133
- f"ROI pixels: {roi_px}\n"
134
- f"Rust on tower ROI: {pct:.2f}%"
135
- )
136
-
137
- return (
138
- cv2.cvtColor(tower * 255, cv2.COLOR_GRAY2RGB),
139
- cv2.cvtColor(rust * 255, cv2.COLOR_GRAY2RGB),
140
- cv2.cvtColor(overlay, cv2.COLOR_BGR2RGB),
141
- cv2.applyColorMap((score * 255).astype(np.uint8), cv2.COLORMAP_TURBO),
142
- stats
143
- )
144
-
145
-
146
- with gr.Blocks(title="Tower Rust Detection") as demo:
147
- gr.Markdown("## Tower Rust Detection (Fully Automatic)\nUpload an image and click **Run**.")
148
-
149
- inp = gr.Image(type="numpy", label="Input Image")
150
- run_btn = gr.Button("Run", variant="primary")
151
-
152
- with gr.Row():
153
- out_tower = gr.Image(label="Tower Mask")
154
- out_rust = gr.Image(label="Rust Mask")
155
- with gr.Row():
156
- out_overlay = gr.Image(label="Overlay")
157
- out_heat = gr.Image(label="Rust Score Heatmap")
158
-
159
- stats = gr.Textbox(label="Stats", lines=5)
160
-
161
- run_btn.click(run, inputs=inp, outputs=[out_tower, out_rust, out_overlay, out_heat, stats])
162
-
163
- if __name__ == "__main__":
164
- demo.launch()
 
1
+ import cv2
2
+ import numpy as np
3
+ import gradio as gr
4
+
5
+ # ================= FIXED CONFIG =================
6
+ RUST_SCORE_THRESH = 0.45
7
+
8
+ # GrabCut rectangle (tower prior)
9
+ GC_LEFT = 0.20
10
+ GC_RIGHT = 0.80
11
+ GC_TOP = 0.02
12
+ GC_BOTTOM = 0.98
13
+
14
+ # Sky HSV bounds
15
+ SKY_LOWER = (80, 20, 40)
16
+ SKY_UPPER = (140, 255, 255)
17
+
18
+ GROUND_FRAC = 0.15
19
+ GRABCUT_ITERS = 10
20
+ TOWER_MORPH_K = 5
21
+ RUST_MORPH_K = 7
22
+
23
+ # Rust scoring weights
24
+ RUST_HUE_CENTER = 15
25
+ HUE_WIDTH = 0.20
26
+ W_A, W_H, W_S, W_T, W_L = 0.38, 0.22, 0.15, 0.20, 0.05
27
+ # ================================================
28
+
29
+
30
+ def remove_sky_mask(img):
31
+ hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
32
+ sky = cv2.inRange(hsv, np.array(SKY_LOWER), np.array(SKY_UPPER))
33
+ return (sky == 0).astype(np.uint8)
34
+
35
+
36
+ def remove_ground_mask(img):
37
+ h, w = img.shape[:2]
38
+ m = np.ones((h, w), np.uint8)
39
+ cut = int(h * GROUND_FRAC)
40
+ m[h - cut:h, :] = 0
41
+ return m
42
+
43
+
44
+ def grabcut_tower_mask(img, non_sky, non_ground):
45
+ h, w = img.shape[:2]
46
+
47
+ mask = np.full((h, w), cv2.GC_PR_BGD, np.uint8)
48
+ mask[non_sky == 0] = cv2.GC_BGD
49
+ mask[non_ground == 0] = cv2.GC_BGD
50
+
51
+ x1, x2 = int(w * GC_LEFT), int(w * GC_RIGHT)
52
+ y1, y2 = int(h * GC_TOP), int(h * GC_BOTTOM)
53
+
54
+ area = mask[y1:y2, x1:x2]
55
+ area[non_ground[y1:y2, x1:x2] == 1] = cv2.GC_PR_FGD
56
+ mask[y1:y2, x1:x2] = area
57
+
58
+ bgdModel = np.zeros((1, 65), np.float64)
59
+ fgdModel = np.zeros((1, 65), np.float64)
60
+
61
+ cv2.grabCut(img, mask, None, bgdModel, fgdModel, GRABCUT_ITERS, cv2.GC_INIT_WITH_MASK)
62
+
63
+ fg = ((mask == cv2.GC_FGD) | (mask == cv2.GC_PR_FGD)).astype(np.uint8)
64
+
65
+ k = np.ones((TOWER_MORPH_K, TOWER_MORPH_K), np.uint8)
66
+ fg = cv2.morphologyEx(fg, cv2.MORPH_CLOSE, k, iterations=2)
67
+ fg = cv2.morphologyEx(fg, cv2.MORPH_OPEN, k, iterations=1)
68
+
69
+ return fg
70
+
71
+
72
+ def rust_score_map(img):
73
+ lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB).astype(np.float32)
74
+ L, A = lab[:, :, 0], lab[:, :, 1]
75
+
76
+ A_n = (A - A.min()) / (A.max() - A.min() + 1e-6)
77
+ L_n = (L - L.min()) / (L.max() - L.min() + 1e-6)
78
+
79
+ hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV).astype(np.float32)
80
+ H, S = hsv[:, :, 0] / 179.0, hsv[:, :, 1] / 255.0
81
+
82
+ rust_center = RUST_HUE_CENTER / 179.0
83
+ hue_score = 1.0 - np.clip(np.abs(H - rust_center) / HUE_WIDTH, 0, 1)
84
+
85
+ gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
86
+ tex = np.abs(cv2.Laplacian(gray, cv2.CV_32F))
87
+ tex_n = (tex - tex.min()) / (tex.max() - tex.min() + 1e-6)
88
+
89
+ score = (
90
+ W_A * A_n +
91
+ W_H * hue_score +
92
+ W_S * S +
93
+ W_T * tex_n +
94
+ W_L * (1.0 - np.abs(L_n - 0.55))
95
+ )
96
+
97
+ return np.clip(score, 0, 1)
98
+
99
+
100
+ def postprocess(m):
101
+ k = np.ones((RUST_MORPH_K, RUST_MORPH_K), np.uint8)
102
+ m = cv2.morphologyEx(m, cv2.MORPH_CLOSE, k, iterations=2)
103
+ m = cv2.morphologyEx(m, cv2.MORPH_OPEN, k, iterations=1)
104
+ return m
105
+
106
+
107
+ def run(img_rgb):
108
+ if img_rgb is None:
109
+ return None, None, None, None, "Upload an image."
110
+
111
+ img = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2BGR)
112
+
113
+ non_sky = remove_sky_mask(img)
114
+ non_ground = remove_ground_mask(img)
115
+ tower = grabcut_tower_mask(img, non_sky, non_ground)
116
+
117
+ roi = tower * non_sky * non_ground
118
+ score = rust_score_map(img)
119
+
120
+ rust = ((score >= RUST_SCORE_THRESH).astype(np.uint8)) * roi
121
+ rust = postprocess(rust)
122
+
123
+ overlay = img.copy()
124
+ overlay[rust == 1] = [0, 0, 255]
125
+
126
+ rust_px = int(rust.sum())
127
+ roi_px = int(roi.sum())
128
+ pct = 100 * rust_px / max(1, roi_px)
129
+
130
+ stats = (
131
+ f"Rust threshold: {RUST_SCORE_THRESH}\n"
132
+ f"Rust pixels: {rust_px}\n"
133
+ f"ROI pixels: {roi_px}\n"
134
+ f"Rust on tower ROI: {pct:.2f}%"
135
+ )
136
+
137
+ return (
138
+ cv2.cvtColor(tower * 255, cv2.COLOR_GRAY2RGB),
139
+ cv2.cvtColor(rust * 255, cv2.COLOR_GRAY2RGB),
140
+ cv2.cvtColor(overlay, cv2.COLOR_BGR2RGB),
141
+ cv2.applyColorMap((score * 255).astype(np.uint8), cv2.COLORMAP_TURBO),
142
+ stats
143
+ )
144
+
145
+
146
+ with gr.Blocks(title="Tower Rust Detection") as demo:
147
+ gr.Markdown("## Tower Rust Detection \nUpload an image and click **Run**.")
148
+
149
+ inp = gr.Image(type="numpy", label="Input Image")
150
+ run_btn = gr.Button("Run", variant="primary")
151
+
152
+ with gr.Row():
153
+ out_tower = gr.Image(label="Tower Mask")
154
+ out_rust = gr.Image(label="Rust Mask")
155
+ with gr.Row():
156
+ out_overlay = gr.Image(label="Overlay")
157
+ out_heat = gr.Image(label="Rust Score Heatmap")
158
+
159
+ stats = gr.Textbox(label="Stats", lines=5)
160
+
161
+ run_btn.click(run, inputs=inp, outputs=[out_tower, out_rust, out_overlay, out_heat, stats])
162
+
163
+ if __name__ == "__main__":
164
+ demo.launch()