{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":8991269,"sourceType":"datasetVersion","datasetId":5415544},{"sourceId":10990941,"sourceType":"datasetVersion","datasetId":6841033},{"sourceId":320292,"sourceType":"modelInstanceVersion","modelInstanceId":270160,"modelId":291147}],"dockerImageVersionId":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## **DATASET AUGMENTATION**","metadata":{}},{"cell_type":"markdown","source":"**NO NEEDED TO AUGMENT AS ALREADY AUGMENTED DATASET UPLOADED**","metadata":{}},{"cell_type":"code","source":"# import os\n# import cv2\n# import numpy as np\n# from imgaug import augmenters as iaa\n# from tqdm import tqdm\n\n# # === CONFIG ===\n# input_dir = \"/kaggle/input/drsegfinaldataset/Augmented\"        # Folder with your 54 original images\n# output_dir = \"/kaggle/working/NonAugmented\"       \n# augmentations_per_image = 8            # 1 original + 8 augmentations = 9 total\n\n# # Create output folder\n# os.makedirs(output_dir, exist_ok=True)\n\n# # Define a sequence of augmentations\n# augmentation_seq = iaa.SomeOf((2, 4), [\n#     iaa.Fliplr(0.5),                        # Horizontal flip\n#     iaa.Flipud(0.5),                        # Vertical flip\n#     iaa.Affine(rotate=(-25, 25)),          # Rotation\n#     iaa.Affine(scale=(0.8, 1.2)),          # Zoom in/out\n#     iaa.Multiply((0.8, 1.2)),              # Brightness\n#     iaa.GaussianBlur(sigma=(0.0, 1.0)),    # Blur\n#     iaa.AdditiveGaussianNoise(scale=(5, 15)), # Noise\n#     iaa.ContrastNormalization((0.8, 1.2)), # Contrast\n# ])\n\n# # Load and augment images\n# image_files = [f for f in os.listdir(input_dir) if f.lower().endswith(('.png', '.jpg', '.jpeg'))]\n\n# for img_file in tqdm(image_files):\n#     img_path = os.path.join(input_dir, img_file)\n#     image = cv2.imread(img_path)\n#     if image is None:\n#         continue\n\n#     base_name = os.path.splitext(img_file)[0]\n#     cv2.imwrite(os.path.join(output_dir, f\"{base_name}_orig.jpg\"), image)\n\n#     for i in range(augmentations_per_image):\n#         aug_image = augmentation_seq(image=image)\n#         aug_name = f\"{base_name}_aug{i+1}.jpg\"\n#         cv2.imwrite(os.path.join(output_dir, aug_name), aug_image)\n\n# print(\"Augmentation complete. Total images generated:\", len(os.listdir(output_dir)))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **PREPARING & LOADING DATA ONE HOT ENCODING MASKS**","metadata":{}},{"cell_type":"code","source":"from PIL import Image\nimport numpy as np\nimport os\nimport cv2\nfrom tensorflow.keras.utils import Sequence\nfrom tensorflow.keras import layers,models\n\n\nclass ImageMaskGenerator(Sequence):\n    def __init__(self, image_dir, mask_dir, batch_size, image_size=(256, 256), shuffle=True):\n        self.image_dir = image_dir\n        self.mask_dir = mask_dir\n        self.batch_size = batch_size\n        self.image_size = image_size\n        self.image_filenames = os.listdir(image_dir)\n        self.on_epoch_end()\n\n    def __len__(self):\n        # Number of batches per epoch\n        return int(np.floor(len(self.image_filenames) / self.batch_size))\n\n    def on_epoch_end(self):\n        # Shuffle the filenames after each epoch (optional)\n        if self.shuffle:\n            np.random.shuffle(self.image_filenames)\n\n    def __getitem__(self, index):\n        # Get the list of filenames for the current batch\n        batch_filenames = self.image_filenames[index * self.batch_size:(index + 1) * self.batch_size]\n        images = []\n        masks = []\n        \n        for filename in batch_filenames:\n            # Load image using OpenCV (this works for .jpg, .png, etc.)\n            image_path = os.path.join(self.image_dir, filename)\n            image = cv2.imread(image_path)\n            image = cv2.resize(image, self.image_size)  # Resize image to the desired size\n            images.append(image)\n            \n            # Load mask using PIL (this handles .tif format properly)\n            mask_filename = filename.replace('.jpg', '.tif')  # Assuming the mask file name corresponds\n            mask_path = os.path.join(self.mask_dir, mask_filename)\n            \n            try:\n                mask = Image.open(mask_path)  # Open mask image (PIL)\n                mask = mask.resize(self.image_size, Image.NEAREST)  # Resize mask to the desired size\n                mask = np.array(mask)  # Convert mask to numpy array\n\n                # One-hot encode the mask (convert it to shape (256, 256, 5))\n                one_hot_mask = np.zeros((self.image_size[0], self.image_size[1], 5))  # 5 classes\n                for class_id in range(5):\n                    one_hot_mask[:, :, class_id] = (mask == class_id).astype(int)\n                masks.append(one_hot_mask)\n            except Exception as e:\n                print(f\"Error loading mask {mask_filename}: {e}\")\n        \n        # Return batch of images and one-hot encoded masks\n        return np.array(images), np.array(masks)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T15:32:26.288389Z","iopub.execute_input":"2025-05-15T15:32:26.288797Z","iopub.status.idle":"2025-05-15T15:32:26.299968Z","shell.execute_reply.started":"2025-05-15T15:32:26.288770Z","shell.execute_reply":"2025-05-15T15:32:26.298752Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.callbacks import ModelCheckpoint\n\ntrain_image_dir = '/kaggle/input/drsegfinaldataset/Augmented/train/images'\ntrain_mask_dir = '/kaggle/input/drsegfinaldataset/Augmented/train/masks'\nval_image_dir = '/kaggle/input/drsegfinaldataset/Augmented/val/images'\nval_mask_dir = '/kaggle/input/drsegfinaldataset/Augmented/val/masks'\n\n# Hyperparameters\nbatch_size = 8\nimage_size = (256, 256)\nnum_classes = 5\n\n# Data generators\ntrain_gen = ImageMaskGenerator(train_image_dir, train_mask_dir, batch_size, image_size)\nval_gen = ImageMaskGenerator(val_image_dir, val_mask_dir, batch_size, image_size)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **MODELS ARCHITECTURE**","metadata":{}},{"cell_type":"code","source":"def unet(input_size=(256, 256, 3), num_classes=5):\n    inputs = layers.Input(input_size)\n\n    # Contracting path (Encoder)\n    c1 = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(inputs)\n    c1 = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(c1)\n    p1 = layers.MaxPooling2D((2, 2))(c1)\n\n    c2 = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(p1)\n    c2 = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(c2)\n    p2 = layers.MaxPooling2D((2, 2))(c2)\n\n    c3 = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(p2)\n    c3 = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(c3)\n    p3 = layers.MaxPooling2D((2, 2))(c3)\n\n    c4 = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(p3)\n    c4 = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(c4)\n    p4 = layers.MaxPooling2D((2, 2))(c4)\n\n    c5 = layers.Conv2D(1024, (3, 3), activation='relu', padding='same')(p4)\n    c5 = layers.Conv2D(1024, (3, 3), activation='relu', padding='same')(c5)\n\n    # Expansive path (Decoder)\n    u6 = layers.Conv2DTranspose(512, (2, 2), strides=(2, 2), padding='same')(c5)\n    u6 = layers.concatenate([u6, c4])\n    c6 = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(u6)\n    c6 = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(c6)\n\n    u7 = layers.Conv2DTranspose(256, (2, 2), strides=(2, 2), padding='same')(c6)\n    u7 = layers.concatenate([u7, c3])\n    c7 = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(u7)\n    c7 = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(c7)\n\n    u8 = layers.Conv2DTranspose(128, (2, 2), strides=(2, 2), padding='same')(c7)\n    u8 = layers.concatenate([u8, c2])\n    c8 = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(u8)\n    c8 = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(c8)\n\n    u9 = layers.Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same')(c8)\n    u9 = layers.concatenate([u9, c1])\n    c9 = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(u9)\n    c9 = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(c9)\n\n    outputs = layers.Conv2D(num_classes, (1, 1), activation='softmax')(c9)\n\n    model = models.Model(inputs, outputs)\n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T15:31:52.391508Z","iopub.execute_input":"2025-05-15T15:31:52.391891Z","iopub.status.idle":"2025-05-15T15:31:52.407413Z","shell.execute_reply.started":"2025-05-15T15:31:52.391862Z","shell.execute_reply":"2025-05-15T15:31:52.406024Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = unet(input_size=(256, 256, 3), num_classes=num_classes)\n\n# Compile the model\nmodel.compile(optimizer=Adam(learning_rate=1e-4), loss='categorical_crossentropy', metrics=['accuracy'])\n\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T15:32:31.300044Z","iopub.execute_input":"2025-05-15T15:32:31.300364Z","iopub.status.idle":"2025-05-15T15:32:31.680529Z","shell.execute_reply.started":"2025-05-15T15:32:31.300340Z","shell.execute_reply":"2025-05-15T15:32:31.679450Z"},"scrolled":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.callbacks import EarlyStopping,ReduceLROnPlateau\nmodel = unet(input_size=(256, 256, 3), num_classes=num_classes)  # Replace with your actual model definition\n\n# Compile the model\nmodel.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])\n\n# Define the callbacks (already defined above)\nearly_stopping = EarlyStopping(\n    monitor='val_loss',         # Monitors validation loss\n    patience=10,                # Number of epochs with no improvement to wait before stopping\n    verbose=1,                  # Print messages when stopping\n    restore_best_weights=True   # Restore the best weights from the epoch with the best validation loss\n)\n\ncheckpoint = ModelCheckpoint(\n    'unet_multiclass_best.keras',  # File path to save the model\n    monitor='val_loss',         # Monitor validation loss\n    save_best_only=True,        # Save only the best model\n    save_weights_only=False,     # Save only the weights (not the full model)\n    verbose=1                   # Print messages when saving the model\n)\n\nreduce_lr = ReduceLROnPlateau(\n    monitor='val_loss',         # Monitor validation loss\n    factor=0.5,                 # Factor by which the learning rate will be reduced\n    patience=5,                 # Number of epochs with no improvement before reducing the learning rate\n    min_lr=1e-6,                # Minimum learning rate\n    verbose=1                   # Print messages when reducing the learning rate\n)\n\n\nmodel.fit(\n    train_gen,                  # Training data generator\n    validation_data=val_gen,    # Validation data generator\n    epochs=50,                  # Number of epochs\n    callbacks=[early_stopping, checkpoint, reduce_lr]  # Pass the callbacks here\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T15:34:15.807053Z","iopub.execute_input":"2025-05-15T15:34:15.807397Z","execution_failed":"2025-05-15T15:35:26.323Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **EVALUATION OF MODEL**","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport tensorflow as tf\nfrom sklearn.metrics import classification_report, jaccard_score\nfrom PIL import Image\nimport os\n\n\nNUM_CLASSES = 5\nIMG_HEIGHT, IMG_WIDTH = 256, 256\n\n# Paths\nMODEL_PATH = \"/kaggle/input/multiclassdrmodel/keras/default/1/unet_multiclass_best.keras\"\nTEST_IMAGE_DIR = \"/kaggle/input/drsegfinaldataset/Augmented/test/images\"\nTEST_MASK_DIR = \"/kaggle/input/drsegfinaldataset/Augmented/test/masks\"\n\n# Load trained model\nmodel = tf.keras.models.load_model(MODEL_PATH, compile=False)\n\n\ndef preprocess_image(image_path):\n    img = Image.open(image_path).convert(\"RGB\")\n    img = img.resize((IMG_WIDTH, IMG_HEIGHT))\n    #img = np.array(img) / 255.0  # Normalize\n    return img\n\ndef preprocess_mask(mask_path, num_classes=NUM_CLASSES):\n    mask = Image.open(mask_path).convert(\"L\")  # Load as grayscale\n    mask = mask.resize((IMG_WIDTH, IMG_HEIGHT), Image.NEAREST)\n    mask = np.array(mask) \n    \n    # One-hot encode mask\n    one_hot_mask = np.zeros((IMG_HEIGHT, IMG_WIDTH, num_classes))\n    for class_id in range(num_classes):\n        one_hot_mask[:, :, class_id] = (mask == class_id).astype(int)\n\n    return one_hot_mask\n\n# Load test images and masks\ntest_images = []\ntest_masks = []\nimage_filenames = sorted(os.listdir(TEST_IMAGE_DIR))\n\nfor filename in image_filenames:\n    image_path = os.path.join(TEST_IMAGE_DIR, filename)\n    mask_path = os.path.join(TEST_MASK_DIR, filename.replace(\".jpg\", \".tif\"))  # Assuming same name structure\n\n    if os.path.exists(mask_path):\n        test_images.append(preprocess_image(image_path))\n        test_masks.append(preprocess_mask(mask_path))\n\n# Convert lists to numpy arrays\ntest_images = np.array(test_images)\ntest_masks = np.array(test_masks)  # Now correctly one-hot encoded\n\n# Make predictions\npredictions = model.predict(test_images)\npredictions = np.argmax(predictions, axis=-1).flatten()  # Convert from one-hot to class labels\ntrue_labels = np.argmax(test_masks, axis=-1).flatten()  # Convert from one-hot to class labels\n\n# Compute metrics\nprint(\"📊 Classification Report:\\n\")\nprint(classification_report(true_labels, predictions, digits=4))\n\n# Compute IoU for each class\niou_scores = jaccard_score(true_labels, predictions, average=None)\nfor i, iou in enumerate(iou_scores):\n    print(f\"  Class {i} IoU: {iou:.4f}\")\n\nprint(\"✅ Evaluation Completed.\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **TESTING ON IMAGES**","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\nimport cv2\nimport os\nimport matplotlib.pyplot as plt\n\n# Paths\nMODEL_PATH = \"/kaggle/input/multiclassdrmodel/keras/default/1/unet_multiclass_best.keras\"\nTEST_IMAGE_PATH = \"/kaggle/input/drsegfinaldataset/Augmented/train/images/IDRiD_08.jpg\"  # Change to your test image path\nTEST_MASK_PATH = \"/kaggle/input/drsegfinaldataset/Augmented/train/masks/IDRiD_08.tif\"    # Change to your test mask path (if available)\n\n# Image size (must match training dimensions)\nIMG_HEIGHT, IMG_WIDTH = 256, 256\nNUM_CLASSES = 5  # Adjust based on your final number of classes\n\n# Load trained model\nmodel = tf.keras.models.load_model(MODEL_PATH, compile=False)\n\n# Function to preprocess input image\ndef preprocess_image(image_path):\n    img = cv2.imread(image_path, cv2.IMREAD_COLOR)\n    img = cv2.resize(img, (IMG_WIDTH, IMG_HEIGHT))\n    img = np.expand_dims(img, axis=0)  # Add batch dimension\n    return img\n\n# Function to preprocess ground truth mask (optional)\ndef preprocess_mask(mask_path):\n    mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)\n    mask = cv2.resize(mask, (IMG_WIDTH, IMG_HEIGHT), interpolation=cv2.INTER_NEAREST)\n    return mask\n\n# Load and preprocess test image\ntest_img = preprocess_image(TEST_IMAGE_PATH)\n\n# Predict segmentation mask\npred_mask = model.predict(test_img)[0]  # Remove batch dimension\npred_mask = np.argmax(pred_mask, axis=-1)  # Convert one-hot to class labels\n\n# Load ground truth mask (if available)\nif os.path.exists(TEST_MASK_PATH):\n    true_mask = preprocess_mask(TEST_MASK_PATH)\nelse:\n    true_mask = None\n\n# Plot results\nplt.figure(figsize=(10, 5))\n\n# Show input image\nplt.subplot(1, 3, 1)\nplt.imshow(cv2.imread(TEST_IMAGE_PATH)[..., ::-1])  # Convert BGR to RGB\nplt.title(\"Input Image\")\nplt.axis(\"off\")\n\n# Show predicted mask\nplt.subplot(1, 3, 2)\nplt.imshow(pred_mask, cmap=\"jet\")  # Visualize segmentation map\nplt.title(\"Predicted Mask\")\nplt.axis(\"off\")\n\n# Show ground truth mask (if available)\nif true_mask is not None:\n    plt.subplot(1, 3, 3)\n    plt.imshow(true_mask, cmap=\"jet\")\n    plt.title(\"Ground Truth Mask\")\n    plt.axis(\"off\")\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T15:38:51.158701Z","iopub.execute_input":"2025-05-15T15:38:51.159065Z","iopub.status.idle":"2025-05-15T15:38:57.418836Z","shell.execute_reply.started":"2025-05-15T15:38:51.159029Z","shell.execute_reply":"2025-05-15T15:38:57.417385Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\nimport cv2\nimport os\nimport matplotlib.pyplot as plt\n\n# Paths\nMODEL_PATH = \"/kaggle/input/multiclassdrmodel/keras/default/1/unet_multiclass_best.keras\"\nTEST_IMAGE_PATH = \"/kaggle/input/drsegfinaldataset/Augmented/train/images/IDRiD_08.jpg\"\nTEST_MASK_PATH = \"/kaggle/input/drsegfinaldataset/Augmented/train/masks/IDRiD_08.tif\"\n\n# Image size and number of classes\nIMG_HEIGHT, IMG_WIDTH = 256, 256\nNUM_CLASSES = 5\nclasses = [\"background\",\"MA\",\"HEM\",\"SE\",\"HE\"]\n# Load trained model\nmodel = tf.keras.models.load_model(MODEL_PATH, compile=False)\n\ndef preprocess_image(image_path):\n    img = cv2.imread(image_path, cv2.IMREAD_COLOR)\n    img = cv2.resize(img, (IMG_WIDTH, IMG_HEIGHT))\n    img = np.expand_dims(img, axis=0)  # Add batch dimension\n    return img\n\ndef preprocess_mask(mask_path):\n    mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)\n    mask = cv2.resize(mask, (IMG_WIDTH, IMG_HEIGHT), interpolation=cv2.INTER_NEAREST)\n    return mask\n\n# Load and preprocess\ninput_img = preprocess_image(TEST_IMAGE_PATH)\norig_img = cv2.imread(TEST_IMAGE_PATH)\norig_img = cv2.resize(orig_img, (IMG_WIDTH, IMG_HEIGHT))\n\n# Predict\npred_mask = model.predict(input_img)[0]\npred_mask_class = np.argmax(pred_mask, axis=-1)  # (256, 256)\n\n# Load GT mask (optional)\ntrue_mask = preprocess_mask(TEST_MASK_PATH) if os.path.exists(TEST_MASK_PATH) else None\n\n# Create a figure\nplt.figure(figsize=(15, 10))\n\n# 1. Show input image\nplt.subplot(2, NUM_CLASSES, 1)\nplt.imshow(cv2.cvtColor(orig_img, cv2.COLOR_BGR2RGB))\nplt.title(\"Original Image\")\nplt.axis(\"off\")\n\n# 2. Show predicted mask (merged)\nplt.subplot(2, NUM_CLASSES, 2)\nplt.imshow(pred_mask_class, cmap='jet')\nplt.title(\"Predicted Mask\")\nplt.axis(\"off\")\n\n# 3. Show class-wise binary masks\nfor class_id in range(1, NUM_CLASSES):  # skip background class 0\n    binary_mask = (pred_mask_class == class_id).astype(np.uint8)\n\n    # Show mask\n    plt.subplot(2, NUM_CLASSES, class_id + 2)\n    plt.imshow(binary_mask, cmap='gray')\n    plt.title(f\"Class {class_id} Mask\")\n    plt.axis(\"off\")\n\n# 4. Draw bounding boxes for each class\nimg_with_boxes = orig_img.copy()\n\nfor class_id in range(1, NUM_CLASSES):  # again, skip background\n    binary_mask = (pred_mask_class == class_id).astype(np.uint8)\n    print(f\"Class {class_id}: {np.sum(binary_mask)} pixels\")\n\n    \n    # Find contours\n    contours, _ = cv2.findContours(binary_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n    \n    # Draw bounding boxes\n    for cnt in contours:\n        x, y, w, h = cv2.boundingRect(cnt)\n        if w > 2 and h > 2:  # filter small boxes\n            cv2.rectangle(img_with_boxes, (x, y), (x+w, y+h), (0, 255, 0), 1)\n            cv2.putText(img_with_boxes, f\"{classes[class_id]}\", (x, y-5),\n                        cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)\n\n# 5. Show image with bounding boxes\nplt.subplot(2, NUM_CLASSES-1, NUM_CLASSES + 1)\nplt.imshow(cv2.cvtColor(img_with_boxes, cv2.COLOR_BGR2RGB))\nplt.title(\"Boxes on Original\")\nplt.axis(\"off\")\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-15T15:40:57.252654Z","iopub.execute_input":"2025-05-15T15:40:57.253043Z","iopub.status.idle":"2025-05-15T15:41:00.708411Z","shell.execute_reply.started":"2025-05-15T15:40:57.253011Z","shell.execute_reply":"2025-05-15T15:41:00.706808Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **GENERATE MASKS OF NEW DATASET**","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\nimport cv2\nimport os\nfrom glob import glob\nimport matplotlib.pyplot as plt\n\n# Paths\nMODEL_PATH = \"/kaggle/input/multiclassdrmodel/keras/default/1/unet_multiclass_best.keras\"\nTEST_IMAGE_DIR = \"/kaggle/input/drsegfinaldataset/Augmented/test/images\"\nOUTPUT_DIR = \"/kaggle/working/output\"\n\n# Constants\nIMG_HEIGHT, IMG_WIDTH = 256, 256\nNUM_CLASSES = 5\nCLASSES = [\"background\", \"MA\", \"HEM\", \"SE\", \"HE\"]\n\n# Output folders\nMASK_FOLDERS = {i: os.path.join(OUTPUT_DIR, str(i)) for i in range(1, NUM_CLASSES)}\nCOMBINED_MASK_DIR = os.path.join(OUTPUT_DIR, \"combined\")\nBOXED_IMG_DIR = os.path.join(OUTPUT_DIR, \"boxed\")\n\n# Create folders if not exist\nfor path in list(MASK_FOLDERS.values()) + [COMBINED_MASK_DIR, BOXED_IMG_DIR]:\n    os.makedirs(path, exist_ok=True)\n\n# Load model\nmodel = tf.keras.models.load_model(MODEL_PATH, compile=False)\n\ndef preprocess_image(image):\n    img = cv2.resize(image, (IMG_WIDTH, IMG_HEIGHT))\n    img = np.expand_dims(img, axis=0)  # Add batch dimension\n    return img\n\n# Iterate through all images\nimage_paths = sorted(glob(os.path.join(TEST_IMAGE_DIR, \"*.jpg\")))\n\nfor image_path in image_paths:\n    filename = os.path.splitext(os.path.basename(image_path))[0]\n    \n    # Load and preprocess\n    orig_img = cv2.imread(image_path)\n    orig_img_rgb = cv2.cvtColor(orig_img, cv2.COLOR_BGR2RGB)\n    orig_height, orig_width = orig_img.shape[:2]\n    input_img = preprocess_image(orig_img)\n\n    # Predict\n    pred_mask = model.predict(input_img)[0]\n    pred_mask_class = np.argmax(pred_mask, axis=-1)\n    pred_mask_class = cv2.resize(pred_mask_class.astype(np.uint8), (orig_width, orig_height), interpolation=cv2.INTER_NEAREST)\n\n    # Save combined mask\n    combined_path = os.path.join(COMBINED_MASK_DIR, f\"{filename}_combined.png\")\n    cv2.imwrite(combined_path, pred_mask_class)\n\n    # Prepare image for bounding boxes\n    img_with_boxes = orig_img.copy()\n\n    # Generate and save masks for each class\n    for class_id in range(1, NUM_CLASSES):  # skip background\n        binary_mask = (pred_mask_class == class_id).astype(np.uint8) * 255\n        mask_save_path = os.path.join(MASK_FOLDERS[class_id], f\"{filename}_class{class_id}.png\")\n        cv2.imwrite(mask_save_path, binary_mask)\n\n        # Draw bounding boxes\n        contours, _ = cv2.findContours(binary_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n        for cnt in contours:\n            x, y, w, h = cv2.boundingRect(cnt)\n            if w > 2 and h > 2:\n                cv2.rectangle(img_with_boxes, (x, y), (x+w, y+h), (0, 255, 0), 1)\n                cv2.putText(img_with_boxes, f\"{CLASSES[class_id]}\", (x, y-5),\n                            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)\n\n    # Save image with bounding boxes\n    boxed_save_path = os.path.join(BOXED_IMG_DIR, f\"{filename}_boxed.jpg\")\n    cv2.imwrite(boxed_save_path, img_with_boxes)\n\n    print(f\"Processed: {filename}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}