File size: 5,786 Bytes
016e3a4 a3fd7df 016e3a4 bc98998 6b2ef87 d8f4143 6b2ef87 702fbba 6b2ef87 db5d973 6b2ef87 702fbba 6b2ef87 a3fd7df 702fbba 6b2ef87 db5d973 6b2ef87 426c5c1 6b2ef87 b145630 d06b635 | 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 143 144 145 146 147 148 | import gradio as gr
import torch
import torch.nn as nn
from torchvision import models, transforms
from PIL import Image
import numpy as np
import pickle
import os
import cv2
import logging
from sklearn.cluster import KMeans
def detect_connect_and_crop(image_source: Image.Image):
"""
1. Detects bolt holes using Hough Transform.
2. Separates them into Top and Bottom rows.
3. Fits a straight horizontal line through the center of each row.
4. Crops the region strictly between these two lines.
"""
# Convert PIL Image to OpenCV format (RGB -> BGR usually, but we keep RGB for display)
img_rgb = np.array(image_source)
img_h, img_w = img_rgb.shape[:2]
# Convert to Grayscale for detection
gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY)
# ββ Step 1: Detect Circles (Bolt Holes) βββββββββββββββββββββββββββββββββ
circles = cv2.HoughCircles(
gray,
cv2.HOUGH_GRADIENT,
dp=1, # Resolution ratio
minDist=50, # Min distance between holes (prevents double detection)
param1=100, # Canny edge threshold (higher = fewer edges)
param2=30, # Accumulator threshold (lower = more circles)
minRadius=10, # Min size of bolt hole
maxRadius=40 # Max size of bolt hole
)
if circles is None:
return image_source, image_source, "β No bolt holes detected. Adjust lighting or focus."
# Convert coordinates to integers
circles = np.round(circles[0]).astype(int)
# ββ Step 2: Separate into Top and Bottom Rows βββββββββββββββββββββββββββ
# We sort all circles by their Y (height) coordinate
# The "Gap" in Y values tells us where the split between rows is.
ys = [c[1] for c in circles]
y_median = np.median(ys) # Find the middle point of the image's height logic
# Split circles based on if they are above or below the median height
top_row = [c for c in circles if c[1] < y_median]
bot_row = [c for c in circles if c[1] >= y_median]
if len(top_row) < 2 or len(bot_row) < 2:
return image_source, image_source, "β οΈ Need at least 2 holes in both top and bottom rows to draw lines."
# ββ Step 3: Calculate Straight Lines (Average Y) ββββββββββββββββββββββββ
# We take the average Y of the top row to get a straight horizontal line
y_top_line = int(np.mean([c[1] for c in top_row]))
# We take the average Y of the bottom row
y_bot_line = int(np.mean([c[1] for c in bot_row]))
# ββ Step 4: Visualization βββββββββββββββββββββββββββββββββββββββββββββββ
vis_img = img_rgb.copy()
# Colors
LINE_COLOR = (0, 255, 0) # Green
HOLE_COLOR = (255, 0, 0) # Red
CENTER_COLOR = (255, 255, 0) # Yellow dots
# Draw the straight horizontal lines across the full width
cv2.line(vis_img, (0, y_top_line), (img_w, y_top_line), LINE_COLOR, 3)
cv2.line(vis_img, (0, y_bot_line), (img_w, y_bot_line), LINE_COLOR, 3)
# Draw the holes and their centers to show what we detected
for (x, y, r) in circles:
cv2.circle(vis_img, (x, y), r, HOLE_COLOR, 2) # The hole outline
cv2.circle(vis_img, (x, y), 3, CENTER_COLOR, -1) # The center dot
# ββ Step 5: Crop the Region Between Lines ββββββββββββββββββββββββββββββ
# Slice the array: img[y_start : y_end, x_start : x_end]
# We add a tiny padding (e.g., +/- 0) or keep it exact.
# Ensure y_top is actually above y_bot
y_start, y_end = sorted([y_top_line, y_bot_line])
# Safety check for crop size
if y_end - y_start < 10:
return Image.fromarray(vis_img), Image.fromarray(img_rgb), "β οΈ Calculated lines are too close."
cropped_img = img_rgb[y_start:y_end, 0:img_w]
# Generate Stats Text
stats_text = (
f"β
**Processing Complete**\n"
f"β’ Top Row Holes: {len(top_row)}\n"
f"β’ Bottom Row Holes: {len(bot_row)}\n"
f"β’ Top Line Y-Pos: {y_top_line} px\n"
f"β’ Bottom Line Y-Pos: {y_bot_line} px\n"
f"β’ Cropped Height: {y_end - y_start} px"
)
return Image.fromarray(vis_img), Image.fromarray(cropped_img), stats_text
# ββ Gradio Interface ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
with gr.Blocks(title="Engine Line Connector", theme=gr.themes.Default(primary_hue="blue")) as demo:
gr.Markdown(
"""
# π Bolt-Center Line Connector
### Precision Cropping Tool
1. Detects bolt holes.
2. Draws a straight line through the average center of the top & bottom rows.
3. Crops the saddle area exactly between these two lines.
"""
)
with gr.Row():
input_image = gr.Image(type="pil", label="π· Upload Engine Block Image")
run_button = gr.Button("π Connect Centers & Crop", variant="primary")
with gr.Row():
output_vis = gr.Image(label="βοΈ Visualized Lines & Centers")
output_crop = gr.Image(label="βοΈ Final Cropped Area")
stats_output = gr.Markdown()
run_button.click(
fn=detect_connect_and_crop,
inputs=[input_image],
outputs=[output_vis, output_crop, stats_output]
)
if __name__ == "__main__":
demo.launch()
|