#Ito ung database connection import mysql.connector DB_CONFIG = { "host": "localhost", "user": "root", "password": "", "database": "crack_detection" } import subprocess import sys import tkinter as tk from tkinter import messagebox import cv2 from PIL import Image, ImageTk import os from keras.models import load_model # TensorFlow is required for Keras to work from PIL import Image, ImageOps # Install pillow instead of PIL import numpy as np # Disable scientific notation for clarity np.set_printoptions(suppress=True) # Load the model model = load_model("keras_Model.h5", compile=False) # Load the labels class_names = open("labels.txt", "r").readlines() # Globals cap = None camera_running = False last_frame = None # store last camera frame crack_type = "s" risk_level = "Medium" confidence = 0 length_cm = 0 width_mm = 0 depth_mm = 0 PIXEL_TO_MM = 0.083 #Calibration Value To Change root = tk.Tk() root.title("Crack Detection") # selected_option = tk.IntVar(value=0) # tk.Label(root, text="Select Value").pack(pady=10) # tk.Radiobutton(root, text="Option 1", variable=selected_option, value=1).pack() # tk.Radiobutton(root, text="Option 2", variable=selected_option, value=2).pack() root.geometry("1050x500") #Screen Size root.configure(bg="white") tk.Label( root, text="Crack Detection", font=("Arial", 26, "bold"), bg="white" ).grid(row=0, column=0, columnspan=3, pady=20) type_var = tk.StringVar(value="TYPE: -") risk_var = tk.StringVar(value="RISK LEVEL: -") conf_var = tk.StringVar(value="CONFIDENCE: - %") length_var = tk.StringVar(value="LENGTH: - cm") width_var = tk.StringVar(value="WIDTH: - mm") depth_var = tk.StringVar(value="DEPTH: - mm") # Camera Frame camera_frame = tk.Frame(root, bg="white") camera_frame.grid(row=1, column=0, padx=40, sticky="n") # Camera 1 (Live) cam1_box = tk.Frame( camera_frame, width=300, height=300, bg="black", highlightbackground="#5b214b", highlightthickness=4 ) cam1_box.pack(side="left", padx=20) cam1_box.pack_propagate(False) cam1_label = tk.Label( cam1_box, bg="black", fg="white", text="Camera 1", font=("Arial", 12, "bold") ) cam1_label.pack(fill="both", expand=True) # Camera 2 (Captured) cam2_box = tk.Frame( camera_frame, width=300, height=300, bg="white", highlightbackground="#5b214b", highlightthickness=4 ) cam2_box.pack(side="left", padx=20) cam2_box.pack_propagate(False) cam2_label = tk.Label( cam2_box, bg="white", text="Camera 2", font=("Arial", 12, "bold") ) cam2_label.pack(fill="both", expand=True) # Buttons btn_frame = tk.Frame(root, bg="white") btn_frame.grid(padx=20, sticky="n") #btn_frame.pack(fill="both", expand=True, padx=30) def styled_button(parent, text, cmd): return tk.Button( parent, text=text, command=cmd, bg="#00a99d", fg="white", font=("Arial", 10, "bold"), relief="flat", padx=18, pady=10 ) # Camera Functions def start_camera(): global cap, camera_running if camera_running: return cap = cv2.VideoCapture(0) if not cap.isOpened(): messagebox.showerror("Error", "Cannot open camera") return camera_running = True update_camera() def update_camera(): global cap, camera_running, last_frame if not camera_running: return ret, frame = cap.read() if ret: last_frame = frame.copy() frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) frame_rgb = cv2.resize(frame_rgb, (300, 300)) img = Image.fromarray(frame_rgb) imgtk = ImageTk.PhotoImage(img) cam1_label.imgtk = imgtk cam1_label.configure(image=imgtk) root.after(20, update_camera) def stop_camera(): global cap, camera_running camera_running = False if cap: cap.release() cap = None def capture_stereo(): global last_frame if last_frame is None: messagebox.showwarning("Warning", "Camera not ready") return # Save image save_path = "captured_stereo.jpg" cv2.imwrite(save_path, last_frame) # Show image img = cv2.imread(save_path) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = cv2.resize(img, (300, 300)) img = Image.fromarray(img) imgtk = ImageTk.PhotoImage(img) cam2_label.imgtk = imgtk cam2_label.configure(image=imgtk, text="") print(f"Image saved and displayed: {save_path}") def run_analysis(): print("Run crack analysis") data = np.ndarray(shape=(1, 224, 224, 3), dtype=np.float32) # Replace this with the path to your image image = Image.open("captured_stereo.jpg").convert("RGB") # resizing the image to be at least 224x224 and then cropping from the center size = (224, 224) image = ImageOps.fit(image, size, Image.Resampling.LANCZOS) # turn the image into a numpy array image_array = np.asarray(image) # Normalize the image normalized_image_array = (image_array.astype(np.float32) / 127.5) - 1 # Load the image into the array data[0] = normalized_image_array # Predicts the model prediction = model.predict(data) index = np.argmax(prediction) class_name = class_names[index] confidence_score = prediction[0][index] * 100 confidence_score = round(confidence_score, 2) # Print prediction and confidence score print("Class:", class_name[2:], end="") print("Confidence Score:", confidence_score) crack_type = class_name[2:].strip() confidence = confidence_score print(crack_type) #Risk Level Condition if crack_type == "Structural Cracks": risk_level = "High" elif crack_type == "Horizontal" or crack_type == "Diagonal": risk_level = "Mid" elif crack_type == "Hairline": risk_level = "Low" else: risk_level = "Low" length_cm = 12.4 width_mm = 1.6 depth_mm = 0.8 binary = preprocess_crack('1.jpg') length_mm = calculate_crack_length(binary, PIXEL_TO_MM) width_mm = calculate_crack_width(binary, PIXEL_TO_MM) length_mm = round(length_mm, 2) width_mm = round(width_mm, 2) depth_mm = width_mm * .0123 length_cm = length_mm / 10 # ---- Update UI labels ---- type_var.set(f"TYPE: {crack_type}") risk_var.set(f"RISK LEVEL: {risk_level}") conf_var.set(f"CONFIDENCE: {confidence:.1f} %") length_var.set(f"LENGTH: {length_cm} cm") width_var.set(f"WIDTH: {width_mm} mm") depth_var.set(f"DEPTH: {depth_mm} mm") print("Crack analysis completed") try: conn = mysql.connector.connect(**DB_CONFIG) cursor = conn.cursor() sql = """ INSERT INTO crack_results (image_path, crack_type, risk_level, confidence, length_cm, width_mm, depth_mm) VALUES (%s, %s, %s, %s, %s, %s, %s) """ data = ( "captured_stereo.jpg", # image path crack_type, # crack type risk_level, # risk level confidence, # confidence % length_cm, # length cm width_mm, # width mm depth_mm # depth mm ) cursor.execute(sql, data) conn.commit() cursor.close() conn.close() messagebox.showinfo("Success", "Data saved to MySQL database") except mysql.connector.Error as e: messagebox.showerror("Database Error", str(e)) def save_results(): try: conn = mysql.connector.connect(**DB_CONFIG) cursor = conn.cursor() sql = """ INSERT INTO crack_results (image_path, crack_type, risk_level, confidence, length_cm, width_mm, depth_mm) VALUES (%s, %s, %s, %s, %s, %s, %s) """ data = ( "captured_stereo.jpg", # image path crack_type, # crack type risk_level, # risk level confidence, # confidence % length_cm, # length cm width_mm, # width mm depth_mm # depth mm ) cursor.execute(sql, data) conn.commit() cursor.close() conn.close() messagebox.showinfo("Success", "Data saved to MySQL database") except mysql.connector.Error as e: messagebox.showerror("Database Error", str(e)) #For Lenght, Widht , Dep Result def calculate_crack_length(binary_img, pixel_to_mm): """ binary_img: thresholded crack image (white crack, black background) """ # Find contours contours, _ = cv2.findContours(binary_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) if not contours: return 0 # Largest contour = crack crack = max(contours, key=cv2.contourArea) # Calculate pixel length length_pixels = cv2.arcLength(crack, closed=False) # Convert to real length length_mm = length_pixels * pixel_to_mm return length_mm def calculate_crack_width(binary_img, pixel_to_mm): # Invert image inv = cv2.bitwise_not(binary_img) # Distance transform dist = cv2.distanceTransform(inv, cv2.DIST_L2, 5) # Max width in pixels max_width_px = np.max(dist) * 2 # Convert to mm width_mm = max_width_px * pixel_to_mm return width_mm def preprocess_crack(img): img = cv2.imread("captured_stereo.jpg") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blur = cv2.GaussianBlur(gray, (5,5), 0) _, binary = cv2.threshold( blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU ) return binary def open_other_program(): subprocess.Popen([sys.executable, "view.py"]) #Display UI styled_button(btn_frame, "CAPTURE STEREO IMAGE", capture_stereo).pack(side="left",padx=15) styled_button(btn_frame, "RUN CRACK ANALYSIS", run_analysis).pack(side="left",padx=15) # Right Info Panel info_frame = tk.Frame(root, bg="white") info_frame.grid(row=1, column=2, padx=40, sticky="n") #Update label Details tk.Label(info_frame, text="Crack Information", font=("Arial", 14, "bold"), bg="white").pack(anchor="w") tk.Label(info_frame, textvariable=type_var, font=("Arial", 10), bg="white").pack(anchor="w", pady=2) tk.Label(info_frame, textvariable=risk_var, font=("Arial", 10), bg="white").pack(anchor="w", pady=2) tk.Label(info_frame, textvariable=conf_var, font=("Arial", 10), bg="white").pack(anchor="w", pady=2) tk.Label(info_frame, text="", bg="white").pack() tk.Label(info_frame, text="GEOMETRIC MEASUREMENTS", font=("Arial", 10, "bold"), bg="white").pack(anchor="w", pady=(5, 2)) tk.Label(info_frame, textvariable=length_var, font=("Arial", 10), bg="white").pack(anchor="w", pady=2) tk.Label(info_frame, textvariable=width_var, font=("Arial", 10), bg="white").pack(anchor="w", pady=2) tk.Label(info_frame, textvariable=depth_var, font=("Arial", 10), bg="white").pack(anchor="w", pady=2) # Save Buttons save_frame = tk.Frame(info_frame, bg="white") save_frame.pack(pady=15) styled_button(save_frame, "SAVE", save_results).pack(side="left", padx=10) styled_button(save_frame, "VIEW", open_other_program).pack(side="left", padx=10) start_camera() # Start Ito ng Camera def on_close(): stop_camera() root.destroy() root.protocol("WM_DELETE_WINDOW", on_close) root.mainloop()