File size: 5,331 Bytes
c436e12 72d2178 c436e12 5cf1972 72d2178 fc232c8 72d2178 fc232c8 72d2178 fc232c8 72d2178 fc232c8 72d2178 5cf1972 fc232c8 72d2178 9444004 c436e12 fc232c8 72d2178 fc232c8 72d2178 c436e12 9444004 72d2178 c436e12 72d2178 c436e12 fc232c8 c436e12 fc232c8 c436e12 fc232c8 c436e12 72d2178 c436e12 fc232c8 c436e12 72d2178 fc232c8 72d2178 fc232c8 9444004 fc232c8 9444004 72d2178 9444004 72d2178 9444004 5cf1972 9444004 5cf1972 72d2178 9444004 72d2178 c436e12 fc232c8 c436e12 5cf1972 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
import cv2
import numpy as np
from PIL import Image, ImageDraw
import gradio as gr
def classify_pipe_material(image_np):
"""
Heuristic to classify the overall pipe material based on brightness.
Brighter images (mean intensity > 130) are assumed to be Plastic; otherwise, Metal.
"""
gray = cv2.cvtColor(image_np, cv2.COLOR_RGB2GRAY)
mean_intensity = np.mean(gray)
return "Plastic" if mean_intensity > 130 else "Metal"
def detect_rust(roi):
"""
Detect rust in the region of interest (ROI) by analyzing the HSV color space.
Rust typically has reddish-brown hues.
"""
# Convert ROI to HSV color space
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_RGB2HSV)
# Define rust color range in HSV (tweak these values as needed)
lower_rust = np.array([5, 50, 50])
upper_rust = np.array([25, 255, 255])
mask = cv2.inRange(hsv_roi, lower_rust, upper_rust)
rust_ratio = np.count_nonzero(mask) / float(roi.shape[0] * roi.shape[1])
return rust_ratio
def classify_defect(roi):
"""
Classify the defect type using both geometric/texture heuristics and color analysis.
The function returns one of:
- "Rust" (if a significant fraction of the region has rust-like colors)
- "Crack" (if the ROI is small, long, and has high intensity variation)
- "Corrosion" (if the ROI is larger with moderate texture variation)
- "Other Defect" (fallback category)
"""
area = roi.shape[0] * roi.shape[1]
std_intensity = np.std(roi)
# Check for rust first
rust_ratio = detect_rust(roi)
if rust_ratio > 0.3:
return "Rust"
# Use area and intensity variation to distinguish other defects.
if area < 5000 and std_intensity > 50:
return "Crack"
elif area >= 5000 and std_intensity > 40:
return "Corrosion"
else:
return "Other Defect"
def detect_pipe_issues(image: Image.Image):
try:
# Convert PIL image to a NumPy array (RGB)
image_np = np.array(image)
annotated = image.copy() # Copy for annotation
draw = ImageDraw.Draw(annotated)
# Classify overall pipe material
pipe_material = classify_pipe_material(image_np)
# Preprocessing: convert to grayscale and enhance contrast with CLAHE
gray = cv2.cvtColor(image_np, cv2.COLOR_RGB2GRAY)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
enhanced = clahe.apply(gray)
# Apply Gaussian blur to reduce noise
blurred = cv2.GaussianBlur(enhanced, (5, 5), 0)
# Adaptive thresholding to highlight potential defect areas
thresh = cv2.adaptiveThreshold(
blurred, 255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY_INV,
11, 2
)
# Morphological closing to connect fragmented regions
kernel = np.ones((3, 3), np.uint8)
morph = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)
# Edge detection
edges = cv2.Canny(morph, 50, 150)
# Find contours corresponding to potential defects
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
detections = []
# Define colors for different defect types
colors = {
"Rust": "orange",
"Crack": "red",
"Corrosion": "blue",
"Other Defect": "green"
}
for cnt in contours:
# Filter out small contours to ignore noise
if cv2.contourArea(cnt) < 100:
continue
x, y, w, h = cv2.boundingRect(cnt)
# Extract ROI from the original image
roi = image_np[y:y+h, x:x+w]
if roi.size == 0:
continue
defect_type = classify_defect(roi)
detection_info = f"{defect_type} at ({x}, {y}, {w}, {h})"
detections.append(detection_info)
# Draw bounding box with corresponding color and label
box_color = colors.get(defect_type, "green")
draw.rectangle([x, y, x+w, y+h], outline=box_color, width=2)
draw.text((x, y-10), defect_type, fill=box_color)
# Create a summary including pipe material and detected defects
if detections:
summary = f"Pipe Material: {pipe_material}\nDetected Issues:\n" + "\n".join(detections)
else:
summary = f"Pipe Material: {pipe_material}\nNo significant defects detected."
return annotated, summary
except Exception as e:
print("Error during detection:", e)
return image, f"Error: {e}"
iface = gr.Interface(
fn=detect_pipe_issues,
inputs=gr.Image(type="pil", label="Upload a Pipe Image"),
outputs=[gr.Image(label="Annotated Image"), gr.Textbox(label="Detection Summary")],
title="Pipe Defect Detector",
description=(
"Upload an image of a pipe to detect granular issues such as cracks, corrosion, rust, "
"and other defects. The app classifies the defect type and displays a colored bounding box for each class. "
"Pipe material (Plastic or Metal) is also identified."
)
)
if __name__ == "__main__":
iface.launch()
|