Cuervo-x commited on
Commit
6de2332
·
verified ·
1 Parent(s): 166fa2b

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +114 -0
app.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import cv2
3
+ import gradio as gr
4
+ from skimage.morphology import convex_hull_image
5
+
6
+ # =========================================================
7
+ # Utility Functions
8
+ # =========================================================
9
+
10
+ def orient_to_portrait(img):
11
+ h, w = img.shape[:2]
12
+ if w > h:
13
+ img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
14
+ return img
15
+
16
+ def analyze_cv_only(image, threshold_pct, min_defect_size):
17
+ """
18
+ Simulates the ML pipeline using traditional image processing.
19
+ """
20
+ if image is None:
21
+ return None, "0.0%", "0.0%", None, None
22
+
23
+ # 1. Preprocessing
24
+ img_color = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
25
+ img_color = orient_to_portrait(img_color)
26
+ gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
27
+ blurred = cv2.GaussianBlur(gray, (5, 5), 0)
28
+
29
+ # 2. Simulate Print Segmentation (Thresholding)
30
+ # Instead of a model, we use simple binary thresholding
31
+ val = int((threshold_pct / 100.0) * 255)
32
+ _, print_mask = cv2.threshold(blurred, val, 255, cv2.THRESH_BINARY_INV)
33
+
34
+ # Find largest contour to represent the print
35
+ contours, _ = cv2.findContours(print_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
36
+ if not contours:
37
+ return image, "0.0%", "0.0%", None, None
38
+
39
+ largest_cnt = max(contours, key=cv2.contourArea)
40
+ print_mask_clean = np.zeros_like(print_mask)
41
+ cv2.drawContours(print_mask_clean, [largest_cnt], -1, 255, thickness=-1)
42
+
43
+ # 3. Simulate Defect Detection (Edge Detection within the print)
44
+ # Detects high-contrast areas (cracks/voids) inside the print mask
45
+ edges = cv2.Canny(blurred, 50, 150)
46
+ defect_mask = cv2.bitwise_and(edges, print_mask_clean)
47
+
48
+ # Filter defects by size
49
+ final_defect_mask = np.zeros_like(defect_mask)
50
+ def_cnts, _ = cv2.findContours(defect_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
51
+ for cnt in def_cnts:
52
+ if cv2.contourArea(cnt) >= min_defect_size:
53
+ cv2.drawContours(final_defect_mask, [cnt], -1, 255, thickness=-1)
54
+
55
+ # 4. Metrics
56
+ # Integrity: Ratio of print to its convex hull
57
+ try:
58
+ hull = convex_hull_image(print_mask_clean > 0)
59
+ integrity_score = np.sum(print_mask_clean > 0) / np.sum(hull)
60
+ except:
61
+ integrity_score = 0.0
62
+
63
+ # Quality: Inverse of defect area
64
+ print_area = np.sum(print_mask_clean > 0)
65
+ defect_area = np.sum(final_defect_mask > 0)
66
+ quality_score = 100.0 - ((defect_area / print_area) * 100.0) if print_area > 0 else 0.0
67
+
68
+ # 5. Visualization
69
+ vis = img_color.copy()
70
+ cv2.drawContours(vis, [largest_cnt], -1, (255, 0, 0), 2) # Blue outline
71
+ cv2.drawContours(vis, [cv2.convexHull(largest_cnt)], -1, (0, 0, 255), 2) # Red hull
72
+
73
+ # Draw defects in green
74
+ vis[final_defect_mask > 0] = [0, 255, 0]
75
+
76
+ # Save outputs
77
+ mask_path = "combined_mask.png"
78
+ cv2.imwrite(mask_path, final_defect_mask)
79
+ vis_path = "analysis_output.png"
80
+ cv2.imwrite(vis_path, vis)
81
+
82
+ return cv2.cvtColor(vis, cv2.COLOR_BGR2RGB), f"{integrity_score*100:.1f}%", f"{quality_score:.1f}%", vis_path, mask_path
83
+
84
+ # =========================================================
85
+ # UI Layout
86
+ # =========================================================
87
+ custom_css = """
88
+ .score-box { background-color: #f8f9fa; border-radius: 10px; padding: 15px; text-align: center; }
89
+ .score-value { font-size: 2rem !important; font-weight: 700 !important; color: #2b6cb0 !important; }
90
+ """
91
+
92
+ with gr.Blocks(css=custom_css) as app:
93
+ gr.Markdown("# CV-Only Print Analysis (No ML)")
94
+
95
+ with gr.Row():
96
+ with gr.Column():
97
+ img_input = gr.Image(type="numpy", label="Input Image")
98
+ thresh_slider = gr.Slider(50, 255, value=127, label="Brightness Threshold")
99
+ size_slider = gr.Slider(0, 500, value=20, label="Min Defect Size")
100
+ run_btn = gr.Button("Analyze", variant="primary")
101
+
102
+ with gr.Column():
103
+ img_output = gr.Image(label="Analysis Result")
104
+ with gr.Row():
105
+ area_out = gr.Markdown("0.0%", elem_classes=["score-value"])
106
+ surface_out = gr.Markdown("0.0%", elem_classes=["score-value"])
107
+
108
+ run_btn.click(
109
+ fn=analyze_cv_only,
110
+ inputs=[img_input, thresh_slider, size_slider],
111
+ outputs=[img_output, area_out, surface_out]
112
+ )
113
+
114
+ app.queue().launch(server_name="0.0.0.0", server_port=7860, ssr_mode=False)