diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..97807ae9ce3bfedcd712d1e67c64ac16cae8b4fc Binary files /dev/null and b/.DS_Store differ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..ac23ed037d3fcdeff1faa6396c2bfe880d9f8506 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +# Utiliser une image de base Python légère +FROM python:3.9-slim + +# Définir le répertoire de travail +WORKDIR /app + +# Copier les fichiers nécessaires dans le conteneur +COPY . /app + +# Installer les dépendances +RUN pip install --no-cache-dir -r requirements.txt + +# Exposer le port 7860 pour le serveur Flask +EXPOSE 7860 + +# Commande pour démarrer Flask +CMD ["python", "app.py"] \ No newline at end of file diff --git a/README.md b/README.md index efa77c4b9869785e08be9d67c1887302fc7145e9..c247b19030f898e97dc3f4458673b608ee240804 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ --- title: Segmentation Project -emoji: ⚡ -colorFrom: blue -colorTo: yellow +emoji: 😻 +colorFrom: red +colorTo: purple sdk: docker pinned: false --- diff --git a/app.log b/app.log new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/app.py b/app.py new file mode 100644 index 0000000000000000000000000000000000000000..bdd4318ba4d6e3c135d34d167940dcb959c8eb7d --- /dev/null +++ b/app.py @@ -0,0 +1,797 @@ +from flask import Flask, render_template, request, jsonify +from flask_socketio import SocketIO +import os +import shutil +import numpy as np +from PIL import Image +from utils.predictor import Predictor +from utils.helpers import ( + blend_mask_with_image, + save_mask_as_png, + convert_mask_to_yolo, +) +import torch +from ultralytics import YOLO +import threading +from threading import Lock +import subprocess +import time +import logging +import multiprocessing + + +# Initialize Flask app and SocketIO +app = Flask(__name__) +socketio = SocketIO(app) + +# Define Base Directory +BASE_DIR = os.path.abspath(os.path.dirname(__file__)) + +# Folder structure with absolute paths +UPLOAD_FOLDERS = { + 'input': os.path.join(BASE_DIR, 'static/uploads/input'), + 'segmented_voids': os.path.join(BASE_DIR, 'static/uploads/segmented/voids'), + 'segmented_chips': os.path.join(BASE_DIR, 'static/uploads/segmented/chips'), + 'mask_voids': os.path.join(BASE_DIR, 'static/uploads/mask/voids'), + 'mask_chips': os.path.join(BASE_DIR, 'static/uploads/mask/chips'), + 'automatic_segmented': os.path.join(BASE_DIR, 'static/uploads/segmented/automatic'), +} + +HISTORY_FOLDERS = { + 'images': os.path.join(BASE_DIR, 'static/history/images'), + 'masks_chip': os.path.join(BASE_DIR, 'static/history/masks/chip'), + 'masks_void': os.path.join(BASE_DIR, 'static/history/masks/void'), +} + +DATASET_FOLDERS = { + 'train_images': os.path.join(BASE_DIR, 'dataset/train/images'), + 'train_labels': os.path.join(BASE_DIR, 'dataset/train/labels'), + 'val_images': os.path.join(BASE_DIR, 'dataset/val/images'), + 'val_labels': os.path.join(BASE_DIR, 'dataset/val/labels'), + 'temp_backup': os.path.join(BASE_DIR, 'temp_backup'), + 'models': os.path.join(BASE_DIR, 'models'), + 'models_old': os.path.join(BASE_DIR, 'models/old'), +} + +# Ensure all folders exist +for folder_name, folder_path in {**UPLOAD_FOLDERS, **HISTORY_FOLDERS, **DATASET_FOLDERS}.items(): + os.makedirs(folder_path, exist_ok=True) + logging.info(f"Ensured folder exists: {folder_name} -> {folder_path}") + +training_process = None + + +def initialize_training_status(): + """Initialize global training status.""" + global training_status + training_status = {'running': False, 'cancelled': False} + +def persist_training_status(): + """Save training status to a file.""" + with open(os.path.join(BASE_DIR, 'training_status.json'), 'w') as status_file: + json.dump(training_status, status_file) + +def load_training_status(): + """Load training status from a file.""" + global training_status + status_path = os.path.join(BASE_DIR, 'training_status.json') + if os.path.exists(status_path): + with open(status_path, 'r') as status_file: + training_status = json.load(status_file) + else: + training_status = {'running': False, 'cancelled': False} + +load_training_status() + +os.environ["TORCH_CUDNN_SDPA_ENABLED"] = "0" + +# Initialize SAM Predictor +MODEL_CFG = r"C:\codes\sam2\segment-anything-2\sam2\configs\sam2.1\sam2.1_hiera_l.yaml" +CHECKPOINT = r"C:\codes\sam2\segment-anything-2\checkpoints\sam2.1_hiera_large.pt" +DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") +predictor = Predictor(MODEL_CFG, CHECKPOINT, DEVICE) + +# Initialize YOLO-seg +YOLO_CFG = os.path.join(DATASET_FOLDERS['models'], "best.pt") +yolo_model = YOLO(YOLO_CFG) + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s [%(levelname)s] %(message)s', + handlers=[ + logging.StreamHandler(), + logging.FileHandler(os.path.join(BASE_DIR, "app.log")) # Log to a file + ] +) + + +@app.route('/') +def index(): + """Serve the main UI.""" + return render_template('index.html') + +@app.route('/upload', methods=['POST']) +def upload_image(): + """Handle image uploads.""" + if 'file' not in request.files: + return jsonify({'error': 'No file uploaded'}), 400 + file = request.files['file'] + if file.filename == '': + return jsonify({'error': 'No file selected'}), 400 + + # Save the uploaded file to the input folder + input_path = os.path.join(UPLOAD_FOLDERS['input'], file.filename) + file.save(input_path) + + # Set the uploaded image in the predictor + image = np.array(Image.open(input_path).convert("RGB")) + predictor.set_image(image) + + # Return a web-accessible URL instead of the file system path + web_accessible_url = f"/static/uploads/input/{file.filename}" + print(f"Image uploaded and set for prediction: {input_path}") + return jsonify({'image_url': web_accessible_url}) + +@app.route('/segment', methods=['POST']) +def segment(): + """ + Perform segmentation and return the blended image URL. + """ + try: + # Extract data from request + data = request.json + points = np.array(data.get('points', [])) + labels = np.array(data.get('labels', [])) + current_class = data.get('class', 'voids') # Default to 'voids' if class not provided + + # Ensure predictor has an image set + if not predictor.image_set: + raise ValueError("No image set for prediction.") + + # Perform SAM prediction + masks, _, _ = predictor.predict( + point_coords=points, + point_labels=labels, + multimask_output=False + ) + + # Check if masks exist and have non-zero elements + if masks is None or masks.size == 0: + raise RuntimeError("No masks were generated by the predictor.") + + # Define output paths based on class + mask_folder = UPLOAD_FOLDERS.get(f'mask_{current_class}') + segmented_folder = UPLOAD_FOLDERS.get(f'segmented_{current_class}') + + if not mask_folder or not segmented_folder: + raise ValueError(f"Invalid class '{current_class}' provided.") + + os.makedirs(mask_folder, exist_ok=True) + os.makedirs(segmented_folder, exist_ok=True) + + # Save the raw mask + mask_path = os.path.join(mask_folder, 'raw_mask.png') + save_mask_as_png(masks[0], mask_path) + + # Generate blended image + blend_color = [34, 139, 34] if current_class == 'voids' else [30, 144, 255] # Green for voids, blue for chips + blended_image = blend_mask_with_image(predictor.image, masks[0], blend_color) + + # Save blended image + blended_filename = f"blended_{current_class}.png" + blended_path = os.path.join(segmented_folder, blended_filename) + Image.fromarray(blended_image).save(blended_path) + + # Return URL for frontend access + segmented_url = f"/static/uploads/segmented/{current_class}/{blended_filename}" + logging.info(f"Segmentation completed for {current_class}. Points: {points}, Labels: {labels}") + return jsonify({'segmented_url': segmented_url}) + + except ValueError as ve: + logging.error(f"Value error during segmentation: {ve}") + return jsonify({'error': str(ve)}), 400 + + except Exception as e: + logging.error(f"Unexpected error during segmentation: {e}") + return jsonify({'error': 'Segmentation failed', 'details': str(e)}), 500 + +@app.route('/automatic_segment', methods=['POST']) +def automatic_segment(): + """Perform automatic segmentation using YOLO.""" + if 'file' not in request.files: + return jsonify({'error': 'No file uploaded'}), 400 + file = request.files['file'] + if file.filename == '': + return jsonify({'error': 'No file selected'}), 400 + + input_path = os.path.join(UPLOAD_FOLDERS['input'], file.filename) + file.save(input_path) + + try: + # Perform YOLO segmentation + results = yolo_model.predict(input_path, save=False, save_txt=False) + output_folder = UPLOAD_FOLDERS['automatic_segmented'] + os.makedirs(output_folder, exist_ok=True) + + chips_data = [] + chips = [] + voids = [] + + # Process results and save segmented images + for result in results: + annotated_image = result.plot() + result_filename = f"{file.filename.rsplit('.', 1)[0]}_pred.jpg" + result_path = os.path.join(output_folder, result_filename) + Image.fromarray(annotated_image).save(result_path) + + # Separate chips and voids + for i, label in enumerate(result.boxes.cls): # YOLO labels + label_name = result.names[int(label)] # Get label name (e.g., 'chip' or 'void') + box = result.boxes.xyxy[i].cpu().numpy() # Bounding box (x1, y1, x2, y2) + area = float((box[2] - box[0]) * (box[3] - box[1])) # Calculate area + + if label_name == 'chip': + chips.append({'box': box, 'area': area, 'voids': []}) + elif label_name == 'void': + voids.append({'box': box, 'area': area}) + + # Assign voids to chips based on proximity + for void in voids: + void_centroid = [ + (void['box'][0] + void['box'][2]) / 2, # x centroid + (void['box'][1] + void['box'][3]) / 2 # y centroid + ] + for chip in chips: + # Check if void centroid is within chip bounding box + if (chip['box'][0] <= void_centroid[0] <= chip['box'][2] and + chip['box'][1] <= void_centroid[1] <= chip['box'][3]): + chip['voids'].append(void) + break + + # Calculate metrics for each chip + for idx, chip in enumerate(chips): + chip_area = chip['area'] + total_void_area = sum([float(void['area']) for void in chip['voids']]) + max_void_area = max([float(void['area']) for void in chip['voids']], default=0) + + void_percentage = (total_void_area / chip_area) * 100 if chip_area > 0 else 0 + max_void_percentage = (max_void_area / chip_area) * 100 if chip_area > 0 else 0 + + chips_data.append({ + "chip_number": int(idx + 1), + "chip_area": round(chip_area, 2), + "void_percentage": round(void_percentage, 2), + "max_void_percentage": round(max_void_percentage, 2) + }) + + # Return the segmented image URL and table data + segmented_url = f"/static/uploads/segmented/automatic/{result_filename}" + return jsonify({ + "segmented_url": segmented_url, # Use the URL for frontend access + "table_data": { + "image_name": file.filename, + "chips": chips_data + } + }) + + except Exception as e: + print(f"Error in automatic segmentation: {e}") + return jsonify({'error': 'Segmentation failed.'}), 500 + +@app.route('/save_both', methods=['POST']) +def save_both(): + """Save both the image and masks into the history folders.""" + data = request.json + image_name = data.get('image_name') + + if not image_name: + return jsonify({'error': 'Image name not provided'}), 400 + + try: + # Ensure image_name is a pure file name + image_name = os.path.basename(image_name) # Strip any directory path + print(f"Sanitized Image Name: {image_name}") + + # Correctly resolve the input image path + input_image_path = os.path.join(UPLOAD_FOLDERS['input'], image_name) + if not os.path.exists(input_image_path): + print(f"Input image does not exist: {input_image_path}") + return jsonify({'error': f'Input image not found: {input_image_path}'}), 404 + + # Copy the image to history/images + image_history_path = os.path.join(HISTORY_FOLDERS['images'], image_name) + os.makedirs(os.path.dirname(image_history_path), exist_ok=True) + shutil.copy(input_image_path, image_history_path) + print(f"Image saved to history: {image_history_path}") + + # Backup void mask + void_mask_path = os.path.join(UPLOAD_FOLDERS['mask_voids'], 'raw_mask.png') + if os.path.exists(void_mask_path): + void_mask_history_path = os.path.join(HISTORY_FOLDERS['masks_void'], f"{os.path.splitext(image_name)[0]}.png") + os.makedirs(os.path.dirname(void_mask_history_path), exist_ok=True) + shutil.copy(void_mask_path, void_mask_history_path) + print(f"Voids mask saved to history: {void_mask_history_path}") + else: + print(f"Voids mask not found: {void_mask_path}") + + # Backup chip mask + chip_mask_path = os.path.join(UPLOAD_FOLDERS['mask_chips'], 'raw_mask.png') + if os.path.exists(chip_mask_path): + chip_mask_history_path = os.path.join(HISTORY_FOLDERS['masks_chip'], f"{os.path.splitext(image_name)[0]}.png") + os.makedirs(os.path.dirname(chip_mask_history_path), exist_ok=True) + shutil.copy(chip_mask_path, chip_mask_history_path) + print(f"Chips mask saved to history: {chip_mask_history_path}") + else: + print(f"Chips mask not found: {chip_mask_path}") + + return jsonify({'message': 'Image and masks saved successfully!'}), 200 + + except Exception as e: + print(f"Error saving files: {e}") + return jsonify({'error': 'Failed to save files.', 'details': str(e)}), 500 + +@app.route('/get_history', methods=['GET']) +def get_history(): + try: + saved_images = os.listdir(HISTORY_FOLDERS['images']) + return jsonify({'status': 'success', 'images': saved_images}), 200 + except Exception as e: + return jsonify({'status': 'error', 'message': f'Failed to fetch history: {e}'}), 500 + + +@app.route('/delete_history_item', methods=['POST']) +def delete_history_item(): + data = request.json + image_name = data.get('image_name') + + if not image_name: + return jsonify({'error': 'Image name not provided'}), 400 + + try: + image_path = os.path.join(HISTORY_FOLDERS['images'], image_name) + if os.path.exists(image_path): + os.remove(image_path) + + void_mask_path = os.path.join(HISTORY_FOLDERS['masks_void'], f"{os.path.splitext(image_name)[0]}.png") + if os.path.exists(void_mask_path): + os.remove(void_mask_path) + + chip_mask_path = os.path.join(HISTORY_FOLDERS['masks_chip'], f"{os.path.splitext(image_name)[0]}.png") + if os.path.exists(chip_mask_path): + os.remove(chip_mask_path) + + return jsonify({'message': f'{image_name} and associated masks deleted successfully.'}), 200 + except Exception as e: + return jsonify({'error': f'Failed to delete files: {e}'}), 500 + +# Lock for training status updates +status_lock = Lock() + +def update_training_status(key, value): + """Thread-safe update for training status.""" + with status_lock: + training_status[key] = value + +@app.route('/retrain_model', methods=['POST']) +def retrain_model(): + """Handle retrain model workflow.""" + global training_status + + if training_status.get('running', False): + return jsonify({'error': 'Training is already in progress'}), 400 + + try: + # Update training status + update_training_status('running', True) + update_training_status('cancelled', False) + logging.info("Training status updated. Starting training workflow.") + + # Backup masks and images + backup_masks_and_images() + logging.info("Backup completed successfully.") + + # Prepare YOLO labels + prepare_yolo_labels() + logging.info("YOLO labels prepared successfully.") + + # Start YOLO training in a separate thread + threading.Thread(target=run_yolo_training).start() + return jsonify({'message': 'Training started successfully!'}), 200 + + except Exception as e: + logging.error(f"Error during training preparation: {e}") + update_training_status('running', False) + return jsonify({'error': f"Failed to start training: {e}"}), 500 + +def prepare_yolo_labels(): + """Convert all masks into YOLO-compatible labels and copy images to the dataset folder.""" + images_folder = HISTORY_FOLDERS['images'] # Use history images as the source + train_labels_folder = DATASET_FOLDERS['train_labels'] + train_images_folder = DATASET_FOLDERS['train_images'] + val_labels_folder = DATASET_FOLDERS['val_labels'] + val_images_folder = DATASET_FOLDERS['val_images'] + + # Ensure destination directories exist + os.makedirs(train_labels_folder, exist_ok=True) + os.makedirs(train_images_folder, exist_ok=True) + os.makedirs(val_labels_folder, exist_ok=True) + os.makedirs(val_images_folder, exist_ok=True) + + try: + all_images = [img for img in os.listdir(images_folder) if img.endswith(('.jpg', '.png'))] + random.shuffle(all_images) # Shuffle the images for randomness + + # Determine split index + split_idx = int(len(all_images) * 0.8) # 80% for training, 20% for validation + + # Split images into train and validation sets + train_images = all_images[:split_idx] + val_images = all_images[split_idx:] + + # Process training images + for image_name in train_images: + process_image_and_mask( + image_name, + source_images_folder=images_folder, + dest_images_folder=train_images_folder, + dest_labels_folder=train_labels_folder + ) + + # Process validation images + for image_name in val_images: + process_image_and_mask( + image_name, + source_images_folder=images_folder, + dest_images_folder=val_images_folder, + dest_labels_folder=val_labels_folder + ) + + logging.info("YOLO labels prepared, and images split into train and validation successfully.") + + except Exception as e: + logging.error(f"Error in preparing YOLO labels: {e}") + raise + +import random + +def prepare_yolo_labels(): + """Convert all masks into YOLO-compatible labels and copy images to the dataset folder.""" + images_folder = HISTORY_FOLDERS['images'] # Use history images as the source + train_labels_folder = DATASET_FOLDERS['train_labels'] + train_images_folder = DATASET_FOLDERS['train_images'] + val_labels_folder = DATASET_FOLDERS['val_labels'] + val_images_folder = DATASET_FOLDERS['val_images'] + + # Ensure destination directories exist + os.makedirs(train_labels_folder, exist_ok=True) + os.makedirs(train_images_folder, exist_ok=True) + os.makedirs(val_labels_folder, exist_ok=True) + os.makedirs(val_images_folder, exist_ok=True) + + try: + all_images = [img for img in os.listdir(images_folder) if img.endswith(('.jpg', '.png'))] + random.shuffle(all_images) # Shuffle the images for randomness + + # Determine split index + split_idx = int(len(all_images) * 0.8) # 80% for training, 20% for validation + + # Split images into train and validation sets + train_images = all_images[:split_idx] + val_images = all_images[split_idx:] + + # Process training images + for image_name in train_images: + process_image_and_mask( + image_name, + source_images_folder=images_folder, + dest_images_folder=train_images_folder, + dest_labels_folder=train_labels_folder + ) + + # Process validation images + for image_name in val_images: + process_image_and_mask( + image_name, + source_images_folder=images_folder, + dest_images_folder=val_images_folder, + dest_labels_folder=val_labels_folder + ) + + logging.info("YOLO labels prepared, and images split into train and validation successfully.") + + except Exception as e: + logging.error(f"Error in preparing YOLO labels: {e}") + raise + + +def process_image_and_mask(image_name, source_images_folder, dest_images_folder, dest_labels_folder): + """ + Process a single image and its masks, saving them in the appropriate YOLO format. + """ + try: + image_path = os.path.join(source_images_folder, image_name) + label_file_path = os.path.join(dest_labels_folder, f"{os.path.splitext(image_name)[0]}.txt") + + # Copy image to the destination images folder + shutil.copy(image_path, os.path.join(dest_images_folder, image_name)) + + # Clear the label file if it exists + if os.path.exists(label_file_path): + os.remove(label_file_path) + + # Process void mask + void_mask_path = os.path.join(HISTORY_FOLDERS['masks_void'], f"{os.path.splitext(image_name)[0]}.png") + if os.path.exists(void_mask_path): + convert_mask_to_yolo( + mask_path=void_mask_path, + image_path=image_path, + class_id=0, # Void class + output_path=label_file_path + ) + + # Process chip mask + chip_mask_path = os.path.join(HISTORY_FOLDERS['masks_chip'], f"{os.path.splitext(image_name)[0]}.png") + if os.path.exists(chip_mask_path): + convert_mask_to_yolo( + mask_path=chip_mask_path, + image_path=image_path, + class_id=1, # Chip class + output_path=label_file_path, + append=True # Append chip annotations + ) + + logging.info(f"Processed {image_name} into YOLO format.") + except Exception as e: + logging.error(f"Error processing {image_name}: {e}") + raise + +def backup_masks_and_images(): + """Backup current masks and images from history folders.""" + temp_backup_paths = { + 'voids': os.path.join(DATASET_FOLDERS['temp_backup'], 'masks/voids'), + 'chips': os.path.join(DATASET_FOLDERS['temp_backup'], 'masks/chips'), + 'images': os.path.join(DATASET_FOLDERS['temp_backup'], 'images') + } + + # Prepare all backup directories + for path in temp_backup_paths.values(): + if os.path.exists(path): + shutil.rmtree(path) + os.makedirs(path, exist_ok=True) + + try: + # Backup images from history + for file in os.listdir(HISTORY_FOLDERS['images']): + src_image_path = os.path.join(HISTORY_FOLDERS['images'], file) + dst_image_path = os.path.join(temp_backup_paths['images'], file) + shutil.copy(src_image_path, dst_image_path) + + # Backup void masks from history + for file in os.listdir(HISTORY_FOLDERS['masks_void']): + src_void_path = os.path.join(HISTORY_FOLDERS['masks_void'], file) + dst_void_path = os.path.join(temp_backup_paths['voids'], file) + shutil.copy(src_void_path, dst_void_path) + + # Backup chip masks from history + for file in os.listdir(HISTORY_FOLDERS['masks_chip']): + src_chip_path = os.path.join(HISTORY_FOLDERS['masks_chip'], file) + dst_chip_path = os.path.join(temp_backup_paths['chips'], file) + shutil.copy(src_chip_path, dst_chip_path) + + logging.info("Masks and images backed up successfully from history.") + except Exception as e: + logging.error(f"Error during backup: {e}") + raise RuntimeError("Backup process failed.") + +def run_yolo_training(num_epochs=10): + """Run YOLO training process.""" + global training_process + + try: + device = "cuda" if torch.cuda.is_available() else "cpu" + data_cfg_path = os.path.join(BASE_DIR, "models/data.yaml") # Ensure correct YAML path + + logging.info(f"Starting YOLO training on {device} with {num_epochs} epochs.") + logging.info(f"Using dataset configuration: {data_cfg_path}") + + training_command = [ + "yolo", + "train", + f"data={data_cfg_path}", + f"model={os.path.join(DATASET_FOLDERS['models'], 'best.pt')}", + f"device={device}", + f"epochs={num_epochs}", + "project=runs", + "name=train" + ] + + training_process = subprocess.Popen( + training_command, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + env=os.environ.copy(), + ) + + # Display and log output in real time + for line in iter(training_process.stdout.readline, ''): + print(line.strip()) + logging.info(line.strip()) + socketio.emit('training_update', {'message': line.strip()}) # Send updates to the frontend + + training_process.wait() + + if training_process.returncode == 0: + finalize_training() # Finalize successfully completed training + else: + raise RuntimeError("YOLO training process failed. Check logs for details.") + except Exception as e: + logging.error(f"Training error: {e}") + restore_backup() # Restore the dataset and masks + + # Emit training error event to the frontend + socketio.emit('training_status', {'status': 'error', 'message': f"Training failed: {str(e)}"}) + finally: + update_training_status('running', False) + training_process = None # Reset the process + + +@socketio.on('cancel_training') +def handle_cancel_training(): + """Cancel the YOLO training process.""" + global training_process, training_status + + if not training_status.get('running', False): + socketio.emit('button_update', {'action': 'retrain'}) # Update button to retrain + return + + try: + training_process.terminate() + training_process.wait() + training_status['running'] = False + training_status['cancelled'] = True + + restore_backup() + cleanup_train_val_directories() + + # Emit button state change + socketio.emit('button_update', {'action': 'retrain'}) + socketio.emit('training_status', {'status': 'cancelled', 'message': 'Training was canceled by the user.'}) + except Exception as e: + logging.error(f"Error cancelling training: {e}") + socketio.emit('training_status', {'status': 'error', 'message': str(e)}) + +def finalize_training(): + """Finalize training by promoting the new model and cleaning up.""" + try: + # Locate the most recent training directory + runs_dir = os.path.join(BASE_DIR, 'runs') + if not os.path.exists(runs_dir): + raise FileNotFoundError("Training runs directory does not exist.") + + # Get the latest training run folder + latest_run = max( + [os.path.join(runs_dir, d) for d in os.listdir(runs_dir)], + key=os.path.getmtime + ) + weights_dir = os.path.join(latest_run, 'weights') + best_model_path = os.path.join(weights_dir, 'best.pt') + + if not os.path.exists(best_model_path): + raise FileNotFoundError(f"'best.pt' not found in {weights_dir}.") + + # Backup the old model + old_model_folder = DATASET_FOLDERS['models_old'] + os.makedirs(old_model_folder, exist_ok=True) + existing_best_model = os.path.join(DATASET_FOLDERS['models'], 'best.pt') + + if os.path.exists(existing_best_model): + timestamp = time.strftime("%Y%m%d_%H%M%S") + shutil.move(existing_best_model, os.path.join(old_model_folder, f"old_{timestamp}.pt")) + logging.info(f"Old model backed up to {old_model_folder}.") + + # Move the new model to the models directory + new_model_dest = os.path.join(DATASET_FOLDERS['models'], 'best.pt') + shutil.move(best_model_path, new_model_dest) + logging.info(f"New model saved to {new_model_dest}.") + + # Notify frontend that training is completed + socketio.emit('training_status', { + 'status': 'completed', + 'message': 'Training completed successfully! Model saved as best.pt.' + }) + + # Clean up train/val directories + cleanup_train_val_directories() + logging.info("Train and validation directories cleaned up successfully.") + + except Exception as e: + logging.error(f"Error finalizing training: {e}") + # Emit error status to the frontend + socketio.emit('training_status', {'status': 'error', 'message': f"Error finalizing training: {str(e)}"}) + +def restore_backup(): + """Restore the dataset and masks from the backup.""" + try: + temp_backup = DATASET_FOLDERS['temp_backup'] + shutil.copytree(os.path.join(temp_backup, 'masks/voids'), UPLOAD_FOLDERS['mask_voids'], dirs_exist_ok=True) + shutil.copytree(os.path.join(temp_backup, 'masks/chips'), UPLOAD_FOLDERS['mask_chips'], dirs_exist_ok=True) + shutil.copytree(os.path.join(temp_backup, 'images'), UPLOAD_FOLDERS['input'], dirs_exist_ok=True) + logging.info("Backup restored successfully.") + except Exception as e: + logging.error(f"Error restoring backup: {e}") + +@app.route('/cancel_training', methods=['POST']) +def cancel_training(): + global training_process + + if training_process is None: + logging.error("No active training process to terminate.") + return jsonify({'error': 'No active training process to cancel.'}), 400 + + try: + training_process.terminate() + training_process.wait() + training_process = None # Reset the process after termination + + # Update training status + update_training_status('running', False) + update_training_status('cancelled', True) + + # Check if the model is already saved as best.pt + best_model_path = os.path.join(DATASET_FOLDERS['models'], 'best.pt') + if os.path.exists(best_model_path): + logging.info(f"Model already saved as best.pt at {best_model_path}.") + socketio.emit('button_update', {'action': 'revert'}) # Notify frontend to revert button state + else: + logging.info("Training canceled, but no new model was saved.") + + # Restore backup if needed + restore_backup() + cleanup_train_val_directories() + + # Emit status update to frontend + socketio.emit('training_status', {'status': 'cancelled', 'message': 'Training was canceled by the user.'}) + return jsonify({'message': 'Training canceled and data restored successfully.'}), 200 + + except Exception as e: + logging.error(f"Error cancelling training: {e}") + return jsonify({'error': f"Failed to cancel training: {e}"}), 500 + +@app.route('/clear_history', methods=['POST']) +def clear_history(): + try: + for folder in [HISTORY_FOLDERS['images'], HISTORY_FOLDERS['masks_chip'], HISTORY_FOLDERS['masks_void']]: + shutil.rmtree(folder, ignore_errors=True) + os.makedirs(folder, exist_ok=True) # Recreate the empty folder + return jsonify({'message': 'History cleared successfully!'}), 200 + except Exception as e: + return jsonify({'error': f'Failed to clear history: {e}'}), 500 + +@app.route('/training_status', methods=['GET']) +def get_training_status(): + """Return the current training status.""" + if training_status.get('running', False): + return jsonify({'status': 'running', 'message': 'Training in progress.'}), 200 + elif training_status.get('cancelled', False): + return jsonify({'status': 'cancelled', 'message': 'Training was cancelled.'}), 200 + return jsonify({'status': 'idle', 'message': 'No training is currently running.'}), 200 + +def cleanup_train_val_directories(): + """Clear the train and validation directories.""" + try: + for folder in [DATASET_FOLDERS['train_images'], DATASET_FOLDERS['train_labels'], + DATASET_FOLDERS['val_images'], DATASET_FOLDERS['val_labels']]: + shutil.rmtree(folder, ignore_errors=True) # Remove folder contents + os.makedirs(folder, exist_ok=True) # Recreate empty folders + logging.info("Train and validation directories cleaned up successfully.") + except Exception as e: + logging.error(f"Error cleaning up train/val directories: {e}") + + +if __name__ == '__main__': + multiprocessing.set_start_method('spawn') # Required for multiprocessing on Windows + app.run(debug=True, use_reloader=False) + + diff --git a/dataset/.DS_Store b/dataset/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..45eee4e220351d04640aaba67c8aca91b515295b Binary files /dev/null and b/dataset/.DS_Store differ diff --git a/dataset/images/.DS_Store b/dataset/images/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..e84e195143810d17e6148f587bc19a630d3a9048 Binary files /dev/null and b/dataset/images/.DS_Store differ diff --git a/dataset/images/train/02_JPG.rf.d6063f8ca200e543da7becc1bf260ed5.jpg b/dataset/images/train/02_JPG.rf.d6063f8ca200e543da7becc1bf260ed5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d8c85c5cc11e9c183748a7d35e3c36ecb73d39ce Binary files /dev/null and b/dataset/images/train/02_JPG.rf.d6063f8ca200e543da7becc1bf260ed5.jpg differ diff --git a/dataset/images/train/03_JPG.rf.2ca107348e11cdefab68044dba66388d.jpg b/dataset/images/train/03_JPG.rf.2ca107348e11cdefab68044dba66388d.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1f896e21dd791ed02fa488ef7c10dc2777118962 Binary files /dev/null and b/dataset/images/train/03_JPG.rf.2ca107348e11cdefab68044dba66388d.jpg differ diff --git a/dataset/images/train/04_JPG.rf.b0b546ecbc6b70149b8932018e69fef0.jpg b/dataset/images/train/04_JPG.rf.b0b546ecbc6b70149b8932018e69fef0.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25373da9f2cd50afbc8ee8f7bc799aac96a40220 Binary files /dev/null and b/dataset/images/train/04_JPG.rf.b0b546ecbc6b70149b8932018e69fef0.jpg differ diff --git a/dataset/images/train/05_jpg.rf.46241369ebb0749c40882400f82eb224.jpg b/dataset/images/train/05_jpg.rf.46241369ebb0749c40882400f82eb224.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3579081555eed5deffe74a0c437f943bdc15c6d6 Binary files /dev/null and b/dataset/images/train/05_jpg.rf.46241369ebb0749c40882400f82eb224.jpg differ diff --git a/dataset/images/train/08_JPG.rf.1f81e954a3bbfc49dcd30e3ba0eb5e98.jpg b/dataset/images/train/08_JPG.rf.1f81e954a3bbfc49dcd30e3ba0eb5e98.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8c3fee5d55e85fbac7e5e21cda3751efcd5ca171 Binary files /dev/null and b/dataset/images/train/08_JPG.rf.1f81e954a3bbfc49dcd30e3ba0eb5e98.jpg differ diff --git a/dataset/images/train/09_JPG.rf.9119efd8c174f968457a893669209835.jpg b/dataset/images/train/09_JPG.rf.9119efd8c174f968457a893669209835.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9a889c4aa0a10f9b5bcd4286b13fa35e7c7535ea Binary files /dev/null and b/dataset/images/train/09_JPG.rf.9119efd8c174f968457a893669209835.jpg differ diff --git a/dataset/images/train/10_JPG.rf.6745a7b3ea828239398b85182acba199.jpg b/dataset/images/train/10_JPG.rf.6745a7b3ea828239398b85182acba199.jpg new file mode 100644 index 0000000000000000000000000000000000000000..38978a38b1cb3774a934411b3f30271b18f56830 Binary files /dev/null and b/dataset/images/train/10_JPG.rf.6745a7b3ea828239398b85182acba199.jpg differ diff --git a/dataset/images/train/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.jpg b/dataset/images/train/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ac452b8c15bf70a138cbc334e670fb75f2c4900e Binary files /dev/null and b/dataset/images/train/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.jpg differ diff --git a/dataset/images/train/12_jpg.rf.357643b374df92f81f9dee7c701b2315.jpg b/dataset/images/train/12_jpg.rf.357643b374df92f81f9dee7c701b2315.jpg new file mode 100644 index 0000000000000000000000000000000000000000..076496fd0fc67d90ad57e8d1489b4b74325d6a95 Binary files /dev/null and b/dataset/images/train/12_jpg.rf.357643b374df92f81f9dee7c701b2315.jpg differ diff --git a/dataset/images/train/14_jpg.rf.d91472c724e7c34da4d96ac5e504044c.jpg b/dataset/images/train/14_jpg.rf.d91472c724e7c34da4d96ac5e504044c.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5c9d8aab04b28cbbede78a5acf683b613aa14dd9 Binary files /dev/null and b/dataset/images/train/14_jpg.rf.d91472c724e7c34da4d96ac5e504044c.jpg differ diff --git a/dataset/images/train/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.jpg b/dataset/images/train/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4cb1ec47ff7e172bcd876582462f9667c0118c19 Binary files /dev/null and b/dataset/images/train/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.jpg differ diff --git a/dataset/images/train/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.jpg b/dataset/images/train/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3612ea8bad3b881d64ba82a7bcb3734fd0d3c301 Binary files /dev/null and b/dataset/images/train/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.jpg differ diff --git a/dataset/images/train/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.jpg b/dataset/images/train/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f7769c2afbed542791dc7aa6c99b8f731b993c3d Binary files /dev/null and b/dataset/images/train/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.jpg differ diff --git a/dataset/images/train/18_jpg.rf.4d241aab78af17171d83f3a50f1cf1aa.jpg b/dataset/images/train/18_jpg.rf.4d241aab78af17171d83f3a50f1cf1aa.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b11c87c8db424bf376c804444f39271f52c3b71f Binary files /dev/null and b/dataset/images/train/18_jpg.rf.4d241aab78af17171d83f3a50f1cf1aa.jpg differ diff --git a/dataset/images/train/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.jpg b/dataset/images/train/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6a23e88255583db9dad0ae7d84c04aee4a17d7a1 Binary files /dev/null and b/dataset/images/train/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.jpg differ diff --git a/dataset/images/train/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.jpg b/dataset/images/train/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.jpg new file mode 100644 index 0000000000000000000000000000000000000000..368daef342ad0515e373f0c051f72717bdeb2d47 Binary files /dev/null and b/dataset/images/train/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.jpg differ diff --git a/dataset/images/train/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.jpg b/dataset/images/train/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1e24609b75ed127858eb6fb66eba9d2274a09917 Binary files /dev/null and b/dataset/images/train/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.jpg differ diff --git a/dataset/images/train/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.jpg b/dataset/images/train/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.jpg new file mode 100644 index 0000000000000000000000000000000000000000..860d0363ad46861aea837591d26295477a608eac Binary files /dev/null and b/dataset/images/train/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.jpg differ diff --git a/dataset/images/train/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.jpg b/dataset/images/train/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5b357e7c557db3b68472b6f40accc04f469f33dd Binary files /dev/null and b/dataset/images/train/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.jpg differ diff --git a/dataset/images/train/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.jpg b/dataset/images/train/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9182db336422bdf0ac364af9fad89d9e0aa7ff4f Binary files /dev/null and b/dataset/images/train/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.jpg differ diff --git a/dataset/images/train/31_jpg.rf.f31137f793efde0462ed560d426dcd24.jpg b/dataset/images/train/31_jpg.rf.f31137f793efde0462ed560d426dcd24.jpg new file mode 100644 index 0000000000000000000000000000000000000000..94357eeb8c07e5d9b99e842c33e7ed46db3f4643 Binary files /dev/null and b/dataset/images/train/31_jpg.rf.f31137f793efde0462ed560d426dcd24.jpg differ diff --git a/dataset/images/train/7-Figure14-1_jpg.rf.1c6cb204ed1f37c8fed44178a02e9058.jpg b/dataset/images/train/7-Figure14-1_jpg.rf.1c6cb204ed1f37c8fed44178a02e9058.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9472eeee73b114d8aca4191a6d71caa94b3fb499 Binary files /dev/null and b/dataset/images/train/7-Figure14-1_jpg.rf.1c6cb204ed1f37c8fed44178a02e9058.jpg differ diff --git a/dataset/images/train/LU-F_mod_jpg.rf.fc594179772346639512f891960969bb.jpg b/dataset/images/train/LU-F_mod_jpg.rf.fc594179772346639512f891960969bb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6db21088484d5b0e1a559b9570231c59ee20a2d0 Binary files /dev/null and b/dataset/images/train/LU-F_mod_jpg.rf.fc594179772346639512f891960969bb.jpg differ diff --git a/dataset/images/train/Solder_Voids_jpg.rf.d40f1b71d8a801f084067fde7f33fb08.jpg b/dataset/images/train/Solder_Voids_jpg.rf.d40f1b71d8a801f084067fde7f33fb08.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3bf2f808895d944306b7b31de2584eb3646c7704 Binary files /dev/null and b/dataset/images/train/Solder_Voids_jpg.rf.d40f1b71d8a801f084067fde7f33fb08.jpg differ diff --git a/dataset/images/train/gc10_lake_voids_260-31_jpg.rf.479f3d9dda8dd22097d3d93c78f7e11d.jpg b/dataset/images/train/gc10_lake_voids_260-31_jpg.rf.479f3d9dda8dd22097d3d93c78f7e11d.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d51dd64d43f84d62af073e86b317d1963ebfe231 Binary files /dev/null and b/dataset/images/train/gc10_lake_voids_260-31_jpg.rf.479f3d9dda8dd22097d3d93c78f7e11d.jpg differ diff --git a/dataset/images/train/images_jpg.rf.675b31c5e1ba2b77f0fa5ca92e2391b0.jpg b/dataset/images/train/images_jpg.rf.675b31c5e1ba2b77f0fa5ca92e2391b0.jpg new file mode 100644 index 0000000000000000000000000000000000000000..045cca42b55430453acb0c6ab30cb76fe9380e43 Binary files /dev/null and b/dataset/images/train/images_jpg.rf.675b31c5e1ba2b77f0fa5ca92e2391b0.jpg differ diff --git a/dataset/images/train/qfn-voiding_0_jpg.rf.2945527db158e9ff4943febaf9cd3eab.jpg b/dataset/images/train/qfn-voiding_0_jpg.rf.2945527db158e9ff4943febaf9cd3eab.jpg new file mode 100644 index 0000000000000000000000000000000000000000..05a2de971994b18d531c7c29c823462999205b12 Binary files /dev/null and b/dataset/images/train/qfn-voiding_0_jpg.rf.2945527db158e9ff4943febaf9cd3eab.jpg differ diff --git a/dataset/images/train/techtips_3_jpg.rf.ad88af637816f0999f4df0b18dfef293.jpg b/dataset/images/train/techtips_3_jpg.rf.ad88af637816f0999f4df0b18dfef293.jpg new file mode 100644 index 0000000000000000000000000000000000000000..35fef586ccd3c420a1f5ccd95f492e3ddd15c06e Binary files /dev/null and b/dataset/images/train/techtips_3_jpg.rf.ad88af637816f0999f4df0b18dfef293.jpg differ diff --git a/dataset/images/val/025_JPG.rf.b2cdc2d984adff593dc985f555b8d280.jpg b/dataset/images/val/025_JPG.rf.b2cdc2d984adff593dc985f555b8d280.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eebcff406fa21c88379bddc14e7bbd558348d63c Binary files /dev/null and b/dataset/images/val/025_JPG.rf.b2cdc2d984adff593dc985f555b8d280.jpg differ diff --git a/dataset/images/val/06_jpg.rf.a94e0a678df372f5ea1395a8d888a388.jpg b/dataset/images/val/06_jpg.rf.a94e0a678df372f5ea1395a8d888a388.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5a89d78f8b015959d982c19c8e09e0cb08b11f0a Binary files /dev/null and b/dataset/images/val/06_jpg.rf.a94e0a678df372f5ea1395a8d888a388.jpg differ diff --git a/dataset/images/val/07_JPG.rf.324d17a87726bd2a9614536c687c6e68.jpg b/dataset/images/val/07_JPG.rf.324d17a87726bd2a9614536c687c6e68.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6a5e04ae573b74fe077143d2c7bb2cb5c20cf855 Binary files /dev/null and b/dataset/images/val/07_JPG.rf.324d17a87726bd2a9614536c687c6e68.jpg differ diff --git a/dataset/images/val/23_jpg.rf.8e9afa6b3b471e10c26637d47700f28b.jpg b/dataset/images/val/23_jpg.rf.8e9afa6b3b471e10c26637d47700f28b.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e9f3239f149d116ab41222cfd7101aa46cf7d186 Binary files /dev/null and b/dataset/images/val/23_jpg.rf.8e9afa6b3b471e10c26637d47700f28b.jpg differ diff --git a/dataset/images/val/24_jpg.rf.4caa996d97e35f6ce4f27a527ea43465.jpg b/dataset/images/val/24_jpg.rf.4caa996d97e35f6ce4f27a527ea43465.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1b9d307699fb320af436e1e0662e0d561902eceb Binary files /dev/null and b/dataset/images/val/24_jpg.rf.4caa996d97e35f6ce4f27a527ea43465.jpg differ diff --git a/dataset/images/val/27_jpg.rf.3475fce31d283058f46d9f349c04cb1a.jpg b/dataset/images/val/27_jpg.rf.3475fce31d283058f46d9f349c04cb1a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aa62a4a294da74b9e245a78ecdbb98746ffa6971 Binary files /dev/null and b/dataset/images/val/27_jpg.rf.3475fce31d283058f46d9f349c04cb1a.jpg differ diff --git a/dataset/images/val/28_jpg.rf.50e348d807d35667583137c9a6c162ca.jpg b/dataset/images/val/28_jpg.rf.50e348d807d35667583137c9a6c162ca.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4bfbef4475236719405a9786a9477f5b85b71112 Binary files /dev/null and b/dataset/images/val/28_jpg.rf.50e348d807d35667583137c9a6c162ca.jpg differ diff --git a/dataset/images/val/30_jpg.rf.ed72622e97cf0d884997585686cfe40a.jpg b/dataset/images/val/30_jpg.rf.ed72622e97cf0d884997585686cfe40a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5bdd14697d8cfb2781ab9ad74f96609c0d5d0b0d Binary files /dev/null and b/dataset/images/val/30_jpg.rf.ed72622e97cf0d884997585686cfe40a.jpg differ diff --git a/dataset/test/.DS_Store b/dataset/test/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..dac909f73e865879c40c05a7378d3b6e42a255b5 Binary files /dev/null and b/dataset/test/.DS_Store differ diff --git a/dataset/test/images/17_jpg.rf.ec31940ea72d0cf8b9f38dba68789fcf.jpg b/dataset/test/images/17_jpg.rf.ec31940ea72d0cf8b9f38dba68789fcf.jpg new file mode 100644 index 0000000000000000000000000000000000000000..484e06e4dd8b45c5402b8216c7b359e052757f7b Binary files /dev/null and b/dataset/test/images/17_jpg.rf.ec31940ea72d0cf8b9f38dba68789fcf.jpg differ diff --git a/dataset/test/images/19_jpg.rf.2c5ffd63bd0ce6b9b0c80fef69d101dc.jpg b/dataset/test/images/19_jpg.rf.2c5ffd63bd0ce6b9b0c80fef69d101dc.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c5fd1580a96568c55c8a2e8c807b3a2bd64a760a Binary files /dev/null and b/dataset/test/images/19_jpg.rf.2c5ffd63bd0ce6b9b0c80fef69d101dc.jpg differ diff --git a/dataset/test/images/32_jpg.rf.f3e33dcf611a8754c0765224f7873d8b.jpg b/dataset/test/images/32_jpg.rf.f3e33dcf611a8754c0765224f7873d8b.jpg new file mode 100644 index 0000000000000000000000000000000000000000..99481b46e91d12dee9f513935645ff969e728adf Binary files /dev/null and b/dataset/test/images/32_jpg.rf.f3e33dcf611a8754c0765224f7873d8b.jpg differ diff --git a/dataset/test/images/normal-reflow_jpg.rf.2c4fbc1fda915b821b85689ae257e116.jpg b/dataset/test/images/normal-reflow_jpg.rf.2c4fbc1fda915b821b85689ae257e116.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1fa35cbc1155a92288144bae6ce6022cef079da1 Binary files /dev/null and b/dataset/test/images/normal-reflow_jpg.rf.2c4fbc1fda915b821b85689ae257e116.jpg differ diff --git a/dataset/test/images/techtips_31_jpg.rf.673cd3c7c8511e534766e6dbc3171b39.jpg b/dataset/test/images/techtips_31_jpg.rf.673cd3c7c8511e534766e6dbc3171b39.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aea9d6c4fc2c5d0fe8fe8d66aebbf1d565d92eaa Binary files /dev/null and b/dataset/test/images/techtips_31_jpg.rf.673cd3c7c8511e534766e6dbc3171b39.jpg differ diff --git a/dataset/test/labels/.DS_Store b/dataset/test/labels/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 Binary files /dev/null and b/dataset/test/labels/.DS_Store differ diff --git a/dataset/test/labels/17_jpg.rf.ec31940ea72d0cf8b9f38dba68789fcf.txt b/dataset/test/labels/17_jpg.rf.ec31940ea72d0cf8b9f38dba68789fcf.txt new file mode 100644 index 0000000000000000000000000000000000000000..40994b2332a91b26245faed345cfb81b58d2698a --- /dev/null +++ b/dataset/test/labels/17_jpg.rf.ec31940ea72d0cf8b9f38dba68789fcf.txt @@ -0,0 +1,6 @@ +0 0.6859375 0.8625 0.6578125 0.8671875 0.615625 0.8390625 0.55 0.85 0.5625 0.8578125 0.5125 0.884375 0.5578125 0.8984375 0.590625 0.871875 0.575 0.9109375 0.596875 0.9109375 0.6015625 0.865625 0.6140625 0.8984375 0.6328125 0.8515625 0.6390625 0.8734375 0.6765625 0.871875 0.68125 0.8984375 +0 0.7859375 0.6375 0.4046875 0.675 0.4109375 0.75625 0.2875 0.6875 0.2875 0.75 0.2125 0.7125 0.15 0.784375 0.3234375 0.9109375 0.3296875 0.8375 +0 0.55 0.5375 0.55625 0.540625 0.55 0.5453125 0.55 0.5859375 0.596875 0.584375 0.60625 0.5984375 0.615625 0.58125 0.634375 0.5859375 0.6375 0.5734375 0.6484375 0.5734375 0.6484375 0.55625 0.6359375 0.5515625 0.634375 0.5375 0.5859375 0.5375 0.5796875 0.54375 0.5703125 0.5421875 0.578125 0.5375 +0 0.0015625 0.5375 0.0015625 0.6734375 0.0546875 0.6875 0.0625 0.7234375 0.0859375 0.696875 0.078125 0.7109375 0.09375 0.7109375 0.1109375 0.65 0.0609375 0.65 0.046875 0.615625 0.075 0.5921875 0.1109375 0.5984375 0.096875 0.5375 +0 0.7234375 0.3015625 0.671875 0.2625 0.44375 0.3015625 0.1125 0.275 0.0625 0.334375 0.265625 0.4984375 0.521875 0.4609375 +0 0.525 0.1375 0.525 0.1734375 0.5125 0.175 0.5125 0.184375 0.525 0.1828125 0.528125 0.1984375 0.5484375 0.1984375 0.5578125 0.20625 0.5515625 0.2109375 0.5625 0.2046875 0.5984375 0.2109375 0.5953125 0.2 0.6109375 0.1953125 0.6109375 0.1796875 0.6046875 0.1828125 0.6109375 0.1390625 diff --git a/dataset/test/labels/19_jpg.rf.2c5ffd63bd0ce6b9b0c80fef69d101dc.txt b/dataset/test/labels/19_jpg.rf.2c5ffd63bd0ce6b9b0c80fef69d101dc.txt new file mode 100644 index 0000000000000000000000000000000000000000..ffdd5463c0935cbcff496fd541d3c1235fa52889 --- /dev/null +++ b/dataset/test/labels/19_jpg.rf.2c5ffd63bd0ce6b9b0c80fef69d101dc.txt @@ -0,0 +1,3 @@ +0 0.625 0.6625 0.625 0.6921875 0.634375 0.6984375 0.6578125 0.6984375 0.6578125 0.69375 0.6734375 0.6984375 0.6671875 0.6953125 0.6765625 0.684375 0.7125 0.6859375 0.70625 0.684375 0.7171875 0.68125 0.715625 0.6859375 0.7234375 0.6859375 0.71875 0.675 0.7234375 0.665625 0.6703125 0.6625 0.66875 0.6671875 0.6671875 0.6625 +0 0.5625 0.6375 0.5625 0.6484375 0.5671875 0.6484375 0.5625 0.6515625 0.5625 0.665625 0.571875 0.6640625 0.5625 0.6734375 0.575 0.6734375 0.578125 0.66875 0.584375 0.671875 0.58125 0.6734375 0.5890625 0.6734375 0.5875 0.66875 0.5984375 0.6734375 0.59375 0.665625 0.5984375 0.6671875 0.6 0.659375 0.6109375 0.659375 0.6046875 0.6578125 0.6109375 0.6515625 0.6046875 0.640625 0.6109375 0.6375 +0 0.525 0.55 0.5265625 0.5609375 0.53125 0.5609375 0.525 0.565625 0.525 0.5734375 0.5265625 0.5703125 0.5328125 0.5734375 0.53125 0.56875 0.5390625 0.5703125 0.5390625 0.5734375 0.55625 0.5734375 0.5609375 0.5703125 0.5609375 0.559375 0.5578125 0.5578125 0.559375 0.553125 0.5609375 0.55625 0.5609375 0.55 0.5421875 0.55 0.5390625 0.553125 0.5359375 0.55 0.5359375 0.5546875 0.5328125 0.55 0.5328125 0.5609375 diff --git a/dataset/test/labels/32_jpg.rf.f3e33dcf611a8754c0765224f7873d8b.txt b/dataset/test/labels/32_jpg.rf.f3e33dcf611a8754c0765224f7873d8b.txt new file mode 100644 index 0000000000000000000000000000000000000000..85a8948968627cc3c10f095de093a374c6e59b5a --- /dev/null +++ b/dataset/test/labels/32_jpg.rf.f3e33dcf611a8754c0765224f7873d8b.txt @@ -0,0 +1,4 @@ +0 0.15 0.7125 0.2515625 0.8234375 0.31875 0.821875 0.3546875 0.7546875 0.3671875 0.7984375 0.39375 0.7453125 0.5 0.7734375 0.5109375 0.8328125 0.5734375 0.759375 0.4609375 0.6375 0.2796875 0.625 +0 0.85 0.2140625 0.8546875 0.225 0.85 0.2359375 0.85625 0.2265625 0.8640625 0.2484375 0.903125 0.2484375 0.9046875 0.2421875 0.9109375 0.2484375 0.909375 0.2359375 0.9234375 0.234375 0.91875 0.23125 0.9234375 0.23125 0.9234375 0.2140625 0.9078125 0.209375 0.9109375 0.2 0.9046875 0.2 0.90625 0.209375 0.903125 0.2046875 0.8734375 0.203125 0.8671875 0.2125 0.8640625 0.209375 0.871875 0.2 0.8625 0.2 0.8640625 0.2125 +0 0.6984375 0.1359375 0.628125 0.1125 0.4640625 0.18125 0.3515625 0.1375 0.3 0.2859375 0.375 0.3484375 0.559375 0.3734375 0.56875 0.2578125 +0 0.775 0.0875 0.78125 0.090625 0.775 0.0953125 0.778125 0.1015625 0.7703125 0.1 0.778125 0.1046875 0.76875 0.1078125 0.7671875 0.1 0.7640625 0.1109375 0.7734375 0.10625 0.78125 0.1109375 0.7828125 0.10625 0.7921875 0.1109375 0.7890625 0.115625 0.796875 0.1140625 0.796875 0.121875 0.7890625 0.1234375 0.809375 0.1234375 0.809375 0.1125 0.8015625 0.1140625 0.7921875 0.1046875 0.7984375 0.1015625 0.79375 0.1 0.796875 0.0953125 0.809375 0.0953125 0.809375 0.0890625 diff --git a/dataset/test/labels/normal-reflow_jpg.rf.2c4fbc1fda915b821b85689ae257e116.txt b/dataset/test/labels/normal-reflow_jpg.rf.2c4fbc1fda915b821b85689ae257e116.txt new file mode 100644 index 0000000000000000000000000000000000000000..b736c451cd079b3ca97dead276c92cdca4f09db2 --- /dev/null +++ b/dataset/test/labels/normal-reflow_jpg.rf.2c4fbc1fda915b821b85689ae257e116.txt @@ -0,0 +1,5 @@ +0 0.3875 0.6875 0.3921875 0.7328125 0.3875 0.7359375 0.39375 0.73125 0.403125 0.740625 0.4015625 0.7484375 0.4140625 0.7421875 0.4234375 0.7484375 0.4328125 0.7359375 0.4265625 0.7484375 0.4359375 0.7484375 0.434375 0.7359375 0.4484375 0.734375 0.440625 0.7296875 0.4484375 0.7234375 0.446875 0.690625 +0 0.5125 0.525 0.51875 0.528125 0.515625 0.5359375 0.5 0.5390625 0.5 0.590625 0.509375 0.5890625 0.5 0.5984375 0.5140625 0.5984375 0.509375 0.590625 0.5171875 0.5984375 0.559375 0.5984375 0.5609375 0.5390625 0.5515625 0.5453125 0.553125 0.5375 0.5203125 0.5328125 0.5203125 0.525 0.5359375 0.528125 +0 0.8328125 0.5125 0.7625 0.5125 0.675 0.59375 0.6875 0.6734375 0.746875 0.6734375 0.8484375 0.5984375 0.8609375 0.5515625 +0 0.3125 0.5 0.2875 0.5375 0.2875 0.5953125 0.3140625 0.6234375 0.396875 0.6359375 0.4359375 0.609375 0.4484375 0.55625 0.421875 0.5125 +0 0.3515625 0.1125 0.3484375 0.128125 0.3125 0.15 0.3125 0.1984375 0.3265625 0.2 0.325 0.2234375 0.3359375 0.215625 0.3421875 0.2359375 0.353125 0.2265625 0.346875 0.2359375 0.396875 0.2359375 0.4234375 0.20625 0.4234375 0.1390625 0.4109375 0.1359375 0.40625 0.1125 diff --git a/dataset/test/labels/techtips_31_jpg.rf.673cd3c7c8511e534766e6dbc3171b39.txt b/dataset/test/labels/techtips_31_jpg.rf.673cd3c7c8511e534766e6dbc3171b39.txt new file mode 100644 index 0000000000000000000000000000000000000000..d0ea5e014fd76bef3dadb2b1b6d184b48da17e61 --- /dev/null +++ b/dataset/test/labels/techtips_31_jpg.rf.673cd3c7c8511e534766e6dbc3171b39.txt @@ -0,0 +1,7 @@ +0 0.4234375 0.8015625 0.41875 0.8046875 0.4171875 0.8 0.4125 0.8015625 0.4140625 0.8109375 0.409375 0.815625 0.40625 0.815625 0.40625 0.8125 0.4 0.815625 0.4 0.8203125 0.4046875 0.81875 0.4 0.825 0.403125 0.825 0.4 0.828125 0.403125 0.8296875 0.4 0.8328125 0.403125 0.8359375 0.403125 0.8265625 0.4078125 0.8296875 0.40625 0.8359375 0.4109375 0.834375 0.4078125 0.8296875 0.4140625 0.8171875 0.415625 0.8234375 0.41875 0.8234375 0.41875 0.81875 0.421875 0.8234375 0.4203125 0.8140625 0.4234375 0.80625 0.41875 0.80625 +0 0.2984375 0.7125 0.275 0.71875 0.28125 0.7125 0.2640625 0.7 0.2625 0.71875 0.2125 0.71875 0.2125 0.784375 0.2265625 0.7875 0.225 0.7984375 0.23125 0.7875 0.2328125 0.7984375 0.284375 0.7984375 0.2875 0.7796875 0.296875 0.784375 0.3109375 0.7546875 0.309375 0.728125 0.2921875 0.725 +0 0.225 0.475 0.2296875 0.4859375 0.2125 0.4890625 0.2203125 0.49375 0.2125 0.5234375 0.2265625 0.5359375 0.234375 0.53125 0.228125 0.5484375 0.2859375 0.5484375 0.28125 0.5359375 0.2984375 0.5359375 0.2921875 0.53125 0.2984375 0.4875 0.278125 0.484375 0.284375 0.475 +0 0.8125 0.3125 0.8125 0.334375 0.81875 0.3328125 0.8125 0.359375 0.8296875 0.3625 0.825 0.4234375 0.8359375 0.4234375 0.8359375 0.3734375 0.8296875 0.3734375 0.8359375 0.365625 0.8328125 0.371875 0.828125 0.365625 0.846875 0.3609375 0.8484375 0.35 0.834375 0.3578125 0.8359375 0.3375 0.83125 0.346875 0.83125 0.3375 0.8234375 0.3390625 0.8234375 0.315625 +0 0.15 0.3140625 0.15 0.3328125 0.15625 0.3296875 0.15625 0.325 0.1640625 0.3328125 0.15 0.3390625 0.15 0.35625 0.1546875 0.3609375 0.1578125 0.3578125 0.1703125 0.3609375 0.1734375 0.3484375 0.1671875 0.3609375 0.1625 0.35625 0.1734375 0.3421875 0.1703125 0.3390625 0.1734375 0.33125 0.1671875 0.321875 0.16875 0.31875 0.1734375 0.325 0.171875 0.3125 +0 0.7140625 0.125 0.7125 0.146875 0.71875 0.1484375 0.7125 0.1609375 0.728125 0.1625 0.7125 0.165625 0.721875 0.1703125 0.7125 0.175 0.7140625 0.1859375 0.7296875 0.1859375 0.7390625 0.1765625 0.7484375 0.1796875 0.7453125 0.175 0.7296875 0.178125 0.734375 0.1625 0.7484375 0.159375 0.7484375 0.125 0.7453125 0.1296875 0.7421875 0.125 +0 0.6328125 0.125 0.65 0.23125 0.2140625 0.25 0.4140625 0.6015625 0.3390625 0.7734375 0.7984375 0.746875 0.8109375 0.3640625 diff --git a/dataset/train/labels.cache b/dataset/train/labels.cache new file mode 100644 index 0000000000000000000000000000000000000000..cda1012ebd4f054570fc6fdbc2ee0954e0d569fc Binary files /dev/null and b/dataset/train/labels.cache differ diff --git a/dataset/val/labels.cache b/dataset/val/labels.cache new file mode 100644 index 0000000000000000000000000000000000000000..288f98d1817a617d2cf4f39fac418a2d26822e0d Binary files /dev/null and b/dataset/val/labels.cache differ diff --git a/models/.DS_Store b/models/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ef0cae7a41b0ec90a90f0c6c56c15a10455c3e88 Binary files /dev/null and b/models/.DS_Store differ diff --git a/models/best.pt b/models/best.pt new file mode 100644 index 0000000000000000000000000000000000000000..a41ca2fa9d12eef772f44654d92e21b37a7594e7 --- /dev/null +++ b/models/best.pt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6c1a69f8b7ebf89dff6c8512342a91782165b0536aafdc8ffa40ded5bd647843 +size 6012957 diff --git a/models/data.yaml b/models/data.yaml new file mode 100644 index 0000000000000000000000000000000000000000..023c9eab43e613c9133ec384417f04e7d9c60718 --- /dev/null +++ b/models/data.yaml @@ -0,0 +1,7 @@ +train: C:/Users/marcv/Desktop/project/segmentation_tool/dataset/train/images +val: C:/Users/marcv/Desktop/project/segmentation_tool/dataset/val/images + +#test: dataset/test/images # Optional, for testing + +nc: 2 # Number of classes +names: ['void', 'chip'] # Class names diff --git a/models/old/old.pt b/models/old/old.pt new file mode 100644 index 0000000000000000000000000000000000000000..a41ca2fa9d12eef772f44654d92e21b37a7594e7 --- /dev/null +++ b/models/old/old.pt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6c1a69f8b7ebf89dff6c8512342a91782165b0536aafdc8ffa40ded5bd647843 +size 6012957 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..d0509b46c0d1c65bd315e66a54f6b93f8e55f32a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,9 @@ +Flask +Pillow +numpy<2 +Flask-SocketIO +Pillow +torch +torchaudio +torchvision +ultralytics diff --git a/runs/.DS_Store b/runs/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..42f24cd135e6f096fa9d63a97e722c7a39da6257 Binary files /dev/null and b/runs/.DS_Store differ diff --git a/runtime.txt b/runtime.txt new file mode 100644 index 0000000000000000000000000000000000000000..cd6f13073e4940080f1692d0e6b2e5fdb98c3a51 --- /dev/null +++ b/runtime.txt @@ -0,0 +1 @@ +python-3.11.1 \ No newline at end of file diff --git a/sam2 b/sam2 new file mode 160000 index 0000000000000000000000000000000000000000..c2ec8e14a185632b0a5d8b161928ceb50197eddc --- /dev/null +++ b/sam2 @@ -0,0 +1 @@ +Subproject commit c2ec8e14a185632b0a5d8b161928ceb50197eddc diff --git a/static/.DS_Store b/static/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..374388b3f4d13894b475f96b15f944145e8a1939 Binary files /dev/null and b/static/.DS_Store differ diff --git a/static/css/styles.css b/static/css/styles.css new file mode 100644 index 0000000000000000000000000000000000000000..a1da6afee50b4f19cb9676362b219bd3a698f8d2 --- /dev/null +++ b/static/css/styles.css @@ -0,0 +1,292 @@ +/* Import Google Fonts */ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap'); + +/* General Body Styling */ +body { + font-family: 'Inter', sans-serif; + background-color: #f4f6f8; + margin: 0; + padding: 0; + min-height: 100vh; +} + +/* Container Styling */ +.container { + max-width: 1400px; /* Widened to better fit the boxes */ + background: white; + padding: 30px; + border-radius: 16px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); + margin: 20px auto; +} + +/* Section Headers */ +h1, h2 { + font-size: 2rem; + font-weight: 700; + color: #333; + text-align: center; + margin-bottom: 20px; +} + +/* Tool Sections */ +.tool-section { + background: #fff; + border: 1px solid #ddd; + border-radius: 16px; + padding: 20px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + margin-bottom: 30px; + width: 100%; + max-width: 1200px; /* Increased to align with SAM boxes */ + margin: 20px auto; +} + +/* Buttons Styling */ +.btn-group { + display: flex; + justify-content: center; + margin-bottom: 20px; + gap: 10px; +} + +.btn-group button { + font-size: 16px; + padding: 10px 20px; + border-radius: 8px; + cursor: pointer; + transition: all 0.3s ease-in-out; + width: 50%; /* Equal button width */ +} + +.btn-group button.active { + background-color: #007bff; + color: white; + border: 1px solid #0056b3; +} + +.btn-group button:hover { + background-color: #0056b3; + color: white; +} + +/* Tool Layout */ +.tool-container { + display: flex; + flex-direction: column; + gap: 40px; + align-items: center; +} + +/* Canvas Containers */ +.canvas-container { + width: 100%; + max-width: 600px; /* Adjusted for better alignment */ + aspect-ratio: 1 / 1; + border: 2px solid #ddd; + border-radius: 16px; + background-color: #fff; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + display: flex; + justify-content: center; + align-items: center; + padding: 10px; + margin: 0 auto; +} + +/* File Upload Fields */ +input[type="file"] { + margin-top: 20px; + padding: 10px; + font-size: 16px; + border-radius: 8px; + border: 1px solid #ddd; + box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.1); + width: 100%; + max-width: 600px; +} + +input[type="file"]:focus { + border: 1px solid #007bff; + outline: none; +} + +/* Processed Image Styling */ +#automaticProcessedImage { + border: 2px solid #ddd; + border-radius: 16px; + background-color: #fff; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + width: 100%; + height: auto; + margin-top: 20px; +} + +/* Clear Points Button */ +#clearPoints { + margin-top: 20px; + font-size: 14px; + padding: 10px 15px; + border-radius: 5px; + color: white; + background-color: #dc3545; + border: none; + cursor: pointer; +} + +#clearPoints:hover { + background-color: #b52b37; +} + +/* Table Styling */ +.table { + border: 1px solid #ddd; + border-radius: 10px; + overflow: hidden; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + width: 100%; +} + +.table th { + background-color: #007bff; /* Blue column headers */ + color: white; + font-weight: bold; + text-align: center; + padding: 10px; +} + +.table td { + padding: 10px; + vertical-align: middle; + background-color: #f9f9f9; + text-align: center; +} + +.table-responsive { + border-radius: 10px; + overflow: hidden; +} + +/* Buttons Styling */ +#clearTableButton, #exportTableButton { + font-size: 16px; + padding: 10px 20px; + border-radius: 8px; + color: white; + background-color: #007bff; + border: none; + transition: all 0.3s ease-in-out; +} + +#clearTableButton:hover, #exportTableButton:hover { + background-color: #0056b3; + cursor: pointer; +} + +/* Responsive Design */ +@media screen and (max-width: 768px) { + .tool-section { + flex-direction: column; + align-items: center; + } + + .canvas-container { + margin-bottom: 20px; + } + + .btn-group button { + width: 100%; + } + + .table { + font-size: 14px; + } +} + +/* Additional Adjustments */ +.tool-section img, canvas { + max-width: 100%; + height: auto; + border-radius: 8px; +} + +#historyButton { + font-size: 16px; + padding: 10px 20px; + border-radius: 8px; + color: white; + background-color: #6c757d; /* Bootstrap secondary color */ + border: none; +} + +#historyButton:hover { + background-color: #5a6268; + cursor: pointer; +} + +/* Modal Body Styling */ +.modal-body { + padding: 15px; + width: 100%; + max-width: 600px; /* Adjust width to accommodate delete buttons */ + margin: auto; + display: flex; + flex-direction: column; + align-items: center; +} +/* History Modal List Styling */ +#historyList { + padding: 0; + margin: 0; + list-style: none; /* Remove default bullets */ + width: 100%; /* Expand list width */ +} + +/* List Group Item Styling */ +#historyList .list-group-item { + display: flex; /* Flexbox for alignment */ + justify-content: space-between; /* Space between filename and delete button */ + align-items: center; /* Vertically align items */ + padding: 10px 15px; /* Add consistent padding */ + border: 1px solid #ddd; /* Optional: border for clarity */ + border-radius: 8px; /* Rounded corners */ + background-color: #fff; /* White background for contrast */ + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */ + margin-bottom: 5px; /* Space between list items */ + width: 100%; /* Ensure full width inside modal */ +} + +/* Filename Styling */ +#historyList .filename { + flex-grow: 1; /* Allow filename to take up available space */ + text-overflow: ellipsis; /* Truncate long names */ + white-space: nowrap; /* Prevent wrapping */ + overflow: hidden; /* Hide overflowing text */ + padding-right: 15px; /* Space between filename and delete button */ +} + +/* Delete Button Styling */ +#historyList .btn-danger { + flex-shrink: 0; /* Prevent button from shrinking */ + padding: 5px 15px; + font-size: 14px; + border-radius: 8px; /* Rounded corners */ + background-color: #dc3545; /* Standard Bootstrap danger color */ + border: none; + transition: all 0.3s ease-in-out; +} + +#historyList .btn-danger:hover { + background-color: #b52b37; /* Slightly darker red on hover */ + color: white; + cursor: pointer; +} + +/* Modal Adjustments */ +.modal-dialog { + max-width: 700px; /* Wider modal dialog to fit the expanded list and delete buttons */ +} + +.modal-content { + padding: 10px; +} diff --git a/static/history/images/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.jpg b/static/history/images/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ac452b8c15bf70a138cbc334e670fb75f2c4900e Binary files /dev/null and b/static/history/images/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.jpg differ diff --git a/static/history/images/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.jpg b/static/history/images/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4cb1ec47ff7e172bcd876582462f9667c0118c19 Binary files /dev/null and b/static/history/images/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.jpg differ diff --git a/static/history/images/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.jpg b/static/history/images/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3612ea8bad3b881d64ba82a7bcb3734fd0d3c301 Binary files /dev/null and b/static/history/images/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.jpg differ diff --git a/static/history/images/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.jpg b/static/history/images/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f7769c2afbed542791dc7aa6c99b8f731b993c3d Binary files /dev/null and b/static/history/images/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.jpg differ diff --git a/static/history/images/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.jpg b/static/history/images/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6a23e88255583db9dad0ae7d84c04aee4a17d7a1 Binary files /dev/null and b/static/history/images/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.jpg differ diff --git a/static/history/images/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.jpg b/static/history/images/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.jpg new file mode 100644 index 0000000000000000000000000000000000000000..368daef342ad0515e373f0c051f72717bdeb2d47 Binary files /dev/null and b/static/history/images/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.jpg differ diff --git a/static/history/images/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.jpg b/static/history/images/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1e24609b75ed127858eb6fb66eba9d2274a09917 Binary files /dev/null and b/static/history/images/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.jpg differ diff --git a/static/history/images/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.jpg b/static/history/images/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.jpg new file mode 100644 index 0000000000000000000000000000000000000000..860d0363ad46861aea837591d26295477a608eac Binary files /dev/null and b/static/history/images/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.jpg differ diff --git a/static/history/images/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.jpg b/static/history/images/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5b357e7c557db3b68472b6f40accc04f469f33dd Binary files /dev/null and b/static/history/images/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.jpg differ diff --git a/static/history/images/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.jpg b/static/history/images/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9182db336422bdf0ac364af9fad89d9e0aa7ff4f Binary files /dev/null and b/static/history/images/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.jpg differ diff --git a/static/history/masks/chip/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png b/static/history/masks/chip/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png new file mode 100644 index 0000000000000000000000000000000000000000..cfe59a8e858cb63a75e133f959eabb1ebdc0c20b Binary files /dev/null and b/static/history/masks/chip/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png differ diff --git a/static/history/masks/chip/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png b/static/history/masks/chip/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png new file mode 100644 index 0000000000000000000000000000000000000000..9d8126856e3b0a8cbdd32ab02489700065839c4d Binary files /dev/null and b/static/history/masks/chip/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png differ diff --git a/static/history/masks/chip/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png b/static/history/masks/chip/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png new file mode 100644 index 0000000000000000000000000000000000000000..b54dd093ebc3753379df1d30325ee7232f1a653d Binary files /dev/null and b/static/history/masks/chip/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png differ diff --git a/static/history/masks/chip/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png b/static/history/masks/chip/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png new file mode 100644 index 0000000000000000000000000000000000000000..e4dbc826edcda87f39dd1998176e2162c379058c Binary files /dev/null and b/static/history/masks/chip/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png differ diff --git a/static/history/masks/chip/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png b/static/history/masks/chip/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png new file mode 100644 index 0000000000000000000000000000000000000000..b1159aa308dd01a7b4ceb1c15d3fcc27f622f193 Binary files /dev/null and b/static/history/masks/chip/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png differ diff --git a/static/history/masks/chip/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png b/static/history/masks/chip/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png new file mode 100644 index 0000000000000000000000000000000000000000..685eb010a7a3ed2820a583c6f79669735e8d2a33 Binary files /dev/null and b/static/history/masks/chip/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png differ diff --git a/static/history/masks/chip/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png b/static/history/masks/chip/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png new file mode 100644 index 0000000000000000000000000000000000000000..8e1c3e1a7e9af6d64b521e132eb24145e5b89bdb Binary files /dev/null and b/static/history/masks/chip/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png differ diff --git a/static/history/masks/chip/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png b/static/history/masks/chip/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png new file mode 100644 index 0000000000000000000000000000000000000000..49af8a089a365164655cb69ee999698285b16b31 Binary files /dev/null and b/static/history/masks/chip/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png differ diff --git a/static/history/masks/chip/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png b/static/history/masks/chip/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png new file mode 100644 index 0000000000000000000000000000000000000000..a9ba5fccb3f7f3eb5b2ce8a556812566f7d1770e Binary files /dev/null and b/static/history/masks/chip/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png differ diff --git a/static/history/masks/chip/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png b/static/history/masks/chip/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png new file mode 100644 index 0000000000000000000000000000000000000000..085353f59f871492391434d027b1f664604dcfc7 Binary files /dev/null and b/static/history/masks/chip/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png differ diff --git a/static/history/masks/void/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png b/static/history/masks/void/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png new file mode 100644 index 0000000000000000000000000000000000000000..e6fc92f551a7d60c65f2df142a541bec91870f5d Binary files /dev/null and b/static/history/masks/void/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png differ diff --git a/static/history/masks/void/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png b/static/history/masks/void/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png new file mode 100644 index 0000000000000000000000000000000000000000..a2354e965cc811518a03465c31af0c198869fd95 Binary files /dev/null and b/static/history/masks/void/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png differ diff --git a/static/history/masks/void/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png b/static/history/masks/void/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png new file mode 100644 index 0000000000000000000000000000000000000000..94ec31dbc470a83ad06750cbfc1dadacdae9e923 Binary files /dev/null and b/static/history/masks/void/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png differ diff --git a/static/history/masks/void/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png b/static/history/masks/void/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png new file mode 100644 index 0000000000000000000000000000000000000000..b373067ac59737c435e4eada9171f4498416a89f Binary files /dev/null and b/static/history/masks/void/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png differ diff --git a/static/history/masks/void/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png b/static/history/masks/void/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png new file mode 100644 index 0000000000000000000000000000000000000000..3ccdfc5a7e3612a37167a117828aa10b31bb2322 Binary files /dev/null and b/static/history/masks/void/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png differ diff --git a/static/history/masks/void/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png b/static/history/masks/void/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png new file mode 100644 index 0000000000000000000000000000000000000000..0151180865d7b664d7ffa51db606086a16f6c889 Binary files /dev/null and b/static/history/masks/void/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png differ diff --git a/static/history/masks/void/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png b/static/history/masks/void/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png new file mode 100644 index 0000000000000000000000000000000000000000..a1c195f11edd403f3dabac42760e9049808c51e7 Binary files /dev/null and b/static/history/masks/void/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png differ diff --git a/static/history/masks/void/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png b/static/history/masks/void/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png new file mode 100644 index 0000000000000000000000000000000000000000..ac8e0a95d726259518793040157782d8ce667656 Binary files /dev/null and b/static/history/masks/void/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png differ diff --git a/static/history/masks/void/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png b/static/history/masks/void/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png new file mode 100644 index 0000000000000000000000000000000000000000..cd9732adb958f28969d2d88c1fe8af3bec378f12 Binary files /dev/null and b/static/history/masks/void/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png differ diff --git a/static/history/masks/void/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png b/static/history/masks/void/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png new file mode 100644 index 0000000000000000000000000000000000000000..13afab24243cbfaf4c21271b50bc0d41c2b38b51 Binary files /dev/null and b/static/history/masks/void/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png differ diff --git a/static/js/app.js b/static/js/app.js new file mode 100644 index 0000000000000000000000000000000000000000..7197eb3451c1b7aecdaa5bc2bdc7e006963e2034 --- /dev/null +++ b/static/js/app.js @@ -0,0 +1,689 @@ +// Interactive Segmentation DOM elements +const inputCanvas = document.getElementById('inputCanvas'); +const segmentedCanvas = document.getElementById('segmentedCanvas'); +const imageUpload = document.getElementById('imageUpload'); +const clearPointsButton = document.getElementById('clearPoints'); +const voidsButton = document.getElementById('voidsButton'); +const chipsButton = document.getElementById('chipsButton'); +const retrainModelButton = document.getElementById('retrainModelButton'); +const etaDisplay = document.getElementById('etaDisplay'); + +// Automatic Segmentation DOM elements +const automaticImageUpload = document.getElementById('automaticImageUpload'); +const automaticProcessedImage = document.getElementById('automaticProcessedImage'); +const resultsTableBody = document.getElementById('resultsTableBody'); +const clearTableButton = document.getElementById('clearTableButton'); +const exportTableButton = document.getElementById('exportTableButton'); + +// Constants for consistent canvas and SAM model dimensions +const CANVAS_SIZE = 512; +inputCanvas.width = CANVAS_SIZE; +inputCanvas.height = CANVAS_SIZE; +segmentedCanvas.width = CANVAS_SIZE; +segmentedCanvas.height = CANVAS_SIZE; + +// Interactive segmentation variables +let points = { Voids: [], Chips: [] }; +let labels = { Voids: [], Chips: [] }; +let currentClass = 'Voids'; +let imageUrl = ''; +let originalImageWidth = 0; +let originalImageHeight = 0; +let trainingInProgress = false; + +// Disable right-click menu on canvas +inputCanvas.addEventListener('contextmenu', (event) => event.preventDefault()); + +// Switch between classes +voidsButton.addEventListener('click', () => { + currentClass = 'Voids'; + voidsButton.classList.add('active'); + chipsButton.classList.remove('active'); + clearAndRestorePoints(); +}); + +chipsButton.addEventListener('click', () => { + currentClass = 'Chips'; + chipsButton.classList.add('active'); + voidsButton.classList.remove('active'); + clearAndRestorePoints(); +}); + +// Handle image upload for interactive tool +imageUpload.addEventListener('change', async (event) => { + const file = event.target.files[0]; + const formData = new FormData(); + formData.append('file', file); + + try { + const response = await fetch('/upload', { method: 'POST', body: formData }); + const data = await response.json(); + if (data.error) { + console.error('Error uploading image:', data.error); + return; + } + + imageUrl = data.image_url; + console.log('Uploaded image URL:', imageUrl); + + const img = new Image(); + img.src = imageUrl; + img.onload = () => { + console.log('Image loaded:', img.width, img.height); + originalImageWidth = img.width; + originalImageHeight = img.height; + resizeAndDrawImage(inputCanvas, img); + resizeAndDrawImage(segmentedCanvas, img); + }; + img.onerror = () => { + console.error('Failed to load image from URL:', imageUrl); + }; + } catch (error) { + console.error('Failed to upload image:', error); + } +}); + + +// Handle input canvas clicks +inputCanvas.addEventListener('mousedown', async (event) => { + const rect = inputCanvas.getBoundingClientRect(); + const x = (event.clientX - rect.left) * (originalImageWidth / CANVAS_SIZE); + const y = (event.clientY - rect.top) * (originalImageHeight / CANVAS_SIZE); + + if (event.button === 2) { + points[currentClass].push([x, y]); + labels[currentClass].push(0); // Exclude point (red) + } else if (event.button === 0) { + points[currentClass].push([x, y]); + labels[currentClass].push(1); // Include point (green) + } + + drawPoints(); + await updateSegmentation(); +}); + +// Clear points for current class +clearPointsButton.addEventListener('click', () => { + points[currentClass] = []; + labels[currentClass] = []; + drawPoints(); + resetSegmentation(); +}); + +function resizeAndDrawImage(canvas, img) { + const ctx = canvas.getContext('2d'); + ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas + + // Scale the image to fit within the canvas + const scale = Math.min(canvas.width / img.width, canvas.height / img.height); + const x = (canvas.width - img.width * scale) / 2; + const y = (canvas.height - img.height * scale) / 2; + + ctx.drawImage(img, x, y, img.width * scale, img.height * scale); +} + + +// Draw points on canvases +function drawPoints() { + [inputCanvas, segmentedCanvas].forEach((canvas) => { + const ctx = canvas.getContext('2d'); + ctx.clearRect(0, 0, CANVAS_SIZE, CANVAS_SIZE); + + const img = new Image(); + img.src = imageUrl; + img.onload = () => { + resizeAndDrawImage(canvas, img); + + points[currentClass].forEach(([x, y], i) => { + const scaledX = x * (CANVAS_SIZE / originalImageWidth); + const scaledY = y * (CANVAS_SIZE / originalImageHeight); + ctx.beginPath(); + ctx.arc(scaledX, scaledY, 5, 0, 2 * Math.PI); + ctx.fillStyle = labels[currentClass][i] === 1 ? 'green' : 'red'; + ctx.fill(); + }); + }; + img.onerror = () => { + console.error('Error loading image for canvas:', img.src); + }; + }); +} + +async function updateSegmentation() { + try { + const response = await fetch('/segment', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ points: points[currentClass], labels: labels[currentClass], class: currentClass.toLowerCase() }) + }); + + const data = await response.json(); + + if (data.error) { + console.error('Error during segmentation:', data.error); + alert(`Segmentation error: ${data.error}`); + return; + } + + console.log('Segmentation result:', data); + + const img = new Image(); + img.src = `${data.segmented_url}?t=${new Date().getTime()}`; // Add timestamp to prevent caching + img.onload = () => { + console.log('Segmented image loaded successfully:', img.src); + resizeAndDrawImage(segmentedCanvas, img); // Render the segmented image + }; + img.onerror = () => { + console.error('Failed to load segmented image:', img.src); + alert('Failed to load the segmented image.'); + }; + } catch (error) { + console.error('Error updating segmentation:', error); + alert('Failed to process segmentation.'); + } +} + +// Reset segmented canvas +function resetSegmentation() { + const ctx = segmentedCanvas.getContext('2d'); + ctx.clearRect(0, 0, CANVAS_SIZE, CANVAS_SIZE); + const img = new Image(); + img.src = imageUrl; + img.onload = () => resizeAndDrawImage(segmentedCanvas, img); +} + +// Handle automatic segmentation +automaticImageUpload.addEventListener('change', async (event) => { + const file = event.target.files[0]; + const formData = new FormData(); + formData.append('file', file); + + try { + const response = await fetch('/automatic_segment', { method: 'POST', body: formData }); + const data = await response.json(); + if (data.error) return console.error('Error during automatic segmentation:', data.error); + + // Display the processed image + const processedImage = document.getElementById('automaticProcessedImage'); + processedImage.src = `${data.segmented_url}?t=${new Date().getTime()}`; + processedImage.style.display = 'block'; + + // Optionally append the table data + appendRowToTable(data.table_data); + } catch (error) { + console.error('Failed to process image automatically:', error); + } +}); + +function appendRowToTable(tableData) { + // Remove duplicates based on the image name and chip number + const existingRows = Array.from(resultsTableBody.querySelectorAll('tr')); + const existingIdentifiers = existingRows.map(row => { + const cells = row.querySelectorAll('td'); + return `${cells[0]?.textContent}_${cells[1]?.textContent}`; // Combine Image Name and Chip # + }); + + tableData.chips.forEach((chip, index) => { + const uniqueId = `${tableData.image_name}_${chip.chip_number}`; + if (existingIdentifiers.includes(uniqueId)) return; // Skip if already present + + const row = document.createElement('tr'); + + // Image Name (unchanged for each chip) + const imageNameCell = document.createElement('td'); + imageNameCell.textContent = tableData.image_name; + row.appendChild(imageNameCell); + + // Chip # (1, 2, etc.) + const chipNumberCell = document.createElement('td'); + chipNumberCell.textContent = chip.chip_number; + row.appendChild(chipNumberCell); + + // Chip Area + const chipAreaCell = document.createElement('td'); + chipAreaCell.textContent = chip.chip_area.toFixed(2); + row.appendChild(chipAreaCell); + + // Void % (Total void area / Chip area * 100) + const voidPercentageCell = document.createElement('td'); + voidPercentageCell.textContent = chip.void_percentage.toFixed(2); + row.appendChild(voidPercentageCell); + + // Max Void % (Largest void area / Chip area * 100) + const maxVoidPercentageCell = document.createElement('td'); + maxVoidPercentageCell.textContent = chip.max_void_percentage.toFixed(2); + row.appendChild(maxVoidPercentageCell); + + resultsTableBody.appendChild(row); + }); +} + +// Handle automatic segmentation +automaticImageUpload.addEventListener('change', async (event) => { + const file = event.target.files[0]; + const formData = new FormData(); + formData.append('file', file); + + try { + const response = await fetch('/automatic_segment', { method: 'POST', body: formData }); + const data = await response.json(); + if (data.error) return console.error('Error during automatic segmentation:', data.error); + + automaticProcessedImage.src = `${data.segmented_url}?t=${new Date().getTime()}`; + automaticProcessedImage.style.display = 'block'; + appendRowToTable(data.table_data); // Append new data to the table + } catch (error) { + console.error('Failed to process image automatically:', error); + } +}); + +// Clear table +clearTableButton.addEventListener('click', () => { + resultsTableBody.innerHTML = ''; +}); + +// Export table to CSV +exportTableButton.addEventListener('click', () => { + const rows = Array.from(resultsTableBody.querySelectorAll('tr')); + const csvContent = [ + ['Image Name', 'Chip #', 'Chip Area', 'Void %', 'Max Void %'], + ...rows.map(row => + Array.from(row.children).map(cell => cell.textContent) + ), + ] + .map(row => row.join(',')) + .join('\n'); + + const blob = new Blob([csvContent], { type: 'text/csv' }); + const url = URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = 'segmentation_results.csv'; + link.click(); + URL.revokeObjectURL(url); +}); +saveBothButton.addEventListener('click', async () => { + const imageName = imageUrl.split('/').pop(); // Extract the image name from the URL + if (!imageName) { + alert("No image to save."); + return; + } + + const confirmSave = confirm("Are you sure you want to save both voids and chips segmentations?"); + if (!confirmSave) return; + + try { + const response = await fetch('/save_both', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ image_name: imageName }) + }); + const result = await response.json(); + if (response.ok) { + alert(result.message); + } else { + alert("Failed to save segmentations."); + } + } catch (error) { + console.error("Error saving segmentations:", error); + alert("Failed to save segmentations."); + } +}); +// Update the "historyButton" click listener to populate the list correctly +document.getElementById('historyButton').addEventListener('click', async () => { + try { + const response = await fetch('/get_history'); // Fetch the saved history + const result = await response.json(); + + if (response.ok) { + const historyList = document.getElementById('historyList'); + historyList.innerHTML = ''; // Clear the list + + if (result.images.length === 0) { + historyList.innerHTML = '
  • No images found in history.
  • '; + return; + } + + result.images.forEach(image => { + const listItem = document.createElement('li'); + listItem.className = 'list-group-item'; + + const imageName = document.createElement('span'); + imageName.textContent = image; + + const deleteButton = document.createElement('button'); + deleteButton.className = 'btn btn-danger btn-sm'; + deleteButton.textContent = 'Delete'; + deleteButton.addEventListener('click', async () => { + if (confirm(`Are you sure you want to delete ${image}?`)) { + await deleteHistoryItem(image, listItem); + } + }); + + listItem.appendChild(imageName); + listItem.appendChild(deleteButton); + historyList.appendChild(listItem); + }); + + new bootstrap.Modal(document.getElementById('historyModal')).show(); + } else { + alert("Failed to fetch history."); + } + } catch (error) { + console.error("Error fetching history:", error); + alert("Failed to fetch history."); + } +}); + +// Function to delete history item +async function deleteHistoryItem(imageName, listItem) { + try { + const response = await fetch('/delete_history_item', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ image_name: imageName }) + }); + const result = await response.json(); + + if (response.ok) { + alert(result.message); + listItem.remove(); // Remove the item from the list + } else { + alert("Failed to delete image."); + } + } catch (error) { + console.error("Error deleting image:", error); + alert("Failed to delete image."); + } +} + +historyButton.addEventListener('click', async () => { + try { + const response = await fetch('/get_history'); + const result = await response.json(); + + if (response.ok) { + const historyList = document.getElementById('historyList'); + historyList.innerHTML = ''; // Clear the list + + if (result.images.length === 0) { + historyList.innerHTML = '
  • No images found in history.
  • '; + return; + } + + result.images.forEach(image => { + const listItem = document.createElement('li'); + listItem.className = 'list-group-item d-flex justify-content-between align-items-center'; + listItem.textContent = image; + + const deleteButton = document.createElement('button'); + deleteButton.className = 'btn btn-danger btn-sm'; + deleteButton.textContent = 'Delete'; + deleteButton.addEventListener('click', async () => { + if (confirm(`Are you sure you want to delete ${image}?`)) { + await deleteHistoryItem(image, listItem); + } + }); + + listItem.appendChild(deleteButton); + historyList.appendChild(listItem); + }); + + new bootstrap.Modal(document.getElementById('historyModal')).show(); + } else { + alert("Failed to fetch history."); + } + } catch (error) { + console.error("Error fetching history:", error); + alert("Failed to fetch history."); + } +}); + +// Function to delete history item +async function deleteHistoryItem(imageName, listItem) { + try { + const response = await fetch('/delete_history_item', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ image_name: imageName }) + }); + const result = await response.json(); + + if (response.ok) { + alert(result.message); + listItem.remove(); // Remove the item from the list + } else { + alert("Failed to delete image."); + } + } catch (error) { + console.error("Error deleting image:", error); + alert("Failed to delete image."); + } +} + +// Handle Retrain Model button click +retrainModelButton.addEventListener('click', async () => { + if (!trainingInProgress) { + const confirmRetrain = confirm("Are you sure you want to retrain the model?"); + if (!confirmRetrain) return; + + try { + const response = await fetch('/retrain_model', { method: 'POST' }); + const result = await response.json(); + + if (response.ok) { + // Update button to "Cancel Training" + trainingInProgress = true; + retrainModelButton.textContent = "Cancel Training"; + retrainModelButton.classList.replace("btn-primary", "btn-danger"); + startTrainingMonitor(); // Start monitoring the training status + } else { + alert(result.error || "Failed to start retraining."); + } + } catch (error) { + console.error("Error starting training:", error); + alert("An error occurred while starting the training process."); + } + } else { + // Handle cancel training + const confirmCancel = confirm("Are you sure you want to cancel the training?"); + if (!confirmCancel) return; + + try { + const response = await fetch('/cancel_training', { method: 'POST' }); + const result = await response.json(); + + if (response.ok) { + // Reset button to "Retrain Model" + trainingInProgress = false; + retrainModelButton.textContent = "Retrain Model"; + retrainModelButton.classList.replace("btn-danger", "btn-primary"); + alert(result.message || "Training canceled successfully."); + } else { + alert(result.error || "Failed to cancel training."); + } + } catch (error) { + console.error("Error canceling training:", error); + alert("An error occurred while canceling the training process."); + } + } +}); + + +function startTrainingMonitor() { + const monitorInterval = setInterval(async () => { + try { + const response = await fetch('/training_status'); + const result = await response.json(); + + const retrainButton = document.getElementById('retrainModelButton'); + const cancelButton = document.getElementById('cancelTrainingButton'); + const etaDisplay = document.getElementById('etaDisplay'); + + if (result.status === 'running') { + // Show training progress + retrainButton.style.display = 'none'; + cancelButton.style.display = 'inline-block'; + etaDisplay.textContent = `Estimated Time Left: ${result.eta || "Calculating..."}`; + } else if (result.status === 'idle' || result.status === 'cancelled') { + // Revert button to "Retrain Model" (blue) + cancelButton.style.display = 'none'; + retrainButton.style.display = 'inline-block'; + retrainButton.textContent = 'Retrain Model'; + retrainButton.classList.replace('btn-danger', 'btn-primary'); + etaDisplay.textContent = ''; + + // Stop monitoring if training is idle + if (result.status === 'idle') { + clearInterval(monitorInterval); + } + } + } catch (error) { + console.error("Error fetching training status:", error); + } + }, 5000); // Poll every 5 seconds +} + +function resetTrainingUI() { + trainingInProgress = false; + retrainModelButton.textContent = "Retrain Model"; + retrainModelButton.classList.replace("btn-danger", "btn-primary"); + etaDisplay.textContent = ""; +} + +clearHistoryButton.addEventListener('click', async () => { + const confirmClear = confirm("Are you sure you want to clear the history? This will delete all images and masks."); + if (!confirmClear) return; + + try { + const response = await fetch('/clear_history', { method: 'POST' }); + const result = await response.json(); + if (response.ok) { + alert(result.message); + // Optionally update UI to reflect the cleared history + const historyList = document.getElementById('historyList'); + if (historyList) historyList.innerHTML = '
  • No images found in history.
  • '; + } else { + alert("Failed to clear history."); + } + } catch (error) { + console.error("Error clearing history:", error); + alert("Failed to clear history."); + } +}); + +// Toggle training progress display +function showTrainingProgress(message = "Initializing...", timeLeft = "Calculating...") { + document.getElementById("trainingProgress").style.display = "block"; + document.getElementById("progressMessage").textContent = message; + document.getElementById("estimatedTimeLeft").textContent = `Estimated Time Left: ${timeLeft}`; +} + +function hideTrainingProgress() { + document.getElementById("trainingProgress").style.display = "none"; +} + +// Toggle Cancel Training Button +function showCancelTrainingButton() { + document.getElementById("cancelTrainingButton").style.display = "inline-block"; + document.getElementById("retrainModelButton").style.display = "none"; +} + +function hideCancelTrainingButton() { + document.getElementById("cancelTrainingButton").style.display = "none"; + document.getElementById("retrainModelButton").style.display = "inline-block"; +} + +// Add event listener to Cancel Training button +document.getElementById("cancelTrainingButton").addEventListener("click", async () => { + const confirmCancel = confirm("Are you sure you want to cancel training?"); + if (!confirmCancel) return; + + try { + const response = await fetch("/cancel_training", { method: "POST" }); + const result = await response.json(); + + if (result.message) { + alert(result.message); + hideTrainingProgress(); + hideCancelTrainingButton(); + } + } catch (error) { + console.error("Error canceling training:", error); + alert("Failed to cancel training."); + } +}); +// Handle training status updates +socket.on('training_status', (data) => { + const trainingButton = document.getElementById('retrainModelButton'); + const cancelButton = document.getElementById('cancelTrainingButton'); + + if (data.status === 'completed') { + // Update UI: change "Cancel Training" to "Retrain Model" + trainingButton.style.display = 'inline-block'; + cancelButton.style.display = 'none'; + + // Show a popup or notification for training completion + alert(data.message || "Training completed successfully!"); + } else if (data.status === 'failed') { + // Update UI: change "Cancel Training" to "Retrain Model" + trainingButton.style.display = 'inline-block'; + cancelButton.style.display = 'none'; + + // Show a popup or notification for training failure + alert(data.message || "Training failed. Please try again."); + } +}); + +socket.on('button_update', (data) => { + const retrainButton = document.getElementById('retrainModelButton'); + const cancelButton = document.getElementById('cancelTrainingButton'); + + if (data.action === 'retrain') { + // Update to "Retrain Model" button + retrainButton.style.display = 'inline-block'; + retrainButton.textContent = 'Retrain Model'; + retrainButton.classList.replace('btn-danger', 'btn-primary'); + cancelButton.style.display = 'none'; + } +}); + +function updateButtonToRetrainModel() { + const button = document.getElementById('retrainModelButton'); + button.innerText = "Retrain Model"; + button.classList.replace("btn-danger", "btn-primary"); + button.disabled = false; +} + + +socket.on('training_status', (data) => { + const retrainButton = document.getElementById('retrainModelButton'); + const cancelButton = document.getElementById('cancelTrainingButton'); + + if (data.status === 'completed') { + retrainButton.style.display = 'inline-block'; // Show retrain button + retrainButton.textContent = "Retrain Model"; + retrainButton.classList.replace("btn-danger", "btn-primary"); + cancelButton.style.display = 'none'; // Hide cancel button + + // Notify user + alert(data.message); + } else if (data.status === 'cancelled') { + retrainButton.style.display = 'inline-block'; + retrainButton.textContent = "Retrain Model"; + retrainButton.classList.replace("btn-danger", "btn-primary"); + cancelButton.style.display = 'none'; + + // Notify user + alert(data.message); + } +}); + +// Ensure the modal backdrop is properly removed when the modal is closed +document.getElementById('historyModal').addEventListener('hidden.bs.modal', function () { + document.body.classList.remove('modal-open'); + const backdrop = document.querySelector('.modal-backdrop'); + if (backdrop) { + backdrop.remove(); + } +}); diff --git a/static/uploads/input/02_JPG.rf.d6063f8ca200e543da7becc1bf260ed5.jpg b/static/uploads/input/02_JPG.rf.d6063f8ca200e543da7becc1bf260ed5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d8c85c5cc11e9c183748a7d35e3c36ecb73d39ce Binary files /dev/null and b/static/uploads/input/02_JPG.rf.d6063f8ca200e543da7becc1bf260ed5.jpg differ diff --git a/static/uploads/input/05_jpg.rf.46241369ebb0749c40882400f82eb224.jpg b/static/uploads/input/05_jpg.rf.46241369ebb0749c40882400f82eb224.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3579081555eed5deffe74a0c437f943bdc15c6d6 Binary files /dev/null and b/static/uploads/input/05_jpg.rf.46241369ebb0749c40882400f82eb224.jpg differ diff --git a/static/uploads/input/08_JPG.rf.1f81e954a3bbfc49dcd30e3ba0eb5e98.jpg b/static/uploads/input/08_JPG.rf.1f81e954a3bbfc49dcd30e3ba0eb5e98.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8c3fee5d55e85fbac7e5e21cda3751efcd5ca171 Binary files /dev/null and b/static/uploads/input/08_JPG.rf.1f81e954a3bbfc49dcd30e3ba0eb5e98.jpg differ diff --git a/static/uploads/input/10_JPG.rf.6745a7b3ea828239398b85182acba199.jpg b/static/uploads/input/10_JPG.rf.6745a7b3ea828239398b85182acba199.jpg new file mode 100644 index 0000000000000000000000000000000000000000..38978a38b1cb3774a934411b3f30271b18f56830 Binary files /dev/null and b/static/uploads/input/10_JPG.rf.6745a7b3ea828239398b85182acba199.jpg differ diff --git a/static/uploads/input/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.jpg b/static/uploads/input/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ac452b8c15bf70a138cbc334e670fb75f2c4900e Binary files /dev/null and b/static/uploads/input/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.jpg differ diff --git a/static/uploads/input/12_jpg.rf.357643b374df92f81f9dee7c701b2315.jpg b/static/uploads/input/12_jpg.rf.357643b374df92f81f9dee7c701b2315.jpg new file mode 100644 index 0000000000000000000000000000000000000000..076496fd0fc67d90ad57e8d1489b4b74325d6a95 Binary files /dev/null and b/static/uploads/input/12_jpg.rf.357643b374df92f81f9dee7c701b2315.jpg differ diff --git a/static/uploads/input/14_jpg.rf.d91472c724e7c34da4d96ac5e504044c.jpg b/static/uploads/input/14_jpg.rf.d91472c724e7c34da4d96ac5e504044c.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5c9d8aab04b28cbbede78a5acf683b613aa14dd9 Binary files /dev/null and b/static/uploads/input/14_jpg.rf.d91472c724e7c34da4d96ac5e504044c.jpg differ diff --git a/static/uploads/input/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.jpg b/static/uploads/input/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4cb1ec47ff7e172bcd876582462f9667c0118c19 Binary files /dev/null and b/static/uploads/input/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.jpg differ diff --git a/static/uploads/input/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.jpg b/static/uploads/input/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3612ea8bad3b881d64ba82a7bcb3734fd0d3c301 Binary files /dev/null and b/static/uploads/input/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.jpg differ diff --git a/static/uploads/input/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.jpg b/static/uploads/input/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f7769c2afbed542791dc7aa6c99b8f731b993c3d Binary files /dev/null and b/static/uploads/input/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.jpg differ diff --git a/static/uploads/input/18_jpg.rf.4d241aab78af17171d83f3a50f1cf1aa.jpg b/static/uploads/input/18_jpg.rf.4d241aab78af17171d83f3a50f1cf1aa.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b11c87c8db424bf376c804444f39271f52c3b71f Binary files /dev/null and b/static/uploads/input/18_jpg.rf.4d241aab78af17171d83f3a50f1cf1aa.jpg differ diff --git a/static/uploads/input/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.jpg b/static/uploads/input/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6a23e88255583db9dad0ae7d84c04aee4a17d7a1 Binary files /dev/null and b/static/uploads/input/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.jpg differ diff --git a/static/uploads/input/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.jpg b/static/uploads/input/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.jpg new file mode 100644 index 0000000000000000000000000000000000000000..368daef342ad0515e373f0c051f72717bdeb2d47 Binary files /dev/null and b/static/uploads/input/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.jpg differ diff --git a/static/uploads/input/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.jpg b/static/uploads/input/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1e24609b75ed127858eb6fb66eba9d2274a09917 Binary files /dev/null and b/static/uploads/input/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.jpg differ diff --git a/static/uploads/input/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.jpg b/static/uploads/input/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.jpg new file mode 100644 index 0000000000000000000000000000000000000000..860d0363ad46861aea837591d26295477a608eac Binary files /dev/null and b/static/uploads/input/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.jpg differ diff --git a/static/uploads/input/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.jpg b/static/uploads/input/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5b357e7c557db3b68472b6f40accc04f469f33dd Binary files /dev/null and b/static/uploads/input/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.jpg differ diff --git a/static/uploads/input/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.jpg b/static/uploads/input/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9182db336422bdf0ac364af9fad89d9e0aa7ff4f Binary files /dev/null and b/static/uploads/input/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.jpg differ diff --git a/static/uploads/input/7-Figure14-1_jpg.rf.1c6cb204ed1f37c8fed44178a02e9058.jpg b/static/uploads/input/7-Figure14-1_jpg.rf.1c6cb204ed1f37c8fed44178a02e9058.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9472eeee73b114d8aca4191a6d71caa94b3fb499 Binary files /dev/null and b/static/uploads/input/7-Figure14-1_jpg.rf.1c6cb204ed1f37c8fed44178a02e9058.jpg differ diff --git a/static/uploads/mask/chips/05_jpg.rf.46241369ebb0749c40882400f82eb224.png b/static/uploads/mask/chips/05_jpg.rf.46241369ebb0749c40882400f82eb224.png new file mode 100644 index 0000000000000000000000000000000000000000..a942f9262cdec73c5cdfdf8056be9bf00045c8e3 Binary files /dev/null and b/static/uploads/mask/chips/05_jpg.rf.46241369ebb0749c40882400f82eb224.png differ diff --git a/static/uploads/mask/chips/10_JPG.rf.6745a7b3ea828239398b85182acba199.png b/static/uploads/mask/chips/10_JPG.rf.6745a7b3ea828239398b85182acba199.png new file mode 100644 index 0000000000000000000000000000000000000000..3d210ff182291a1a3cc88cfb3340a774a685b6fb Binary files /dev/null and b/static/uploads/mask/chips/10_JPG.rf.6745a7b3ea828239398b85182acba199.png differ diff --git a/static/uploads/mask/chips/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png b/static/uploads/mask/chips/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png new file mode 100644 index 0000000000000000000000000000000000000000..cfe59a8e858cb63a75e133f959eabb1ebdc0c20b Binary files /dev/null and b/static/uploads/mask/chips/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png differ diff --git a/static/uploads/mask/chips/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png b/static/uploads/mask/chips/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png new file mode 100644 index 0000000000000000000000000000000000000000..9d8126856e3b0a8cbdd32ab02489700065839c4d Binary files /dev/null and b/static/uploads/mask/chips/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png differ diff --git a/static/uploads/mask/chips/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png b/static/uploads/mask/chips/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png new file mode 100644 index 0000000000000000000000000000000000000000..b54dd093ebc3753379df1d30325ee7232f1a653d Binary files /dev/null and b/static/uploads/mask/chips/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png differ diff --git a/static/uploads/mask/chips/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png b/static/uploads/mask/chips/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png new file mode 100644 index 0000000000000000000000000000000000000000..e4dbc826edcda87f39dd1998176e2162c379058c Binary files /dev/null and b/static/uploads/mask/chips/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png differ diff --git a/static/uploads/mask/chips/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png b/static/uploads/mask/chips/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png new file mode 100644 index 0000000000000000000000000000000000000000..b1159aa308dd01a7b4ceb1c15d3fcc27f622f193 Binary files /dev/null and b/static/uploads/mask/chips/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png differ diff --git a/static/uploads/mask/chips/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png b/static/uploads/mask/chips/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png new file mode 100644 index 0000000000000000000000000000000000000000..685eb010a7a3ed2820a583c6f79669735e8d2a33 Binary files /dev/null and b/static/uploads/mask/chips/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png differ diff --git a/static/uploads/mask/chips/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png b/static/uploads/mask/chips/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png new file mode 100644 index 0000000000000000000000000000000000000000..8e1c3e1a7e9af6d64b521e132eb24145e5b89bdb Binary files /dev/null and b/static/uploads/mask/chips/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png differ diff --git a/static/uploads/mask/chips/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png b/static/uploads/mask/chips/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png new file mode 100644 index 0000000000000000000000000000000000000000..49af8a089a365164655cb69ee999698285b16b31 Binary files /dev/null and b/static/uploads/mask/chips/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png differ diff --git a/static/uploads/mask/chips/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png b/static/uploads/mask/chips/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png new file mode 100644 index 0000000000000000000000000000000000000000..a9ba5fccb3f7f3eb5b2ce8a556812566f7d1770e Binary files /dev/null and b/static/uploads/mask/chips/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png differ diff --git a/static/uploads/mask/chips/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png b/static/uploads/mask/chips/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png new file mode 100644 index 0000000000000000000000000000000000000000..085353f59f871492391434d027b1f664604dcfc7 Binary files /dev/null and b/static/uploads/mask/chips/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png differ diff --git a/static/uploads/mask/chips/raw_mask.png b/static/uploads/mask/chips/raw_mask.png new file mode 100644 index 0000000000000000000000000000000000000000..87663ac428d4cf9c4c0b4b682e93b2817c9fd8c9 Binary files /dev/null and b/static/uploads/mask/chips/raw_mask.png differ diff --git a/static/uploads/mask/voids/05_jpg.rf.46241369ebb0749c40882400f82eb224.png b/static/uploads/mask/voids/05_jpg.rf.46241369ebb0749c40882400f82eb224.png new file mode 100644 index 0000000000000000000000000000000000000000..967594c43334b0f6d6d8cf184108f29e940d6a51 Binary files /dev/null and b/static/uploads/mask/voids/05_jpg.rf.46241369ebb0749c40882400f82eb224.png differ diff --git a/static/uploads/mask/voids/10_JPG.rf.6745a7b3ea828239398b85182acba199.png b/static/uploads/mask/voids/10_JPG.rf.6745a7b3ea828239398b85182acba199.png new file mode 100644 index 0000000000000000000000000000000000000000..535574a5d920250a287286dc4cdbd2198b503bcb Binary files /dev/null and b/static/uploads/mask/voids/10_JPG.rf.6745a7b3ea828239398b85182acba199.png differ diff --git a/static/uploads/mask/voids/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png b/static/uploads/mask/voids/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png new file mode 100644 index 0000000000000000000000000000000000000000..e6fc92f551a7d60c65f2df142a541bec91870f5d Binary files /dev/null and b/static/uploads/mask/voids/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png differ diff --git a/static/uploads/mask/voids/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png b/static/uploads/mask/voids/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png new file mode 100644 index 0000000000000000000000000000000000000000..a2354e965cc811518a03465c31af0c198869fd95 Binary files /dev/null and b/static/uploads/mask/voids/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png differ diff --git a/static/uploads/mask/voids/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png b/static/uploads/mask/voids/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png new file mode 100644 index 0000000000000000000000000000000000000000..94ec31dbc470a83ad06750cbfc1dadacdae9e923 Binary files /dev/null and b/static/uploads/mask/voids/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png differ diff --git a/static/uploads/mask/voids/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png b/static/uploads/mask/voids/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png new file mode 100644 index 0000000000000000000000000000000000000000..b373067ac59737c435e4eada9171f4498416a89f Binary files /dev/null and b/static/uploads/mask/voids/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png differ diff --git a/static/uploads/mask/voids/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png b/static/uploads/mask/voids/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png new file mode 100644 index 0000000000000000000000000000000000000000..3ccdfc5a7e3612a37167a117828aa10b31bb2322 Binary files /dev/null and b/static/uploads/mask/voids/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png differ diff --git a/static/uploads/mask/voids/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png b/static/uploads/mask/voids/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png new file mode 100644 index 0000000000000000000000000000000000000000..0151180865d7b664d7ffa51db606086a16f6c889 Binary files /dev/null and b/static/uploads/mask/voids/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png differ diff --git a/static/uploads/mask/voids/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png b/static/uploads/mask/voids/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png new file mode 100644 index 0000000000000000000000000000000000000000..a1c195f11edd403f3dabac42760e9049808c51e7 Binary files /dev/null and b/static/uploads/mask/voids/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png differ diff --git a/static/uploads/mask/voids/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png b/static/uploads/mask/voids/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png new file mode 100644 index 0000000000000000000000000000000000000000..ac8e0a95d726259518793040157782d8ce667656 Binary files /dev/null and b/static/uploads/mask/voids/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png differ diff --git a/static/uploads/mask/voids/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png b/static/uploads/mask/voids/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png new file mode 100644 index 0000000000000000000000000000000000000000..cd9732adb958f28969d2d88c1fe8af3bec378f12 Binary files /dev/null and b/static/uploads/mask/voids/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png differ diff --git a/static/uploads/mask/voids/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png b/static/uploads/mask/voids/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png new file mode 100644 index 0000000000000000000000000000000000000000..13afab24243cbfaf4c21271b50bc0d41c2b38b51 Binary files /dev/null and b/static/uploads/mask/voids/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png differ diff --git a/static/uploads/mask/voids/raw_mask.png b/static/uploads/mask/voids/raw_mask.png new file mode 100644 index 0000000000000000000000000000000000000000..5b197214b627eb2d8ab6de48a1c110b4ae4ad0af Binary files /dev/null and b/static/uploads/mask/voids/raw_mask.png differ diff --git a/static/uploads/segmented/automatic/02_JPG.rf.d6063f8ca200e543da7becc1bf260ed5_pred.jpg b/static/uploads/segmented/automatic/02_JPG.rf.d6063f8ca200e543da7becc1bf260ed5_pred.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c6780664033acc985c09c1ce3c595467e9e3e0a5 Binary files /dev/null and b/static/uploads/segmented/automatic/02_JPG.rf.d6063f8ca200e543da7becc1bf260ed5_pred.jpg differ diff --git a/static/uploads/segmented/automatic/08_JPG.rf.1f81e954a3bbfc49dcd30e3ba0eb5e98_pred.jpg b/static/uploads/segmented/automatic/08_JPG.rf.1f81e954a3bbfc49dcd30e3ba0eb5e98_pred.jpg new file mode 100644 index 0000000000000000000000000000000000000000..53fa958e7a2dc661029ce443e99b6dec9f47f065 Binary files /dev/null and b/static/uploads/segmented/automatic/08_JPG.rf.1f81e954a3bbfc49dcd30e3ba0eb5e98_pred.jpg differ diff --git a/static/uploads/segmented/automatic/09_JPG.rf.9119efd8c174f968457a893669209835_pred.jpg b/static/uploads/segmented/automatic/09_JPG.rf.9119efd8c174f968457a893669209835_pred.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a235f3b90e22425392701edf2512e7bb6cc7d683 Binary files /dev/null and b/static/uploads/segmented/automatic/09_JPG.rf.9119efd8c174f968457a893669209835_pred.jpg differ diff --git a/static/uploads/segmented/automatic/10_JPG.rf.6745a7b3ea828239398b85182acba199_pred.jpg b/static/uploads/segmented/automatic/10_JPG.rf.6745a7b3ea828239398b85182acba199_pred.jpg new file mode 100644 index 0000000000000000000000000000000000000000..54c0b310d17de83cf0df43b1fb36b363c14ad4d9 Binary files /dev/null and b/static/uploads/segmented/automatic/10_JPG.rf.6745a7b3ea828239398b85182acba199_pred.jpg differ diff --git a/static/uploads/segmented/automatic/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb_pred.jpg b/static/uploads/segmented/automatic/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb_pred.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f8e7cd3c134a1f41a87448bf764a2dc18468315b Binary files /dev/null and b/static/uploads/segmented/automatic/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb_pred.jpg differ diff --git a/static/uploads/segmented/automatic/12_jpg.rf.357643b374df92f81f9dee7c701b2315_pred.jpg b/static/uploads/segmented/automatic/12_jpg.rf.357643b374df92f81f9dee7c701b2315_pred.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9d8b448d79abde4a5eddea506ac44eb0ec7721ec Binary files /dev/null and b/static/uploads/segmented/automatic/12_jpg.rf.357643b374df92f81f9dee7c701b2315_pred.jpg differ diff --git a/static/uploads/segmented/automatic/14_jpg.rf.d91472c724e7c34da4d96ac5e504044c_pred.jpg b/static/uploads/segmented/automatic/14_jpg.rf.d91472c724e7c34da4d96ac5e504044c_pred.jpg new file mode 100644 index 0000000000000000000000000000000000000000..96f4bc949ef48c41321d654a339ad008cbde48ee Binary files /dev/null and b/static/uploads/segmented/automatic/14_jpg.rf.d91472c724e7c34da4d96ac5e504044c_pred.jpg differ diff --git a/static/uploads/segmented/automatic/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0_pred.jpg b/static/uploads/segmented/automatic/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0_pred.jpg new file mode 100644 index 0000000000000000000000000000000000000000..65ca5e28eab24cd07c90db185b164c62f9071525 Binary files /dev/null and b/static/uploads/segmented/automatic/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0_pred.jpg differ diff --git a/static/uploads/segmented/automatic/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536_pred.jpg b/static/uploads/segmented/automatic/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536_pred.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c80f32e508a2a2e25a60c8d0cd3710cd05e44158 Binary files /dev/null and b/static/uploads/segmented/automatic/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536_pred.jpg differ diff --git a/static/uploads/segmented/automatic/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba_pred.jpg b/static/uploads/segmented/automatic/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba_pred.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3a4ecae049c42c8f160146bedb05d1cb67279e98 Binary files /dev/null and b/static/uploads/segmented/automatic/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba_pred.jpg differ diff --git a/static/uploads/segmented/automatic/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147_pred.jpg b/static/uploads/segmented/automatic/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147_pred.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cea7467ea27a4b62cb024a0d7b67c976c83f5850 Binary files /dev/null and b/static/uploads/segmented/automatic/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147_pred.jpg differ diff --git a/static/uploads/segmented/automatic/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab_pred.jpg b/static/uploads/segmented/automatic/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab_pred.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bd37ca630143244d2b5cbfb7a3d7b24dd0abd9f3 Binary files /dev/null and b/static/uploads/segmented/automatic/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab_pred.jpg differ diff --git a/static/uploads/segmented/automatic/29_jpg.rf.931769b58ae20d18d1f09d042bc44176_pred.jpg b/static/uploads/segmented/automatic/29_jpg.rf.931769b58ae20d18d1f09d042bc44176_pred.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7c8091d61aed18b2ba2177175359a893911d752e Binary files /dev/null and b/static/uploads/segmented/automatic/29_jpg.rf.931769b58ae20d18d1f09d042bc44176_pred.jpg differ diff --git a/static/uploads/segmented/automatic/7-Figure14-1_jpg.rf.1c6cb204ed1f37c8fed44178a02e9058_pred.jpg b/static/uploads/segmented/automatic/7-Figure14-1_jpg.rf.1c6cb204ed1f37c8fed44178a02e9058_pred.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ac40c44b30a36c7dc1ab15f4b36e8b918ffaf030 Binary files /dev/null and b/static/uploads/segmented/automatic/7-Figure14-1_jpg.rf.1c6cb204ed1f37c8fed44178a02e9058_pred.jpg differ diff --git a/static/uploads/segmented/chips/blended_chips.png b/static/uploads/segmented/chips/blended_chips.png new file mode 100644 index 0000000000000000000000000000000000000000..160bc0e96af90d18a99e7bdc59840fc74a0aa686 Binary files /dev/null and b/static/uploads/segmented/chips/blended_chips.png differ diff --git a/static/uploads/segmented/chips/blended_image.png b/static/uploads/segmented/chips/blended_image.png new file mode 100644 index 0000000000000000000000000000000000000000..1d8fbf1814f362d4cdf5b637de25362befe3ed4d Binary files /dev/null and b/static/uploads/segmented/chips/blended_image.png differ diff --git a/static/uploads/segmented/voids/blended_image.png b/static/uploads/segmented/voids/blended_image.png new file mode 100644 index 0000000000000000000000000000000000000000..45b729389e40cc9aa196311076af6305de5ea98d Binary files /dev/null and b/static/uploads/segmented/voids/blended_image.png differ diff --git a/static/uploads/segmented/voids/blended_voids.png b/static/uploads/segmented/voids/blended_voids.png new file mode 100644 index 0000000000000000000000000000000000000000..9aadb2a2d3bf8b8ca8cbecc64be92a27168a2052 Binary files /dev/null and b/static/uploads/segmented/voids/blended_voids.png differ diff --git a/temp_backup/.DS_Store b/temp_backup/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ad89615ad548a34663c2e49a0e40671136a26d5a Binary files /dev/null and b/temp_backup/.DS_Store differ diff --git a/temp_backup/images/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.jpg b/temp_backup/images/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ac452b8c15bf70a138cbc334e670fb75f2c4900e Binary files /dev/null and b/temp_backup/images/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.jpg differ diff --git a/temp_backup/images/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.jpg b/temp_backup/images/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4cb1ec47ff7e172bcd876582462f9667c0118c19 Binary files /dev/null and b/temp_backup/images/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.jpg differ diff --git a/temp_backup/images/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.jpg b/temp_backup/images/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3612ea8bad3b881d64ba82a7bcb3734fd0d3c301 Binary files /dev/null and b/temp_backup/images/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.jpg differ diff --git a/temp_backup/images/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.jpg b/temp_backup/images/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f7769c2afbed542791dc7aa6c99b8f731b993c3d Binary files /dev/null and b/temp_backup/images/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.jpg differ diff --git a/temp_backup/images/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.jpg b/temp_backup/images/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6a23e88255583db9dad0ae7d84c04aee4a17d7a1 Binary files /dev/null and b/temp_backup/images/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.jpg differ diff --git a/temp_backup/images/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.jpg b/temp_backup/images/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.jpg new file mode 100644 index 0000000000000000000000000000000000000000..368daef342ad0515e373f0c051f72717bdeb2d47 Binary files /dev/null and b/temp_backup/images/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.jpg differ diff --git a/temp_backup/images/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.jpg b/temp_backup/images/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1e24609b75ed127858eb6fb66eba9d2274a09917 Binary files /dev/null and b/temp_backup/images/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.jpg differ diff --git a/temp_backup/images/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.jpg b/temp_backup/images/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.jpg new file mode 100644 index 0000000000000000000000000000000000000000..860d0363ad46861aea837591d26295477a608eac Binary files /dev/null and b/temp_backup/images/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.jpg differ diff --git a/temp_backup/images/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.jpg b/temp_backup/images/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5b357e7c557db3b68472b6f40accc04f469f33dd Binary files /dev/null and b/temp_backup/images/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.jpg differ diff --git a/temp_backup/images/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.jpg b/temp_backup/images/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9182db336422bdf0ac364af9fad89d9e0aa7ff4f Binary files /dev/null and b/temp_backup/images/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.jpg differ diff --git a/temp_backup/masks/chips/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png b/temp_backup/masks/chips/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png new file mode 100644 index 0000000000000000000000000000000000000000..cfe59a8e858cb63a75e133f959eabb1ebdc0c20b Binary files /dev/null and b/temp_backup/masks/chips/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png differ diff --git a/temp_backup/masks/chips/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png b/temp_backup/masks/chips/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png new file mode 100644 index 0000000000000000000000000000000000000000..9d8126856e3b0a8cbdd32ab02489700065839c4d Binary files /dev/null and b/temp_backup/masks/chips/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png differ diff --git a/temp_backup/masks/chips/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png b/temp_backup/masks/chips/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png new file mode 100644 index 0000000000000000000000000000000000000000..b54dd093ebc3753379df1d30325ee7232f1a653d Binary files /dev/null and b/temp_backup/masks/chips/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png differ diff --git a/temp_backup/masks/chips/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png b/temp_backup/masks/chips/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png new file mode 100644 index 0000000000000000000000000000000000000000..e4dbc826edcda87f39dd1998176e2162c379058c Binary files /dev/null and b/temp_backup/masks/chips/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png differ diff --git a/temp_backup/masks/chips/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png b/temp_backup/masks/chips/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png new file mode 100644 index 0000000000000000000000000000000000000000..b1159aa308dd01a7b4ceb1c15d3fcc27f622f193 Binary files /dev/null and b/temp_backup/masks/chips/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png differ diff --git a/temp_backup/masks/chips/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png b/temp_backup/masks/chips/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png new file mode 100644 index 0000000000000000000000000000000000000000..685eb010a7a3ed2820a583c6f79669735e8d2a33 Binary files /dev/null and b/temp_backup/masks/chips/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png differ diff --git a/temp_backup/masks/chips/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png b/temp_backup/masks/chips/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png new file mode 100644 index 0000000000000000000000000000000000000000..8e1c3e1a7e9af6d64b521e132eb24145e5b89bdb Binary files /dev/null and b/temp_backup/masks/chips/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png differ diff --git a/temp_backup/masks/chips/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png b/temp_backup/masks/chips/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png new file mode 100644 index 0000000000000000000000000000000000000000..49af8a089a365164655cb69ee999698285b16b31 Binary files /dev/null and b/temp_backup/masks/chips/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png differ diff --git a/temp_backup/masks/chips/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png b/temp_backup/masks/chips/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png new file mode 100644 index 0000000000000000000000000000000000000000..a9ba5fccb3f7f3eb5b2ce8a556812566f7d1770e Binary files /dev/null and b/temp_backup/masks/chips/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png differ diff --git a/temp_backup/masks/chips/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png b/temp_backup/masks/chips/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png new file mode 100644 index 0000000000000000000000000000000000000000..085353f59f871492391434d027b1f664604dcfc7 Binary files /dev/null and b/temp_backup/masks/chips/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png differ diff --git a/temp_backup/masks/voids/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png b/temp_backup/masks/voids/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png new file mode 100644 index 0000000000000000000000000000000000000000..e6fc92f551a7d60c65f2df142a541bec91870f5d Binary files /dev/null and b/temp_backup/masks/voids/11_JPG.rf.3aa3109a1838549cf273cdbe8b2cafeb.png differ diff --git a/temp_backup/masks/voids/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png b/temp_backup/masks/voids/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png new file mode 100644 index 0000000000000000000000000000000000000000..a2354e965cc811518a03465c31af0c198869fd95 Binary files /dev/null and b/temp_backup/masks/voids/15_jpg.rf.284413e4432b16253b4cd19f0c4f01e2.png differ diff --git a/temp_backup/masks/voids/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png b/temp_backup/masks/voids/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png new file mode 100644 index 0000000000000000000000000000000000000000..94ec31dbc470a83ad06750cbfc1dadacdae9e923 Binary files /dev/null and b/temp_backup/masks/voids/15r_jpg.rf.2da1990173346311d3a3555e23a9164a.png differ diff --git a/temp_backup/masks/voids/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png b/temp_backup/masks/voids/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png new file mode 100644 index 0000000000000000000000000000000000000000..b373067ac59737c435e4eada9171f4498416a89f Binary files /dev/null and b/temp_backup/masks/voids/16_jpg.rf.9fdb4f56ec8596ddcc31db5bbffc26a0.png differ diff --git a/temp_backup/masks/voids/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png b/temp_backup/masks/voids/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png new file mode 100644 index 0000000000000000000000000000000000000000..3ccdfc5a7e3612a37167a117828aa10b31bb2322 Binary files /dev/null and b/temp_backup/masks/voids/20_jpg.rf.4a45f799ba16b5ff81ab1929f12a12b1.png differ diff --git a/temp_backup/masks/voids/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png b/temp_backup/masks/voids/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png new file mode 100644 index 0000000000000000000000000000000000000000..0151180865d7b664d7ffa51db606086a16f6c889 Binary files /dev/null and b/temp_backup/masks/voids/21_jpg.rf.d1d6dd254d2e5f396589ccc68a3c8536.png differ diff --git a/temp_backup/masks/voids/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png b/temp_backup/masks/voids/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png new file mode 100644 index 0000000000000000000000000000000000000000..a1c195f11edd403f3dabac42760e9049808c51e7 Binary files /dev/null and b/temp_backup/masks/voids/22_jpg.rf.a72964a78ea36c7bebe3a09cf27ef6ba.png differ diff --git a/temp_backup/masks/voids/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png b/temp_backup/masks/voids/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png new file mode 100644 index 0000000000000000000000000000000000000000..ac8e0a95d726259518793040157782d8ce667656 Binary files /dev/null and b/temp_backup/masks/voids/25_jpg.rf.893f4286e0c8a3cef2efb7612f248147.png differ diff --git a/temp_backup/masks/voids/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png b/temp_backup/masks/voids/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png new file mode 100644 index 0000000000000000000000000000000000000000..cd9732adb958f28969d2d88c1fe8af3bec378f12 Binary files /dev/null and b/temp_backup/masks/voids/26_jpg.rf.a03c550707ff22cd50ff7f54bebda7ab.png differ diff --git a/temp_backup/masks/voids/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png b/temp_backup/masks/voids/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png new file mode 100644 index 0000000000000000000000000000000000000000..13afab24243cbfaf4c21271b50bc0d41c2b38b51 Binary files /dev/null and b/temp_backup/masks/voids/29_jpg.rf.931769b58ae20d18d1f09d042bc44176.png differ diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000000000000000000000000000000000000..cbf5c21141d33d37be214a5f598faad99e93d23d --- /dev/null +++ b/templates/index.html @@ -0,0 +1,137 @@ + + + + + + Segmentation Tools + + + + +
    + +

    Segmentation Tools

    + + +
    +

    Interactive Segmentation Tool

    +
    + + +
    +
    +
    +
    Input Image
    +
    + +
    + +
    +
    +
    Segmented Image
    +
    + +
    +
    + + + + + +
    +
    +
    + +
    + + + + + +
    +

    Automatic Segmentation Tool

    +
    +
    +
    Input Image
    + +
    +
    +
    Processed Image
    +
    + +
    +
    +
    +
    + + +
    +

    Segmentation Results

    + + + + + + + + + + + + + +
    Image NameChip #Chip AreaVoid %Max Void %
    +
    + + +
    +
    +
    + + + + + + + + + + diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/utils/__pycache__/__init__.cpython-311.pyc b/utils/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7471c80806948ab99a064501a26cfe7dc8ccd3ae Binary files /dev/null and b/utils/__pycache__/__init__.cpython-311.pyc differ diff --git a/utils/__pycache__/helpers.cpython-311.pyc b/utils/__pycache__/helpers.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..184f8d72303fed8f7c7f52427fe8ea12b9b20f24 Binary files /dev/null and b/utils/__pycache__/helpers.cpython-311.pyc differ diff --git a/utils/__pycache__/predictor.cpython-311.pyc b/utils/__pycache__/predictor.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e9b4bcb5833e2f0a6243900d0e56562f56922a16 Binary files /dev/null and b/utils/__pycache__/predictor.cpython-311.pyc differ diff --git a/utils/helpers.py b/utils/helpers.py new file mode 100644 index 0000000000000000000000000000000000000000..129147f109dc13541220e126be1ab7e9b43f8f7d --- /dev/null +++ b/utils/helpers.py @@ -0,0 +1,74 @@ +import numpy as np +from PIL import Image +import cv2 +import os +import shutil + +def blend_mask_with_image(image, mask, color): + """Blend the mask with the original image using a transparent color overlay.""" + mask_rgb = np.stack([mask * color[i] for i in range(3)], axis=-1) + blended = (0.7 * image + 0.3 * mask_rgb).astype(np.uint8) + return blended + +def save_mask_as_png(mask, path): + """Save the binary mask as a PNG.""" + mask_image = Image.fromarray((mask * 255).astype(np.uint8)) + mask_image.save(path) + +def convert_mask_to_yolo(mask_path, image_path, class_id, output_path, append=False): + """ + Convert a binary mask to YOLO-compatible segmentation labels. + + Args: + mask_path (str): Path to the binary mask image. + image_path (str): Path to the corresponding image. + class_id (int): Class ID (e.g., 0 for void, 1 for chip). + output_path (str): Path to save the YOLO label (.txt) file. + append (bool): Whether to append labels to the file. + + Returns: + None + """ + try: + # Load the binary mask + mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) + if mask is None: + raise ValueError(f"Mask not found or invalid: {mask_path}") + + # Load the corresponding image to get dimensions + image = cv2.imread(image_path) + if image is None: + raise ValueError(f"Image not found or invalid: {image_path}") + + h, w = image.shape[:2] # Image height and width + + # Find contours in the mask + contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + + # Determine file mode: "w" for overwrite or "a" for append + file_mode = "a" if append else "w" + + # Open the output .txt file + with open(output_path, file_mode) as label_file: + for contour in contours: + # Simplify the contour points to reduce the number of vertices + epsilon = 0.01 * cv2.arcLength(contour, True) # Tolerance for approximation + contour = cv2.approxPolyDP(contour, epsilon, True) + + # Normalize contour points (polygon vertices) + normalized_vertices = [] + for point in contour: + x, y = point[0] # Extract x, y from the point + x_normalized = x / w + y_normalized = y / h + normalized_vertices.extend([x_normalized, y_normalized]) + + # Write the polygon annotation to the label file + if len(normalized_vertices) >= 6: # At least 3 points required for a polygon + label_file.write(f"{class_id} " + " ".join(f"{v:.6f}" for v in normalized_vertices) + "\n") + + print(f"YOLO segmentation label saved: {output_path}") + + except Exception as e: + print(f"Error converting mask to YOLO format: {e}") + raise RuntimeError(f"Failed to convert {mask_path} for class {class_id}: {e}") diff --git a/utils/predictor.py b/utils/predictor.py new file mode 100644 index 0000000000000000000000000000000000000000..0e0e358117a71ea711b1d221034341a23599f0f0 --- /dev/null +++ b/utils/predictor.py @@ -0,0 +1,26 @@ +import numpy as np +from sam2.build_sam import build_sam2 +from sam2.sam2_image_predictor import SAM2ImagePredictor + +class Predictor: + def __init__(self, model_cfg, checkpoint, device): + self.device = device + self.model = build_sam2(model_cfg, checkpoint, device=device) + self.predictor = SAM2ImagePredictor(self.model) + self.image_set = False + + def set_image(self, image): + """Set the image for SAM prediction.""" + self.image = image + self.predictor.set_image(image) + self.image_set = True + + def predict(self, point_coords, point_labels, multimask_output=False): + """Run SAM prediction.""" + if not self.image_set: + raise RuntimeError("An image must be set with .set_image(...) before mask prediction.") + return self.predictor.predict( + point_coords=point_coords, + point_labels=point_labels, + multimask_output=multimask_output + ) diff --git a/yolo11n.pt b/yolo11n.pt new file mode 100644 index 0000000000000000000000000000000000000000..c7723db027d009343e9682f261370833fd6f0d84 --- /dev/null +++ b/yolo11n.pt @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0ebbc80d4a7680d14987a577cd21342b65ecfd94632bd9a8da63ae6417644ee1 +size 5613764