{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","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"},"vscode":{"interpreter":{"hash":"0987726327b6c9b2f5f936e5ed66944479e247a882213e2c65b0f41fe619a749"}},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":90316,"databundleVersionId":10477888,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport cv2 as cv\nimport csv\nimport matplotlib.pyplot as plt","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T22:16:12.626731Z","iopub.execute_input":"2025-01-03T22:16:12.627132Z","iopub.status.idle":"2025-01-03T22:16:12.916051Z","shell.execute_reply.started":"2025-01-03T22:16:12.627088Z","shell.execute_reply":"2025-01-03T22:16:12.915060Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Decoding RLEs into masks for training","metadata":{},"attachments":{}},{"cell_type":"code","source":"import numpy as np\nimport csv\n\ndef decode_rle_to_mask(rle, height, width, viz=False):\n    '''\n    rle : run-length encoding string formatted as \"start count start count ...\"\n    height : height of the mask\n    width : width of the mask\n    returns binary mask\n    '''\n    if not rle or rle.strip() == '':\n        print(f\"Skipping empty RLE: {rle}\")\n        return np.zeros((height, width, 3), dtype=np.float32)\n\n    try:\n        rle = np.array(rle.split(), dtype=int).reshape(-1, 2)\n    except ValueError:\n        print(f\"Invalid RLE format: {rle}\")\n        return np.zeros((height, width, 3), dtype=np.float32)\n\n    mask = np.zeros((height * width, 3), dtype=np.float32)\n    color = np.random.rand(3) if viz else [1, 1, 1]\n\n    for start, count in rle:\n        mask[start:start + count, :] = color\n\n    return mask.reshape(height, width, 3)\n\n# Open train file\nwith open('/kaggle/input/ai-dl-multiclass-segmentation/train.csv', 'r', encoding='utf-8') as train:\n    reader = csv.reader(train)\n    # Skip headers row\n    next(reader)\n\n    # Pull the masks for the first image\n    row = next(iter(reader))\n    print(row[0])\n    mask1 = decode_rle_to_mask(row[4], int(row[1]), int(row[2]))\n\n    row = next(iter(reader))\n    mask2 = decode_rle_to_mask(row[4], int(row[1]), int(row[2]))\n\n    row = next(iter(reader))\n    mask3 = decode_rle_to_mask(row[4], int(row[1]), int(row[2]))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T22:16:13.705781Z","iopub.execute_input":"2025-01-03T22:16:13.706167Z","iopub.status.idle":"2025-01-03T22:16:13.726810Z","shell.execute_reply.started":"2025-01-03T22:16:13.706138Z","shell.execute_reply":"2025-01-03T22:16:13.725851Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Head mask\nplt.imshow(mask1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T22:16:14.290959Z","iopub.execute_input":"2025-01-03T22:16:14.291245Z","iopub.status.idle":"2025-01-03T22:16:14.547403Z","shell.execute_reply.started":"2025-01-03T22:16:14.291224Z","shell.execute_reply":"2025-01-03T22:16:14.546661Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Body mask\nplt.imshow(mask2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T22:16:17.161916Z","iopub.execute_input":"2025-01-03T22:16:17.162224Z","iopub.status.idle":"2025-01-03T22:16:17.388748Z","shell.execute_reply.started":"2025-01-03T22:16:17.162197Z","shell.execute_reply":"2025-01-03T22:16:17.387999Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Legs mask\nplt.imshow(mask3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T22:16:17.570389Z","iopub.execute_input":"2025-01-03T22:16:17.570743Z","iopub.status.idle":"2025-01-03T22:16:17.790098Z","shell.execute_reply.started":"2025-01-03T22:16:17.570711Z","shell.execute_reply":"2025-01-03T22:16:17.789177Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# combine masks for training\nmixed_mask = mask1*1+mask2*2+mask3*3 #+mask4*4\n\n# This is an image multi-segmentation task. The classes are:\n    # 1: Head\n    # 2: Body\n    # 3: Legs\n    # 4: Tail\n# As seen below (notice this image does not include a tail in the image so no class 4)\nprint(np.unique(mixed_mask))\n\n## For visualization purposes only, we can see the different segments colorcoded in the mixed mask by dividing my the sum of the class values (normalization)\n## However, for submission, you should split the mask into 4 binary masks and RLE encode them individually as shown below.\n\nplt.imshow(mixed_mask/6) # normalized just to show different segmentations (divide by sum of values)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T22:16:21.020386Z","iopub.execute_input":"2025-01-03T22:16:21.020687Z","iopub.status.idle":"2025-01-03T22:16:21.249318Z","shell.execute_reply.started":"2025-01-03T22:16:21.020663Z","shell.execute_reply":"2025-01-03T22:16:21.248474Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Training Pipeline","metadata":{},"attachments":{}},{"cell_type":"code","source":"!pip install tensorflow opencv-python matplotlib numpy\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T22:16:25.668442Z","iopub.execute_input":"2025-01-03T22:16:25.668790Z","iopub.status.idle":"2025-01-03T22:16:30.125006Z","shell.execute_reply.started":"2025-01-03T22:16:25.668760Z","shell.execute_reply":"2025-01-03T22:16:30.124022Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport csv\nimport cv2\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nfrom tensorflow.keras import layers, models\nfrom tensorflow.keras.preprocessing.image import load_img, img_to_array\nfrom tensorflow.keras.utils import to_categorical\nfrom sklearn.model_selection import train_test_split","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T22:18:30.147131Z","iopub.execute_input":"2025-01-03T22:18:30.147421Z","iopub.status.idle":"2025-01-03T22:18:30.153947Z","shell.execute_reply.started":"2025-01-03T22:18:30.147399Z","shell.execute_reply":"2025-01-03T22:18:30.153104Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport cv2\nfrom tensorflow.keras.preprocessing.image import load_img, img_to_array\nfrom sklearn.model_selection import train_test_split\n\n# Define paths\ndata_paths = {\n    \"images\": \"/kaggle/input/ai-dl-multiclass-segmentation/TrainImages\",\n    \"masks\": \"/kaggle/working/GeneratedMasks\"\n}\n\n# Create directory for masks if not present\nos.makedirs(data_paths[\"masks\"], exist_ok=True)\n\n# Generate masks from CSV data\nwith open('/kaggle/input/ai-dl-multiclass-segmentation/train.csv', 'r', encoding='utf-8') as train_file:\n    reader = csv.reader(train_file)\n    next(reader)  # Skip header\n\n    for row in reader:\n        image_name, height, width, class_number, rle = row[0], int(row[1]), int(row[2]), int(row[3]), row[4]\n        mask = decode_rle_to_mask(rle, height, width)\n        mask_path = os.path.join(data_paths[\"masks\"], f\"{os.path.splitext(image_name)[0]}_mask.png\")\n        Image.fromarray((mask * 255).astype(np.uint8)).save(mask_path)\n\nprint(f\"Masks saved in {data_paths['masks']}\")\n\ndef load_data(images_path, masks_path, target_size=(256, 256)):\n    image_files = sorted(os.listdir(images_path))\n    mask_files = sorted(os.listdir(masks_path))\n\n    images = []\n    masks = []\n\n    for img_file, mask_file in zip(image_files, mask_files):\n        img = load_img(os.path.join(images_path, img_file), target_size=target_size)\n        img = img_to_array(img) / 255.0\n\n        mask = load_img(os.path.join(masks_path, mask_file), target_size=target_size, color_mode='grayscale')\n        mask = img_to_array(mask).astype(np.uint8)\n\n        # Ensure mask values map to valid class indices (0–3)\n        mask = np.clip(mask, 0, 3)  # Adjust values if necessary\n\n        images.append(img)\n        masks.append(mask)\n\n    images = np.array(images)\n    masks = np.array(masks).squeeze(-1)  # Remove extra channel dimension\n\n    # Convert masks to categorical (4 classes)\n    masks = to_categorical(masks, num_classes=4)\n\n    return images, masks\n\n\n# Load dataset\nimages, masks = load_data(data_paths[\"images\"], data_paths[\"masks\"], target_size=(256, 256))\n\n# Split dataset\nX_train, X_val, y_train, y_val = train_test_split(images, masks, test_size=0.2, random_state=42)\n\nprint(f\"Training data shape: {X_train.shape}\")\nprint(f\"Validation data shape: {X_val.shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T22:18:30.702141Z","iopub.execute_input":"2025-01-03T22:18:30.702428Z","iopub.status.idle":"2025-01-03T22:19:37.853291Z","shell.execute_reply.started":"2025-01-03T22:18:30.702404Z","shell.execute_reply":"2025-01-03T22:19:37.852520Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# U-Net model\ndef unet_model(input_size=(256, 256, 3), num_classes=4):\n    inputs = layers.Input(input_size)\n\n    # 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    # Decoder\n    u6 = layers.UpSampling2D((2, 2))(c5)\n    u6 = layers.concatenate([u6, c4], axis=-1)\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.UpSampling2D((2, 2))(c6)\n    u7 = layers.concatenate([u7, c3], axis=-1)\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.UpSampling2D((2, 2))(c7)\n    u8 = layers.concatenate([u8, c2], axis=-1)\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.UpSampling2D((2, 2))(c8)\n    u9 = layers.concatenate([u9, c1], axis=-1)\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    return models.Model(inputs=[inputs], outputs=[outputs])\n\n# Build and compile the model\nmodel = unet_model(input_size=(256, 256, 3), num_classes=4)\nmodel.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T22:19:37.854524Z","iopub.execute_input":"2025-01-03T22:19:37.854876Z","iopub.status.idle":"2025-01-03T22:19:38.629287Z","shell.execute_reply.started":"2025-01-03T22:19:37.854842Z","shell.execute_reply":"2025-01-03T22:19:38.628507Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Train the model\nepochs = 20\nbatch_size = 16\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom tensorflow.keras import backend as K\nimport tensorflow as tf\n\n\n# Early stopping callback\nearly_stopping = EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True)\n\n# Compile the model with IoU as a metric\nmodel.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])\n\n# Train the model\nhistory = model.fit(\n    X_train, y_train,\n    validation_data=(X_val, y_val),\n    batch_size=batch_size,\n    epochs=epochs,\n    callbacks=[early_stopping]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T22:19:38.630516Z","iopub.execute_input":"2025-01-03T22:19:38.630754Z","iopub.status.idle":"2025-01-03T22:28:23.627954Z","shell.execute_reply.started":"2025-01-03T22:19:38.630734Z","shell.execute_reply":"2025-01-03T22:28:23.627154Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Save using the recommended `.keras` extension\nmodel.save(\"unet_model.keras\")\nprint(\"Model saved in Keras format: 'unet_model.keras'\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T22:29:02.933765Z","iopub.execute_input":"2025-01-03T22:29:02.934064Z","iopub.status.idle":"2025-01-03T22:29:04.487512Z","shell.execute_reply.started":"2025-01-03T22:29:02.934042Z","shell.execute_reply":"2025-01-03T22:29:04.486535Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Encoding masks into RLE for submission","metadata":{},"attachments":{}},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport cv2\nfrom tensorflow.keras.preprocessing.image import load_img, img_to_array\nfrom tensorflow.keras.models import load_model\n\n# Define paths\ntest_csv_path = '/kaggle/input/ai-dl-multiclass-segmentation/test_class.csv'\ntest_images_path = '/kaggle/input/ai-dl-multiclass-segmentation/TestImages'\nmodel_path = '/kaggle/working/unet_model.keras'\nsubmission_path = '/kaggle/working/submission.csv'\n\n# Load the saved model\nmodel = load_model(model_path)\n\ndef preprocess_image(image_path, target_size=(256, 256)):\n    img = load_img(image_path, target_size=target_size)\n    img = img_to_array(img) / 255.0\n    img = np.expand_dims(img, axis=0)\n    return img\n\ndef postprocess_mask(pred, target_size=(256, 256)):\n    pred = np.argmax(pred, axis=-1)\n    pred = np.squeeze(pred)\n    pred = cv2.resize(pred, target_size, interpolation=cv2.INTER_NEAREST)\n    return pred\n\ndef encode_rle(mask):\n    pixels = mask.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(str(x) for x in runs)\n\n# Load test images\ntest_df = pd.read_csv(test_csv_path)\nsubmission_data = []\n\nfor _, row in test_df.iterrows():\n    image_name = row['ImageName']\n    class_number = row['ClassNumber']\n    original_height, original_width = int(row['ImageHeight']), int(row['ImageWidth'])\n    \n    # Preprocess image\n    image_path = os.path.join(test_images_path, image_name + '.jpg')\n    img = preprocess_image(image_path)\n    \n    # Predict mask\n    pred = model.predict(img)[0]\n    mask = postprocess_mask(pred, target_size=(original_height, original_width))\n    binary_mask = (mask == class_number).astype(np.uint8)\n    \n    # Encode mask\n    if binary_mask.sum() > 0:\n        rle = encode_rle(binary_mask)\n    else:\n        rle = ''  # Empty RLE for empty masks\n    \n    submission_data.append({'ImageId_ClassId': f\"{image_name}_{class_number}\", 'EncodedPixels': rle})\n\n# Save submission\nsubmission_df = pd.DataFrame(submission_data)\nsubmission_df.to_csv(submission_path, index=False)\nprint(f\"Submission saved to {submission_path}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T22:39:32.132252Z","iopub.execute_input":"2025-01-03T22:39:32.132649Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def encode_mask_to_rle(mask):\n    '''\n    mask: numpy array binary mask \n    1 - mask \n    0 - background\n    Returns encoded run length \n    '''\n    pixels = mask.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(str(x) for x in runs)","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"mask1.shape","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# IMPORTANT || Convert mask to grayscale\nmask1 = mask1[:,:,0] # or using other methods depending on mask\nmask1.shape","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"rle = encode_mask_to_rle(mask1)\nrle","metadata":{},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\ndef visualize_predictions(image_path, model_path):\n    model = tf.keras.models.load_model(model_path, custom_objects={'dice_loss': dice_loss})\n\n    img = load_img(image_path, target_size=(256, 256))  # Assuming H, W = 256, 256\n    img = img_to_array(img) / 255.0\n    img = np.expand_dims(img, axis=0)\n\n    pred = model.predict(img)[0]\n    pred_mask = np.argmax(pred, axis=-1)\n\n    plt.figure(figsize=(12, 6))\n    plt.subplot(1, 2, 1)\n    plt.imshow(load_img(image_path))\n    plt.title(\"Original Image\")\n    plt.axis('off')\n\n    plt.subplot(1, 2, 2)\n    plt.imshow(pred_mask, cmap='viridis')\n    plt.title(\"Predicted Mask\")\n    plt.axis('off')\n\n    plt.show()\n\n# Example usage\nimage_path = '/kaggle/input/ai-dl-multiclass-segmentation/TestImages/02.jpg' \nmodel_path = '/kaggle/working/unet_model.keras'\nvisualize_predictions(image_path, model_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T21:12:44.803980Z","iopub.execute_input":"2025-01-03T21:12:44.804250Z","iopub.status.idle":"2025-01-03T21:12:47.031447Z","shell.execute_reply.started":"2025-01-03T21:12:44.804214Z","shell.execute_reply":"2025-01-03T21:12:47.030609Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def generate_submission(test_csv_path, test_images_path, model_path, submission_path):\n    test_df = pd.read_csv(test_csv_path)\n    model = tf.keras.models.load_model(model_path, custom_objects={'dice_loss': dice_loss})\n\n    submission_data = []\n    for _, row in test_df.iterrows():\n        image_name = row['ImageName']\n        class_number = row['ClassNumber']\n        original_height, original_width = int(row['ImageHeight']), int(row['ImageWidth'])\n\n        # Preprocess image\n        image_path = os.path.join(test_images_path, image_name + '.jpg')\n        img = load_img(image_path, target_size=(H, W))\n        img = img_to_array(img) / 255.0\n        img = np.expand_dims(img, axis=0)\n\n        # Predict and process mask\n        pred = model.predict(img)[0]\n        pred_mask = np.argmax(pred, axis=-1)\n        binary_mask = (pred_mask == class_number).astype(np.uint8)\n        binary_mask = cv2.resize(binary_mask, (original_width, original_height), interpolation=cv2.INTER_NEAREST)\n\n        # Debugging output\n        print(f\"Image: {image_name}, Class: {class_number}\")\n        print(f\"Predicted Mask Unique Values: {np.unique(pred_mask)}\")\n        print(f\"Binary Mask Unique Values: {np.unique(binary_mask)}\")\n\n        # Encode mask if not empty\n        if binary_mask.sum() > 0:\n            pixels = binary_mask.flatten()\n            pixels = np.concatenate([[0], pixels, [0]])\n            runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n            runs[1::2] -= runs[::2]\n            rle = ' '.join(map(str, runs))\n        else:\n            rle = ''  # Empty RLE for empty masks\n\n        submission_data.append({'ImageName': f\"{image_name}_{class_number}\", 'Encoding': rle})\n\n    submission_df = pd.DataFrame(submission_data)\n    submission_df.to_csv(submission_path, index=False)\n    print(f\"Submission saved to {submission_path}\")\n\n\n# Paths for submission generation\ntest_csv_path = '/kaggle/input/ai-dl-multiclass-segmentation/test_class.csv'\ntest_images_path = '/kaggle/input/ai-dl-multiclass-segmentation/TestImages'\nmodel_path = 'best_model.keras'\nsubmission_path = '/kaggle/working/submission3.csv'\n\n# Generate submission\ngenerate_submission(test_csv_path, test_images_path, model_path, submission_path)\n","metadata":{"trusted":true,"execution":{"execution_failed":"2025-01-03T19:48:20.275Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport os\nfrom tensorflow.keras.models import load_model\nfrom tensorflow.keras.preprocessing.image import load_img, img_to_array\n\n# Paths\nmodel_path = '/kaggle/working/best_model.keras'  # Path to your saved model\ntest_images_path = '/kaggle/input/ai-dl-multiclass-segmentation/TestImages'  # Path to test images\nsubmission_path = '/kaggle/working/sample_submission1.csv'  # Output submission file\n\n# Load trained model\nmodel = load_model(model_path)\n\n# Constants\nIMG_HEIGHT, IMG_WIDTH = 256, 256  # Model input size\nNUM_CLASSES = 4  # Number of classes (1=head, 2=body, 3=legs, 4=tail)\n\n# Function to encode mask to RLE\ndef encode_mask_to_rle(mask):\n    '''\n    mask : binary numpy array of shape (height, width)\n    Returns RLE as string\n    '''\n    pixels = mask.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])  # Add padding to handle edge cases\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(map(str, runs))\n\n# Function to preprocess test images\ndef preprocess_image(image_path, target_size=(256, 256)):\n    img = load_img(image_path, target_size=target_size)  # Resize image\n    img = img_to_array(img) / 255.0  # Normalize\n    return np.expand_dims(img, axis=0)  # Add batch dimension\n\n# Prepare submission DataFrame\nsubmission = []\n\n# List of test images\ntest_image_files = sorted(os.listdir(test_images_path))  # List of test image filenames\n\n# Predict masks and generate RLE\nfor img_file in test_image_files:\n    # Preprocess the test image\n    img_path = os.path.join(test_images_path, img_file)\n    preprocessed_img = preprocess_image(img_path)\n\n    # Predict the mask using the trained model\n    pred_mask = model.predict(preprocessed_img, verbose=0)[0]  # Output shape: (256, 256, NUM_CLASSES)\n    pred_mask = np.argmax(pred_mask, axis=-1)  # Convert probabilities to class indices\n\n    # Iterate over each class (1 to 4)\n    for class_number in range(1, NUM_CLASSES + 1):\n        binary_mask = (pred_mask == class_number).astype(np.uint8)  # Generate binary mask for the class\n        rle = encode_mask_to_rle(binary_mask)  # Encode the binary mask to RLE\n        \n        # Prepare the submission entry\n        submission.append([f\"{os.path.splitext(img_file)[0]}_{class_number}\", rle])\n\n# Create the DataFrame\nsubmission_df = pd.DataFrame(submission, columns=['ImageId_ClassId', 'EncodedPixels'])\n\n# Save to CSV\nsubmission_df.to_csv(submission_path, index=False)\nprint(f\"Sample submission file saved successfully at {submission_path}!\")\n\n# Display a sample of the submission DataFrame\nprint(submission_df.head())\nprint(f\"Total rows in submission: {len(submission_df)}\")\n\n\nimport pandas as pd\nimport numpy as np\nimport os\nfrom tensorflow.keras.models import load_model\nfrom tensorflow.keras.preprocessing.image import load_img, img_to_array\n\n# Paths\ntest_csv_path = '/kaggle/input/ai-dl-multiclass-segmentation/test_class.csv'  # Path to test CSV\ntest_images_path = '/kaggle/input/ai-dl-multiclass-segmentation/TestImages'  # Path to test images\nmodel_path = '/kaggle/working/best_model.keras'  # Path to trained model\noutput_csv_path = '/kaggle/working/sample_submission.csv'  # Output submission file\n\n# Constants\nIMG_HEIGHT, IMG_WIDTH = 256, 256  # Model input size\nNUM_CLASSES = 4  # Number of classes (head, body, legs, tail)\n\n# Load trained model\nmodel = load_model(model_path)\nfrom tensorflow.keras.losses import Loss\n\n# Custom Dice Loss function\ndef dice_loss(y_true, y_pred, smooth=1e-6):\n    y_true_f = tf.reshape(y_true, [-1])\n    y_pred_f = tf.reshape(y_pred, [-1])\n    intersection = tf.reduce_sum(y_true_f * y_pred_f)\n    return 1 - (2. * intersection + smooth) / (tf.reduce_sum(y_true_f) + tf.reduce_sum(y_pred_f) + smooth)\n\n# Load trained model with custom loss function\nmodel = load_model(model_path, custom_objects={'dice_loss': dice_loss})\n\n\n# Function to encode mask to RLE\ndef encode_mask_to_rle(mask):\n    '''\n    mask : binary numpy array of shape (height, width)\n    Returns RLE as string\n    '''\n    pixels = mask.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])  # Add padding to handle edge cases\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(map(str, runs))\n\n# Function to preprocess test images\ndef preprocess_image(image_path, target_size=(256, 256)):\n    img = load_img(image_path, target_size=target_size)  # Resize image\n    img = img_to_array(img) / 255.0  # Normalize\n    return np.expand_dims(img, axis=0)  # Add batch dimension\n\n# Load test CSV\ntest_csv = pd.read_csv(test_csv_path)\n\n# Predict and fill the Encoding column\nencodings = []\n\nfor _, row in test_csv.iterrows():\n    image_name = row['ImageName']\n    class_number = row['ClassNumber']\n    original_height = int(row['ImageHeight'])\n    original_width = int(row['ImageWidth'])\n\n    # Preprocess the image\n    image_path = os.path.join(test_images_path, image_name + '.jpg')\n    preprocessed_img = preprocess_image(image_path)\n\n    # Predict the mask using the trained model\n    pred_mask = model.predict(preprocessed_img, verbose=0)[0]  # Output shape: (256, 256, NUM_CLASSES)\n    pred_mask = np.argmax(pred_mask, axis=-1)  # Convert probabilities to class indices\n\n    # Generate binary mask for the current class\n    binary_mask = (pred_mask == class_number).astype(np.uint8)  # Binary mask for the class\n\n    # Resize the binary mask back to original dimensions\n    binary_mask = np.expand_dims(binary_mask, axis=-1)  # Add channel dimension\n    binary_mask = tf.image.resize(binary_mask, (original_height, original_width), method='nearest')\n    binary_mask = tf.squeeze(binary_mask).numpy().astype(np.uint8)  # Remove channel dimension\n\n    # Encode the binary mask to RLE\n    rle = encode_mask_to_rle(binary_mask)\n    encodings.append(rle)\n\n# Update the Encoding column\ntest_csv['Encoding'] = encodings\n\n# Save the updated test CSV\ntest_csv.to_csv(output_csv_path, index=False)\nprint(f\"Updated test CSV saved to {output_csv_path}\")\n\n# Display a sample of the updated CSV\nprint(test_csv.head())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-03T18:47:03.901051Z","iopub.execute_input":"2025-01-03T18:47:03.901353Z","iopub.status.idle":"2025-01-03T18:47:04.123216Z","shell.execute_reply.started":"2025-01-03T18:47:03.901325Z","shell.execute_reply":"2025-01-03T18:47:04.121950Z"},"collapsed":true,"jupyter":{"source_hidden":true,"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load the correct test CSV file\ntest_csv_path = '/kaggle/input/ai-dl-multiclass-segmentation/Sample Submission.csv'\ntest_csv = pd.read_csv(test_csv_path)\n\n# Now proceed with your processing steps\nprint(test_csv.head())  # Check the first few rows to understand the structure\n","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}