ZENLLC commited on
Commit
75b4a12
·
verified ·
1 Parent(s): fc232c8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +67 -43
app.py CHANGED
@@ -5,7 +5,7 @@ import gradio as gr
5
 
6
  def classify_pipe_material(image_np):
7
  """
8
- Heuristic to classify the overall pipe material based on brightness.
9
  Brighter images (mean intensity > 130) are assumed to be Plastic; otherwise, Metal.
10
  """
11
  gray = cv2.cvtColor(image_np, cv2.COLOR_RGB2GRAY)
@@ -14,36 +14,62 @@ def classify_pipe_material(image_np):
14
 
15
  def detect_rust(roi):
16
  """
17
- Detect rust in the region of interest (ROI) by analyzing the HSV color space.
18
- Rust typically has reddish-brown hues.
19
  """
20
- # Convert ROI to HSV color space
21
  hsv_roi = cv2.cvtColor(roi, cv2.COLOR_RGB2HSV)
22
- # Define rust color range in HSV (tweak these values as needed)
23
  lower_rust = np.array([5, 50, 50])
24
  upper_rust = np.array([25, 255, 255])
25
  mask = cv2.inRange(hsv_roi, lower_rust, upper_rust)
26
  rust_ratio = np.count_nonzero(mask) / float(roi.shape[0] * roi.shape[1])
27
  return rust_ratio
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  def classify_defect(roi):
30
  """
31
- Classify the defect type using both geometric/texture heuristics and color analysis.
32
- The function returns one of:
33
- - "Rust" (if a significant fraction of the region has rust-like colors)
34
- - "Crack" (if the ROI is small, long, and has high intensity variation)
35
- - "Corrosion" (if the ROI is larger with moderate texture variation)
36
- - "Other Defect" (fallback category)
37
  """
38
  area = roi.shape[0] * roi.shape[1]
39
  std_intensity = np.std(roi)
40
 
41
- # Check for rust first
42
  rust_ratio = detect_rust(roi)
43
- if rust_ratio > 0.3:
 
 
 
 
44
  return "Rust"
 
 
 
 
45
 
46
- # Use area and intensity variation to distinguish other defects.
47
  if area < 5000 and std_intensity > 50:
48
  return "Crack"
49
  elif area >= 5000 and std_intensity > 40:
@@ -51,25 +77,23 @@ def classify_defect(roi):
51
  else:
52
  return "Other Defect"
53
 
54
- def detect_pipe_issues(image: Image.Image):
55
  try:
56
- # Convert PIL image to a NumPy array (RGB)
57
  image_np = np.array(image)
58
- annotated = image.copy() # Copy for annotation
59
  draw = ImageDraw.Draw(annotated)
60
 
61
- # Classify overall pipe material
62
- pipe_material = classify_pipe_material(image_np)
63
 
64
- # Preprocessing: convert to grayscale and enhance contrast with CLAHE
65
  gray = cv2.cvtColor(image_np, cv2.COLOR_RGB2GRAY)
66
  clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
67
  enhanced = clahe.apply(gray)
68
-
69
- # Apply Gaussian blur to reduce noise
70
  blurred = cv2.GaussianBlur(enhanced, (5, 5), 0)
71
 
72
- # Adaptive thresholding to highlight potential defect areas
73
  thresh = cv2.adaptiveThreshold(
74
  blurred, 255,
75
  cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
@@ -77,31 +101,31 @@ def detect_pipe_issues(image: Image.Image):
77
  11, 2
78
  )
79
 
80
- # Morphological closing to connect fragmented regions
81
  kernel = np.ones((3, 3), np.uint8)
82
  morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)
83
 
84
- # Edge detection
85
  edges = cv2.Canny(morph, 50, 150)
86
 
87
- # Find contours corresponding to potential defects
88
  contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
89
  detections = []
90
 
91
- # Define colors for different defect types
92
  colors = {
93
  "Rust": "orange",
 
 
94
  "Crack": "red",
95
- "Corrosion": "blue",
96
- "Other Defect": "green"
97
  }
98
 
99
  for cnt in contours:
100
- # Filter out small contours to ignore noise
101
- if cv2.contourArea(cnt) < 100:
102
  continue
103
  x, y, w, h = cv2.boundingRect(cnt)
104
- # Extract ROI from the original image
105
  roi = image_np[y:y+h, x:x+w]
106
  if roi.size == 0:
107
  continue
@@ -109,16 +133,16 @@ def detect_pipe_issues(image: Image.Image):
109
  detection_info = f"{defect_type} at ({x}, {y}, {w}, {h})"
110
  detections.append(detection_info)
111
 
112
- # Draw bounding box with corresponding color and label
113
- box_color = colors.get(defect_type, "green")
114
  draw.rectangle([x, y, x+w, y+h], outline=box_color, width=2)
115
  draw.text((x, y-10), defect_type, fill=box_color)
116
 
117
- # Create a summary including pipe material and detected defects
118
  if detections:
119
- summary = f"Pipe Material: {pipe_material}\nDetected Issues:\n" + "\n".join(detections)
120
  else:
121
- summary = f"Pipe Material: {pipe_material}\nNo significant defects detected."
122
 
123
  return annotated, summary
124
  except Exception as e:
@@ -126,14 +150,14 @@ def detect_pipe_issues(image: Image.Image):
126
  return image, f"Error: {e}"
127
 
128
  iface = gr.Interface(
129
- fn=detect_pipe_issues,
130
- inputs=gr.Image(type="pil", label="Upload a Pipe Image"),
131
  outputs=[gr.Image(label="Annotated Image"), gr.Textbox(label="Detection Summary")],
132
- title="Pipe Defect Detector",
133
  description=(
134
- "Upload an image of a pipe to detect granular issues such as cracks, corrosion, rust, "
135
- "and other defects. The app classifies the defect type and displays a colored bounding box for each class. "
136
- "Pipe material (Plastic or Metal) is also identified."
137
  )
138
  )
139
 
 
5
 
6
  def classify_pipe_material(image_np):
7
  """
8
+ Classify overall material based on image brightness.
9
  Brighter images (mean intensity > 130) are assumed to be Plastic; otherwise, Metal.
10
  """
11
  gray = cv2.cvtColor(image_np, cv2.COLOR_RGB2GRAY)
 
14
 
15
  def detect_rust(roi):
16
  """
17
+ Detect rust by checking for reddish-brown hues in the ROI.
 
18
  """
 
19
  hsv_roi = cv2.cvtColor(roi, cv2.COLOR_RGB2HSV)
 
20
  lower_rust = np.array([5, 50, 50])
21
  upper_rust = np.array([25, 255, 255])
22
  mask = cv2.inRange(hsv_roi, lower_rust, upper_rust)
23
  rust_ratio = np.count_nonzero(mask) / float(roi.shape[0] * roi.shape[1])
24
  return rust_ratio
25
 
26
+ def detect_mold(roi):
27
+ """
28
+ Detect mold by looking for greenish hues, which may indicate fungal growth.
29
+ """
30
+ hsv_roi = cv2.cvtColor(roi, cv2.COLOR_RGB2HSV)
31
+ lower_mold = np.array([35, 50, 20])
32
+ upper_mold = np.array([85, 255, 120])
33
+ mask = cv2.inRange(hsv_roi, lower_mold, upper_mold)
34
+ mold_ratio = np.count_nonzero(mask) / float(roi.shape[0] * roi.shape[1])
35
+ return mold_ratio
36
+
37
+ def detect_water_damage(roi):
38
+ """
39
+ Detect water damage by checking for discoloration typical of stains (dark brownish-yellow).
40
+ """
41
+ hsv_roi = cv2.cvtColor(roi, cv2.COLOR_RGB2HSV)
42
+ lower_water = np.array([5, 50, 50])
43
+ upper_water = np.array([20, 200, 150])
44
+ mask = cv2.inRange(hsv_roi, lower_water, upper_water)
45
+ water_ratio = np.count_nonzero(mask) / float(roi.shape[0] * roi.shape[1])
46
+ return water_ratio
47
+
48
  def classify_defect(roi):
49
  """
50
+ Classify the defect using a combination of color and texture heuristics.
51
+ Priority is given to color cues:
52
+ - "Rust": reddish-brown
53
+ - "Mold": greenish
54
+ - "Water Damage": discoloration from water stains
55
+ Then geometric/texture analysis is used to differentiate "Crack" and "Corrosion."
56
  """
57
  area = roi.shape[0] * roi.shape[1]
58
  std_intensity = np.std(roi)
59
 
 
60
  rust_ratio = detect_rust(roi)
61
+ mold_ratio = detect_mold(roi)
62
+ water_ratio = detect_water_damage(roi)
63
+
64
+ # Check for color-based defects first.
65
+ if rust_ratio > 0.25:
66
  return "Rust"
67
+ elif mold_ratio > 0.2:
68
+ return "Mold"
69
+ elif water_ratio > 0.2:
70
+ return "Water Damage"
71
 
72
+ # Then use size and intensity variation for structural defects.
73
  if area < 5000 and std_intensity > 50:
74
  return "Crack"
75
  elif area >= 5000 and std_intensity > 40:
 
77
  else:
78
  return "Other Defect"
79
 
80
+ def detect_infrastructure_issues(image: Image.Image):
81
  try:
82
+ # Convert the PIL image to a NumPy array (RGB)
83
  image_np = np.array(image)
84
+ annotated = image.copy() # For drawing annotations
85
  draw = ImageDraw.Draw(annotated)
86
 
87
+ # Classify the overall pipe (or structure) material
88
+ overall_material = classify_pipe_material(image_np)
89
 
90
+ # Enhance image for defect detection:
91
  gray = cv2.cvtColor(image_np, cv2.COLOR_RGB2GRAY)
92
  clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
93
  enhanced = clahe.apply(gray)
 
 
94
  blurred = cv2.GaussianBlur(enhanced, (5, 5), 0)
95
 
96
+ # Adaptive thresholding highlights potential defect areas
97
  thresh = cv2.adaptiveThreshold(
98
  blurred, 255,
99
  cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
 
101
  11, 2
102
  )
103
 
104
+ # Morphological closing to consolidate defect regions
105
  kernel = np.ones((3, 3), np.uint8)
106
  morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)
107
 
108
+ # Edge detection to identify defect boundaries
109
  edges = cv2.Canny(morph, 50, 150)
110
 
111
+ # Extract contours as candidate defect regions
112
  contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
113
  detections = []
114
 
115
+ # Define distinct colors for each defect type
116
  colors = {
117
  "Rust": "orange",
118
+ "Mold": "purple",
119
+ "Water Damage": "blue",
120
  "Crack": "red",
121
+ "Corrosion": "cyan",
122
+ "Other Defect": "gray"
123
  }
124
 
125
  for cnt in contours:
126
+ if cv2.contourArea(cnt) < 100: # Filter out noise
 
127
  continue
128
  x, y, w, h = cv2.boundingRect(cnt)
 
129
  roi = image_np[y:y+h, x:x+w]
130
  if roi.size == 0:
131
  continue
 
133
  detection_info = f"{defect_type} at ({x}, {y}, {w}, {h})"
134
  detections.append(detection_info)
135
 
136
+ # Draw bounding box with defect-specific color
137
+ box_color = colors.get(defect_type, "gray")
138
  draw.rectangle([x, y, x+w, y+h], outline=box_color, width=2)
139
  draw.text((x, y-10), defect_type, fill=box_color)
140
 
141
+ # Create a textual summary
142
  if detections:
143
+ summary = f"Overall Material: {overall_material}\nDetected Issues:\n" + "\n".join(detections)
144
  else:
145
+ summary = f"Overall Material: {overall_material}\nNo significant defects detected."
146
 
147
  return annotated, summary
148
  except Exception as e:
 
150
  return image, f"Error: {e}"
151
 
152
  iface = gr.Interface(
153
+ fn=detect_infrastructure_issues,
154
+ inputs=gr.Image(type="pil", label="Upload an Infrastructure Image"),
155
  outputs=[gr.Image(label="Annotated Image"), gr.Textbox(label="Detection Summary")],
156
+ title="Comprehensive Home Infrastructure Defect Detector",
157
  description=(
158
+ "Upload an image of a pipe or any home infrastructure (walls, floors, etc.) to detect defects. "
159
+ "This tool identifies issues such as Rust (orange), Mold (purple), Water Damage (blue), Cracks (red), "
160
+ "and Corrosion (cyan), and returns both an annotated image and a detailed summary."
161
  )
162
  )
163