Practice / app.py
Cuervo-x's picture
Create app.py
6de2332 verified
import numpy as np
import cv2
import gradio as gr
from skimage.morphology import convex_hull_image
# =========================================================
# Utility Functions
# =========================================================
def orient_to_portrait(img):
h, w = img.shape[:2]
if w > h:
img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
return img
def analyze_cv_only(image, threshold_pct, min_defect_size):
"""
Simulates the ML pipeline using traditional image processing.
"""
if image is None:
return None, "0.0%", "0.0%", None, None
# 1. Preprocessing
img_color = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
img_color = orient_to_portrait(img_color)
gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
# 2. Simulate Print Segmentation (Thresholding)
# Instead of a model, we use simple binary thresholding
val = int((threshold_pct / 100.0) * 255)
_, print_mask = cv2.threshold(blurred, val, 255, cv2.THRESH_BINARY_INV)
# Find largest contour to represent the print
contours, _ = cv2.findContours(print_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if not contours:
return image, "0.0%", "0.0%", None, None
largest_cnt = max(contours, key=cv2.contourArea)
print_mask_clean = np.zeros_like(print_mask)
cv2.drawContours(print_mask_clean, [largest_cnt], -1, 255, thickness=-1)
# 3. Simulate Defect Detection (Edge Detection within the print)
# Detects high-contrast areas (cracks/voids) inside the print mask
edges = cv2.Canny(blurred, 50, 150)
defect_mask = cv2.bitwise_and(edges, print_mask_clean)
# Filter defects by size
final_defect_mask = np.zeros_like(defect_mask)
def_cnts, _ = cv2.findContours(defect_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for cnt in def_cnts:
if cv2.contourArea(cnt) >= min_defect_size:
cv2.drawContours(final_defect_mask, [cnt], -1, 255, thickness=-1)
# 4. Metrics
# Integrity: Ratio of print to its convex hull
try:
hull = convex_hull_image(print_mask_clean > 0)
integrity_score = np.sum(print_mask_clean > 0) / np.sum(hull)
except:
integrity_score = 0.0
# Quality: Inverse of defect area
print_area = np.sum(print_mask_clean > 0)
defect_area = np.sum(final_defect_mask > 0)
quality_score = 100.0 - ((defect_area / print_area) * 100.0) if print_area > 0 else 0.0
# 5. Visualization
vis = img_color.copy()
cv2.drawContours(vis, [largest_cnt], -1, (255, 0, 0), 2) # Blue outline
cv2.drawContours(vis, [cv2.convexHull(largest_cnt)], -1, (0, 0, 255), 2) # Red hull
# Draw defects in green
vis[final_defect_mask > 0] = [0, 255, 0]
# Save outputs
mask_path = "combined_mask.png"
cv2.imwrite(mask_path, final_defect_mask)
vis_path = "analysis_output.png"
cv2.imwrite(vis_path, vis)
return cv2.cvtColor(vis, cv2.COLOR_BGR2RGB), f"{integrity_score*100:.1f}%", f"{quality_score:.1f}%", vis_path, mask_path
# =========================================================
# UI Layout
# =========================================================
custom_css = """
.score-box { background-color: #f8f9fa; border-radius: 10px; padding: 15px; text-align: center; }
.score-value { font-size: 2rem !important; font-weight: 700 !important; color: #2b6cb0 !important; }
"""
with gr.Blocks(css=custom_css) as app:
gr.Markdown("# CV-Only Print Analysis (No ML)")
with gr.Row():
with gr.Column():
img_input = gr.Image(type="numpy", label="Input Image")
thresh_slider = gr.Slider(50, 255, value=127, label="Brightness Threshold")
size_slider = gr.Slider(0, 500, value=20, label="Min Defect Size")
run_btn = gr.Button("Analyze", variant="primary")
with gr.Column():
img_output = gr.Image(label="Analysis Result")
with gr.Row():
area_out = gr.Markdown("0.0%", elem_classes=["score-value"])
surface_out = gr.Markdown("0.0%", elem_classes=["score-value"])
run_btn.click(
fn=analyze_cv_only,
inputs=[img_input, thresh_slider, size_slider],
outputs=[img_output, area_out, surface_out]
)
app.queue().launch(server_name="0.0.0.0", server_port=7860, ssr_mode=False)