Spaces:
Sleeping
Sleeping
File size: 14,562 Bytes
70ebc90 | 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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | from utils.reference import detect_reference
from utils.detect_objects import run_modelA
from utils.generate_masks import run_modelB
from measure import measure_tool
from utils.match_spec import run_spec_match
from utils.visualize_all import visualize_detections
from pathlib import Path
import os
import cv2
import numpy as np
import sys
# Get project root (for absolute paths)
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Helper function to get absolute paths
def get_path(relative_path):
return os.path.join(PROJECT_ROOT, relative_path)
def main():
print("π Starting main program...")
# Clean outputs/5_measured and outputs/6_results for a fresh run
import shutil
for folder in [get_path("outputs/5_measured"), get_path("outputs/6_results")]:
if os.path.exists(folder):
shutil.rmtree(folder)
Path(get_path("outputs/2_reference")).mkdir(parents=True, exist_ok=True)
Path(get_path("outputs/3_detection")).mkdir(parents=True, exist_ok=True)
Path(get_path("outputs/3_detection/labels")).mkdir(parents=True, exist_ok=True)
Path(get_path("outputs/4_segmentation/masks")).mkdir(parents=True, exist_ok=True)
Path(get_path("outputs/4_segmentation/overlay")).mkdir(parents=True, exist_ok=True)
Path(get_path("outputs/5_measured")).mkdir(parents=True, exist_ok=True)
Path(get_path("outputs/6_results/spec_match_report")).mkdir(parents=True, exist_ok=True)
Path(get_path("outputs/6_results/output_images")).mkdir(parents=True, exist_ok=True)
# Step 1: Provide image path (no live capture)
if len(sys.argv) > 1:
img_path = sys.argv[1]
else:
img_path = input("Enter image path: ").strip()
if not os.path.isfile(img_path):
print("β οΈ Invalid image path. Exiting program.")
return
print(f"π Using image: {img_path}")
# Step 2: Detect reference square
ref_status, px_per_mm, ref_points = detect_reference(
image_path=img_path,
ref_size_mm=20.0,
save_path=get_path("outputs/2_reference")
)
if ref_status == "success":
print(f"β
Reference detected. Pixels per mm: {px_per_mm:.2f}")
else:
print("β Reference not detected. Check image quality or lighting.")
px_per_mm = None
# Step 3: Run Model A (Object Detection)
print("π― Running Model A for object detection...")
detections, label_path = run_modelA(
image_path=img_path,
model_path=get_path("models/model_a.pt"),
device="cpu",
imgsz=640,
conf_thr=0.25,
iou_thr=0.5,
save_annotated=True,
outdir=get_path("outputs/3_detection"),
save_labels=True
)
if detections:
print("\nβ
Detected objects:")
for i, det in enumerate(detections):
print(f"{i+1}. {det['class_name']}")
print()
else:
print("β οΈ No objects detected.")
# Step 4: Run Model B (Segmentation/Mask Generation)
mask_array = None
if label_path and detections:
print("π― Running Model B for segmentation/mask generation...")
result = run_modelB(
img_path=img_path,
label_txt_path=label_path
)
if result and "mask_array" in result:
mask_array = result["mask_array"]
print("β
Mask generated and saved successfully.")
print()
else:
print("β οΈ No masks generated.")
else:
print("β οΈ Skipping Model B (no labels from Model A).")
# Step 5: Run Model C (Measurements)
measurement_results = {}
if detections:
print("π Running Model C (Measurements)...")
measurement_results = measure_tool.process_measurements(
image_path=img_path,
detections=detections,
label_path=label_path,
mask_data=mask_array,
px_per_mm=px_per_mm
)
if measurement_results:
for obj_id, res in measurement_results.items():
class_name = res.get('class', 'unknown')
if class_name == 'washer':
print("β
Washer measurement saved.")
elif class_name == 'bolt':
print("β
Bolt measurement saved.")
elif class_name == 'nut':
print("β
Nut measurement saved.")
elif class_name == 'screw':
print("β
Screw measurement saved.")
else:
print("β οΈ No valid measurements returned.")
else:
print("β οΈ Skipping Model C (no detections).")
# Step 6: Run Model D (Specification Matching)
spec_results = []
if measurement_results:
print("π Running Model D (Specification Matching)...")
report_path = get_path("outputs/6_results/spec_match_report/spec_match_report.txt")
reference_csv_dict = {
"washer": get_path("data/datasets/washers_dataset.csv"),
"bolt": get_path("data/datasets/bolts_dataset.csv"),
"nut": get_path("data/datasets/nuts_dataset.csv"),
"screw": get_path("data/datasets/screws_dataset.csv")
}
spec_results = run_spec_match(
measurements_dir=get_path("outputs/5_measured"),
reference_csv_dict=reference_csv_dict,
output_txt=report_path
)
print(f"β
Spec matching completed. Report saved at: {report_path}")
else:
print("β οΈ Skipping Model D (no measurements to match).")
# --- Visualization ---
if detections:
image = cv2.imread(img_path)
det_list = []
mask_list = []
meas_list = []
# Create a mapping of object_id to predicted values
predicted_values = {}
for spec_res in spec_results:
if spec_res['reference']:
file_name = Path(spec_res['file']).stem
obj_id = file_name.replace('_measured', '')
predicted_values[obj_id] = spec_res['reference']
# Process all detections for visualization
for idx, det in enumerate(detections):
cls_name = det['class_name'].lower()
bbox = det['xyxy']
det_list.append({'label': det['class_name'], 'bbox': bbox})
# Find corresponding measurement result
obj_id = f"{cls_name}_{idx+1}"
meas = measurement_results.get(obj_id, {})
# Extract mask from Model B
if mask_array is not None:
x1, y1, x2, y2 = map(int, bbox)
if isinstance(mask_array, (list, tuple)) and idx < len(mask_array):
obj_mask = np.zeros(image.shape[:2], dtype=np.uint8)
mask_obj = mask_array[idx]
if mask_obj.shape != obj_mask.shape:
mask_obj = cv2.resize(mask_obj, (obj_mask.shape[1], obj_mask.shape[0]), interpolation=cv2.INTER_NEAREST)
obj_mask = (mask_obj > 0).astype(np.uint8)
mask_list.append(obj_mask)
elif isinstance(mask_array, np.ndarray) and mask_array.ndim == 3 and idx < mask_array.shape[0]:
mask_obj = mask_array[idx]
obj_mask = (mask_obj > 0).astype(np.uint8)
mask_list.append(obj_mask)
elif isinstance(mask_array, np.ndarray) and mask_array.ndim == 2:
obj_mask = np.zeros(image.shape[:2], dtype=np.uint8)
mask_crop = mask_array[y1:y2, x1:x2]
obj_mask[y1:y2, x1:x2] = (mask_crop > 0).astype(np.uint8)
mask_list.append(obj_mask)
else:
mask_list.append(np.zeros(image.shape[:2], dtype=np.uint8))
else:
mask_list.append(np.zeros(image.shape[:2], dtype=np.uint8))
# Use predicted values if available, otherwise fall back to measured values
pred_vals = predicted_values.get(obj_id, {})
dims = {}
if meas.get('class') == 'bolt' and pred_vals:
if 'Bolt Size' in pred_vals:
dims['Nominal_M'] = pred_vals['Bolt Size']
if 'Length_mm' in pred_vals and pred_vals['Length_mm'] is not None:
dims['Length_mm'] = float(pred_vals['Length_mm'])
elif meas.get('class') == 'washer' and pred_vals:
if 'OD_mm' in pred_vals and pred_vals['OD_mm'] is not None:
dims['OD'] = float(pred_vals['OD_mm'])
if 'ID_mm' in pred_vals and pred_vals['ID_mm'] is not None:
dims['ID'] = float(pred_vals['ID_mm'])
elif meas.get('class') == 'nut' and pred_vals:
if 'Nominal Dia' in pred_vals:
dims['Nominal_Dia'] = pred_vals['Nominal Dia']
if 'AF_mm' in pred_vals and pred_vals['AF_mm'] is not None:
dims['AF'] = float(pred_vals['AF_mm'])
elif meas.get('class') == 'screw' and pred_vals:
if 'Length_mm' in meas and meas['Length_mm'] is not None:
dims['Length_mm'] = float(meas['Length_mm'])
if 'Nominal Dia' in pred_vals:
dims['Nominal_Dia'] = pred_vals['Nominal Dia']
else:
if meas.get('OD_mm') is not None:
dims['OD'] = float(meas['OD_mm'])
if meas.get('ID_mm') is not None:
dims['ID'] = float(meas['ID_mm'])
if meas.get('AF_mm') is not None:
dims['AF'] = float(meas['AF_mm'])
if meas.get('Length_mm') is not None:
dims['Length_mm'] = float(meas['Length_mm'])
if meas.get('class') == 'screw' and 'Length_mm' in meas and 'Length_mm' not in dims and meas['Length_mm'] is not None:
dims['Length_mm'] = float(meas['Length_mm'])
meas_list.append(dims)
# Visualize all detections
if det_list:
result_img = visualize_detections(image, det_list, mask_list, meas_list)
out_img_path = get_path("outputs/6_results/output_images/final_output.jpg")
cv2.imwrite(out_img_path, result_img)
print(f"πΌοΈ Final visualization saved: {out_img_path}")
print("\nπΌοΈ Displaying final output image...")
cv2.imshow("Final Detection & Measurement Results", result_img)
print("Press any key to close the image window...")
cv2.waitKey(0)
cv2.destroyAllWindows()
print("\n" + "="*60)
print("π FINAL SUMMARY - DETECTED AND MEASURED COMPONENTS")
print("="*60)
print(f"\nπ― DETECTION SUMMARY:")
print(f" Total objects detected: {len(detections)}")
class_counts = {}
for det in detections:
class_name = det['class_name']
class_counts[class_name] = class_counts.get(class_name, 0) + 1
for class_name, count in class_counts.items():
print(f" - {class_name}: {count} object(s)")
print(f"\nπ PROCESSING SUMMARY:")
print(f" Components with measurements: {len(measurement_results)}")
for obj_id, meas in measurement_results.items():
print(f"\n π§ {obj_id.upper()}:")
print(f" Class: {meas['class']}")
confidence = meas.get('confidence', 'N/A')
if isinstance(confidence, (int, float)):
print(f" Confidence: {confidence:.3f}")
else:
print(f" Confidence: {confidence}")
if meas['class'] == 'bolt':
if 'Bolt Size' in predicted_values.get(obj_id, {}):
print(f" Nominal Size: {predicted_values[obj_id]['Bolt Size']}")
if 'Length_mm' in predicted_values.get(obj_id, {}):
print(f" Length: {predicted_values[obj_id]['Length_mm']} mm")
elif meas['class'] == 'washer':
if 'OD_mm' in predicted_values.get(obj_id, {}):
print(f" Outer Diameter: {predicted_values[obj_id]['OD_mm']} mm")
if 'ID_mm' in predicted_values.get(obj_id, {}):
print(f" Inner Diameter: {predicted_values[obj_id]['ID_mm']} mm")
elif meas['class'] == 'nut':
if 'Nominal Dia' in predicted_values.get(obj_id, {}):
print(f" Nominal Diameter: {predicted_values[obj_id]['Nominal Dia']}")
if 'AF_mm' in predicted_values.get(obj_id, {}):
print(f" Across Flats: {predicted_values[obj_id]['AF_mm']} mm")
elif meas['class'] == 'screw':
if 'Nominal Dia' in predicted_values.get(obj_id, {}):
print(f" Nominal Diameter: {predicted_values[obj_id]['Nominal Dia']}")
if 'Length_mm' in meas:
print(f" Length: {meas['Length_mm']:.2f} mm")
if spec_results:
print(f"\nπ SPECIFICATION MATCHING SUMMARY:")
print(f" Total components analyzed: {len(spec_results)}")
matched_count = sum(1 for spec in spec_results if spec['reference'])
print(f" Successfully matched: {matched_count}")
print(f" Match rate: {(matched_count/len(spec_results)*100):.1f}%")
print(f"\n π Detailed spec matching results:")
for spec in spec_results:
file_name = Path(spec['file']).stem.replace('_measured', '')
status = "β
MATCHED" if spec['reference'] else "β NO MATCH"
print(f" {file_name}: {status}")
if spec['reference']:
print(f" Reference: {spec['reference']}")
print("\n" + "="*60)
print("β
ANALYSIS COMPLETE")
print("="*60)
if __name__ == "__main__":
main()
|