{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":113558,"databundleVersionId":14878066,"sourceType":"competition"},{"sourceId":14167480,"sourceType":"datasetVersion","datasetId":9030673},{"sourceId":4534,"sourceType":"modelInstanceVersion","modelInstanceId":3326,"modelId":986},{"sourceId":686586,"sourceType":"modelInstanceVersion","modelInstanceId":520737,"modelId":534998}],"dockerImageVersionId":31236,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<div style=\"\n    background: linear-gradient(135deg, #2a103b 0%, #3f1d54 50%, #5e2d7f 100%);\n    border: 2px solid #c084fc;\n    border-radius: 15px;\n    padding: 25px;\n    margin: 20px 0;\n    box-shadow: 0 0 30px rgba(192, 132, 252, 0.4),\n                inset 0 0 20px rgba(255, 255, 255, 0.1);\n    color: #f5f3ff;\n    font-family: 'Segoe UI', system-ui, sans-serif;\n    position: relative;\n    overflow: hidden;\n\">\n\n<div style=\"\n    position: absolute;\n    top: -20px;\n    right: -20px;\n    width: 100px;\n    height: 100px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.25) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<div style=\"\n    position: absolute;\n    bottom: -40px;\n    left: -40px;\n    width: 120px;\n    height: 120px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.2) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<h1 style=\"\n    color: #c084fc;\n    margin: 0 0 20px 0;\n    text-align: center;\n    font-weight: 700;\n    font-size: 1.8em;\n    text-shadow: 0 0 15px rgba(192, 132, 252, 0.6);\n    position: relative;\n    z-index: 1;\n\">\n    👋 Hi everyone! 🌟\n</h1>\n\n<p style=\"\n    text-align: center; \n    font-size: 1.2em;\n    margin-bottom: 25px;\n    position: relative;\n    z-index: 1;\n    font-weight: 500;\n\">\n    I hope this notebook will be useful for beginners! 🚀\n</p>\n\n<div style=\"\n    background: rgba(192, 132, 252, 0.1);\n    border-left: 4px solid #c084fc;\n    border-radius: 8px;\n    padding: 20px;\n    margin: 20px 0;\n    position: relative;\n    z-index: 1;\n\">\n    <h3 style=\"\n        color: #c084fc;\n        margin-top: 0;\n        font-size: 1.3em;\n        display: flex;\n        align-items: center;\n        gap: 10px;\n    \">\n        🎯 Task: <span style=\"color: #f5f3ff;\">Semantic Segmentation</span>\n    </h3>\n</div>\n\n<div style=\"\n    background: rgba(255, 255, 255, 0.05);\n    border-radius: 10px;\n    padding: 20px;\n    position: relative;\n    z-index: 1;\n\">\n    <h3 style=\"\n        color: #c084fc;\n        margin-top: 0;\n        font-size: 1.3em;\n        display: flex;\n        align-items: center;\n        gap: 10px;\n    \">\n        ⚡ Challenges:\n    </h3>\n    <ul style=\"\n        color: #f5f3ff;\n        font-size: 1.1em;\n        line-height: 1.6;\n        margin-bottom: 0;\n    \">\n        <li>🖼️ Different sizes of images</li>\n        <li>🧠 Difficult task for conventional models</li>\n        <li>⚠️ Penalties for mistakes</li>\n    </ul>\n</div>\n","metadata":{}},{"cell_type":"markdown","source":"<div style=\"\n    background: linear-gradient(135deg, #2a103b 0%, #3f1d54 50%, #5e2d7f 100%);\n    border: 2px solid #c084fc;\n    border-radius: 15px;\n    padding: 25px;\n    margin: 20px 0;\n    box-shadow: 0 0 30px rgba(192, 132, 252, 0.4),\n                inset 0 0 20px rgba(255, 255, 255, 0.1);\n    color: #f5f3ff;\n    font-family: 'Segoe UI', system-ui, sans-serif;\n    position: relative;\n    overflow: hidden;\n\">\n\n<div style=\"\n    position: absolute;\n    top: -20px;\n    right: -20px;\n    width: 100px;\n    height: 100px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.25) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<div style=\"\n    position: absolute;\n    bottom: -40px;\n    left: -40px;\n    width: 120px;\n    height: 120px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.2) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<h1 style=\"\n    color: #c084fc;\n    margin: 0 0 20px 0;\n    text-align: center;\n    font-weight: 700;\n    font-size: 1.8em;\n    text-shadow: 0 0 15px rgba(192, 132, 252, 0.6);\n    position: relative;\n    z-index: 1;\n\">\n    Importing libraries\n</h1>\n","metadata":{}},{"cell_type":"code","source":"import os\nimport glob\nimport cv2\nimport json\nimport math\nimport torch\nimport torchvision\nimport random\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nimport matplotlib.pyplot as plt\nimport torch.nn.functional as F\n\nfrom tqdm.auto import tqdm\nfrom PIL import Image\nfrom pathlib import Path\nfrom transformers import AutoImageProcessor, AutoModel\nfrom tqdm import tqdm\nfrom collections import defaultdict\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision.models.detection import MaskRCNN\nfrom sklearn.model_selection import train_test_split\nfrom torchvision.models.detection.rpn import AnchorGenerator\nfrom torchvision.transforms import functional as F_transforms\n\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Checking GPU availability\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\ndevice","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:29:16.564667Z","iopub.execute_input":"2025-12-29T11:29:16.565172Z","iopub.status.idle":"2025-12-29T11:29:44.804246Z","shell.execute_reply.started":"2025-12-29T11:29:16.565142Z","shell.execute_reply":"2025-12-29T11:29:44.803653Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<div style=\"\n    background: linear-gradient(135deg, #2a103b 0%, #3f1d54 50%, #5e2d7f 100%);\n    border: 2px solid #c084fc;\n    border-radius: 15px;\n    padding: 25px;\n    margin: 20px 0;\n    box-shadow: 0 0 30px rgba(192, 132, 252, 0.4),\n                inset 0 0 20px rgba(255, 255, 255, 0.1);\n    color: #f5f3ff;\n    font-family: 'Segoe UI', system-ui, sans-serif;\n    position: relative;\n    overflow: hidden;\n\">\n\n<div style=\"\n    position: absolute;\n    top: -20px;\n    right: -20px;\n    width: 100px;\n    height: 100px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.25) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<div style=\"\n    position: absolute;\n    bottom: -40px;\n    left: -40px;\n    width: 120px;\n    height: 120px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.2) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<h1 style=\"\n    color: #c084fc;\n    margin: 0 0 20px 0;\n    text-align: center;\n    font-weight: 700;\n    font-size: 1.8em;\n    text-shadow: 0 0 15px rgba(192, 132, 252, 0.6);\n    position: relative;\n    z-index: 1;\n\">\n    Let's check the image sizes, sorry for the big conclusion, it's just that size is very important in CV tasks.\n</h1>\n","metadata":{}},{"cell_type":"code","source":"PATH_DATASET = \"/kaggle/input/recodai-luc-scientific-image-forgery-detection\"\nauthentic_images = glob.glob(os.path.join(PATH_DATASET, 'train_images', 'authentic', '*.png'))\nforged_images = glob.glob(os.path.join(PATH_DATASET, 'train_images', 'forged', '*.png'))\nforged_images += glob.glob(os.path.join(PATH_DATASET, 'supplemental_images', '*.png'))\n\nprint(f\"Found {len(authentic_images)} authentic images.\")\nprint(f\"Found {len(forged_images)} forged images.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:29:44.805706Z","iopub.execute_input":"2025-12-29T11:29:44.806336Z","iopub.status.idle":"2025-12-29T11:29:44.877112Z","shell.execute_reply.started":"2025-12-29T11:29:44.806305Z","shell.execute_reply":"2025-12-29T11:29:44.876412Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CONFIG:\n    test_images_path = \"/kaggle/input/recodai-luc-scientific-image-forgery-detection/test_images\"\n    sample_sub_path = \"/kaggle/input/recodai-luc-scientific-image-forgery-detection/sample_submission.csv\"\n    model1_path = \"/kaggle/input/modelsbest309base/best_model.pth\"\n    model2_path = \"/kaggle/input/dinobestmodel/pytorch/default/1/dino197.pth\"\n    dino_path = \"/kaggle/input/dinov2/pytorch/base/1\"\n    device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n    img_size = 512\n    use_tta = True\n    min_area_percent = 0.05 # percent new!\n    min_confidence = 0.336  # better conf","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:29:44.877951Z","iopub.execute_input":"2025-12-29T11:29:44.878207Z","iopub.status.idle":"2025-12-29T11:29:44.882269Z","shell.execute_reply.started":"2025-12-29T11:29:44.878188Z","shell.execute_reply":"2025-12-29T11:29:44.881636Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_unique_sizes(directory):\n    size_counts = defaultdict(int)\n    for root, _, files in os.walk(directory):\n        for file in files:\n            if file.lower().endswith(('.png', '.jpg', '.jpeg', 'JPG')):\n                try:\n                    with Image.open(os.path.join(root, file)) as img:\n                        size = img.size\n                        size_counts[size] += 1\n                except Exception as e:\n                    print(f\"Error {file}: {e}\")\n\n    return size_counts\n\nfolders = [\n    \"/kaggle/input/recodai-luc-scientific-image-forgery-detection/train_images/authentic\",\n    \"/kaggle/input/recodai-luc-scientific-image-forgery-detection/train_images/forged\",\n    \"/kaggle/input/recodai-luc-scientific-image-forgery-detection/test_images\"\n]\n\nfor folder in folders:\n    print(f\"\\n📂 Folder: {folder}\")\n    sizes = get_unique_sizes(folder)\n\n    if not sizes:\n        print(\"No images or mistake in code\")\n        continue\n    \n    sorted_sizes = sorted(sizes.items(), key=lambda x: x[1], reverse=True)\n\n    print(\"┌───────────────┬───────────────┬─────────┐\")\n    print(\"│  Width (px)  │ Height (px) │ Quantity │\")\n    print(\"├───────────────┼───────────────┼─────────┤\")\n    for (w, h), count in sorted_sizes:\n        print(f\"│ {w:<13} │ {h:<13} │ {count:<7} │\")\n    print(\"└───────────────┴───────────────┴─────────┘\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:29:44.883248Z","iopub.execute_input":"2025-12-29T11:29:44.883572Z","iopub.status.idle":"2025-12-29T11:30:16.448717Z","shell.execute_reply.started":"2025-12-29T11:29:44.883552Z","shell.execute_reply":"2025-12-29T11:30:16.447941Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<div style=\"\n    background: linear-gradient(135deg, #2a103b 0%, #3f1d54 50%, #5e2d7f 100%);\n    border: 2px solid #c084fc;\n    border-radius: 15px;\n    padding: 25px;\n    margin: 20px 0;\n    box-shadow: 0 0 30px rgba(192, 132, 252, 0.4),\n                inset 0 0 20px rgba(255, 255, 255, 0.1);\n    color: #f5f3ff;\n    font-family: 'Segoe UI', system-ui, sans-serif;\n    position: relative;\n    overflow: hidden;\n\">\n\n<div style=\"\n    position: absolute;\n    top: -20px;\n    right: -20px;\n    width: 100px;\n    height: 100px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.25) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<div style=\"\n    position: absolute;\n    bottom: -40px;\n    left: -40px;\n    width: 120px;\n    height: 120px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.2) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<h1 style=\"\n    color: #c084fc;\n    margin: 0 0 20px 0;\n    text-align: center;\n    font-weight: 700;\n    font-size: 1.8em;\n    text-shadow: 0 0 15px rgba(192, 132, 252, 0.6);\n    position: relative;\n    z-index: 1;\n\">\n    Check all data structure\n</h1>\n","metadata":{}},{"cell_type":"code","source":"def analyze_data_structure():\n    base_path = '/kaggle/input/recodai-luc-scientific-image-forgery-detection'\n    \n    # Checking train images\n    train_authentic_path = os.path.join(base_path, 'train_images/authentic')\n    train_forged_path = os.path.join(base_path, 'train_images/forged')\n    train_masks_path = os.path.join(base_path, 'train_masks')\n    test_images_path = os.path.join(base_path, 'test_images')\n    \n    print(f\"Authentic images: {len(os.listdir(train_authentic_path))}\")\n    print(f\"Forged images: {len(os.listdir(train_forged_path))}\")\n    print(f\"Masks: {len(os.listdir(train_masks_path))}\")\n    print(f\"Test images: {len(os.listdir(test_images_path))}\")\n    \n    # Let's analyze some examples of masks\n    mask_files = os.listdir(train_masks_path)[:5]\n    print(f\"Examples of mask files: {mask_files}\")\n    \n    # Checking the mask format\n    sample_mask = np.load(os.path.join(train_masks_path, mask_files[0]))\n    print(f\"Mask format: {sample_mask.shape}, dtype: {sample_mask.dtype}\")\n    \n    test_files = os.listdir(test_images_path)\n    print(f\"Test images: {test_files}\")\n    \n    return {\n        'train_authentic': train_authentic_path,\n        'train_forged': train_forged_path,\n        'train_masks': train_masks_path,\n        'test_images': test_images_path\n    }\n\npaths = analyze_data_structure()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:16.450412Z","iopub.execute_input":"2025-12-29T11:30:16.450714Z","iopub.status.idle":"2025-12-29T11:30:16.507913Z","shell.execute_reply.started":"2025-12-29T11:30:16.450692Z","shell.execute_reply":"2025-12-29T11:30:16.507205Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<div style=\"\n    background: linear-gradient(135deg, #2a103b 0%, #3f1d54 50%, #5e2d7f 100%);\n    border: 2px solid #c084fc;\n    border-radius: 15px;\n    padding: 25px;\n    margin: 20px 0;\n    box-shadow: 0 0 30px rgba(192, 132, 252, 0.4),\n                inset 0 0 20px rgba(255, 255, 255, 0.1);\n    color: #f5f3ff;\n    font-family: 'Segoe UI', system-ui, sans-serif;\n    position: relative;\n    overflow: hidden;\n\">\n\n<div style=\"\n    position: absolute;\n    top: -20px;\n    right: -20px;\n    width: 100px;\n    height: 100px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.25) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<div style=\"\n    position: absolute;\n    bottom: -40px;\n    left: -40px;\n    width: 120px;\n    height: 120px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.2) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<h1 style=\"\n    color: #c084fc;\n    margin: 0 0 20px 0;\n    text-align: center;\n    font-weight: 700;\n    font-size: 1.8em;\n    text-shadow: 0 0 15px rgba(192, 132, 252, 0.6);\n    position: relative;\n    z-index: 1;\n\">\n    🌟 Let's take a look at the image\n</h1>\n\n<div style=\"\n    background: rgba(255, 255, 255, 0.05);\n    border-radius: 10px;\n    padding: 20px;\n    position: relative;\n    z-index: 1;\n\">\n    <h3 style=\"\n        color: #c084fc;\n        margin-top: 0;\n        font-size: 1.3em;\n        display: flex;\n        align-items: center;\n        gap: 10px;\n    \">\n        Types:\n    </h3>\n    <ul style=\"\n        color: #f5f3ff;\n        font-size: 1.1em;\n        line-height: 1.6;\n        margin-bottom: 0;\n    \">\n        <li>Authentic: Real images without manipulation</li>\n        <li>Tampered: Areas that have been manipulated</li>\n    </ul>\n</div>\n","metadata":{}},{"cell_type":"code","source":"num_samples = 3 # counts images/masks\n\n# Visualize authentic images\nauthentic_files = sorted(os.listdir(paths['train_authentic']))[:num_samples]\nforged_files = sorted(os.listdir(paths['train_forged']))[:num_samples]\nmask_files = sorted(os.listdir(paths['train_masks']))[:num_samples]\n    \nfig, axes = plt.subplots(3, num_samples, figsize=(15, 10))\n    \n# Authentic images\nfor i, file in enumerate(authentic_files):\n    img_path = os.path.join(paths['train_authentic'], file)\n    img = Image.open(img_path)\n    axes[0, i].imshow(img)\n    axes[0, i].set_title(f'Authentic: {file}')\n    axes[0, i].axis('off')\n    \n# Forged images\nfor i, file in enumerate(forged_files):\n    img_path = os.path.join(paths['train_forged'], file)\n    img = Image.open(img_path)\n    axes[1, i].imshow(img)\n    axes[1, i].set_title(f'Forged: {file}')\n    axes[1, i].axis('off')\n    \n# Masks\nfor i, file in enumerate(mask_files):\n    mask_path = os.path.join(paths['train_masks'], file)\n    mask = np.load(mask_path)\n    mask = np.squeeze(mask)\n    axes[2, i].imshow(mask, cmap='gray')\n    axes[2, i].set_title(f'Mask: {file}')\n    axes[2, i].axis('off')\n    \nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:16.508802Z","iopub.execute_input":"2025-12-29T11:30:16.509081Z","iopub.status.idle":"2025-12-29T11:30:18.106323Z","shell.execute_reply.started":"2025-12-29T11:30:16.509045Z","shell.execute_reply":"2025-12-29T11:30:18.105433Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Select a random subset of authentic images\nnum_images_to_show = 12  # 3x4 grid\nrandom_authentic_images = random.sample(authentic_images, min(num_images_to_show, len(authentic_images)))\n\n# Display the images in a grid\nfig, axes = plt.subplots(3, 4, figsize=(10, 8))\naxes = axes.flatten()\n\nfor i, img_path in enumerate(random_authentic_images):\n    img = mpimg.imread(img_path)\n    axes[i].imshow(img)\n    axes[i].axis('off') # Hide axes\n    axes[i].set_title(os.path.basename(img_path), fontsize=8) # Add filename as title\n\n# Hide any unused subplots\nfor j in range(i + 1, len(axes)):\n    axes[j].axis('off')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:18.107390Z","iopub.execute_input":"2025-12-29T11:30:18.107717Z","iopub.status.idle":"2025-12-29T11:30:19.689861Z","shell.execute_reply.started":"2025-12-29T11:30:18.107690Z","shell.execute_reply":"2025-12-29T11:30:19.689090Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Assuming the masks are in a 'train_masks' directory within the data_dir\nmask_dir = os.path.join(PATH_DATASET, 'train_masks')\n\n# Find all .npy files in the train_masks directory and store in a dictionary\nmask_files_dict = {}\nmask_files = glob.glob(os.path.join(mask_dir, '*.npy'))\nmask_files += glob.glob(os.path.join(PATH_DATASET, 'supplemental_masks', '*.npy'))\nfor mask_path in mask_files:\n    basename = os.path.basename(mask_path)\n    filename_without_extension, _ = os.path.splitext(basename) # Remove extension\n    mask_files_dict[filename_without_extension] = mask_path\n\nprint(f\"Found {len(mask_files_dict)} mask files and stored in a dictionary with keys as filenames without extensions.\")\nmask_dict = [f\"{k}: {v}\" for k, v in list(mask_files_dict.items())]\nprint(\"\\n\".join(mask_dict[:5]))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:19.691143Z","iopub.execute_input":"2025-12-29T11:30:19.691791Z","iopub.status.idle":"2025-12-29T11:30:19.713092Z","shell.execute_reply.started":"2025-12-29T11:30:19.691753Z","shell.execute_reply":"2025-12-29T11:30:19.712492Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load all masks and store their shapes\nall_mask_shapes = []\nfor filename_without_extension, mask_path in tqdm(mask_files_dict.items()):\n    mask = np.load(mask_path)\n    all_mask_shapes.append(len(mask.shape))\n\nprint(f\"Loaded shapes for {len(all_mask_shapes)} masks.\")\nprint(\"Mask shapes:\", set(all_mask_shapes))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:19.713850Z","iopub.execute_input":"2025-12-29T11:30:19.714089Z","iopub.status.idle":"2025-12-29T11:30:46.192813Z","shell.execute_reply.started":"2025-12-29T11:30:19.714069Z","shell.execute_reply":"2025-12-29T11:30:46.192037Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_mask(mask_path: str):\n    mask_raw = np.load(mask_path)\n    # Sum across the first dimension and binarize: 1 if any channel has a value > 0, 0 otherwise.\n    mask = np.zeros_like(mask_raw[0, :, :], dtype=np.uint8)\n    for c in range(mask_raw.shape[0]):\n        mask[mask_raw[c, :, :] > 0] = c + 1\n    return mask","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:46.193689Z","iopub.execute_input":"2025-12-29T11:30:46.193950Z","iopub.status.idle":"2025-12-29T11:30:46.198429Z","shell.execute_reply.started":"2025-12-29T11:30:46.193929Z","shell.execute_reply":"2025-12-29T11:30:46.197743Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Step 1: Match images and masks\n# We'll match based on the base filename (without extension)\nimage_mask_pairs = []\n\nfor image_path in forged_images:\n    image_basename = os.path.basename(image_path)\n    filename_without_extension, _ = os.path.splitext(image_basename)\n    mask_path = mask_files_dict[filename_without_extension]\n    image_mask_pairs.append((image_path, mask_path))\n\nprint(f\"Found {len(image_mask_pairs)} image-mask pairs.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:46.199241Z","iopub.execute_input":"2025-12-29T11:30:46.199475Z","iopub.status.idle":"2025-12-29T11:30:46.218160Z","shell.execute_reply.started":"2025-12-29T11:30:46.199445Z","shell.execute_reply":"2025-12-29T11:30:46.217427Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define a list of colors for the different mask levels (excluding background 0)\n# You can customize this list with more colors if you expect more levels\nmask_colors = ['red', 'blue', 'green', 'purple', 'orange', 'brown', 'pink', 'gray', 'olive', 'cyan']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:46.218980Z","iopub.execute_input":"2025-12-29T11:30:46.219284Z","iopub.status.idle":"2025-12-29T11:30:46.231265Z","shell.execute_reply.started":"2025-12-29T11:30:46.219265Z","shell.execute_reply":"2025-12-29T11:30:46.230469Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Step 2: Select random subset\nnum_pairs_to_show = 12 # For a 12-row grid\nrandom_pairs = random.sample(image_mask_pairs, min(num_pairs_to_show, len(image_mask_pairs)))\n\nfor i, (image_path, mask_path) in enumerate(random_pairs):\n    # Step 3: Visualize in grid (3 columns, num_pairs_to_show rows)\n    fig, axes = plt.subplots(1, 3, figsize=(12, 4)) # Adjust figsize as needed\n    # Display image in the first column\n    img = mpimg.imread(image_path)\n    axes[0].imshow(img)\n    axes[0].axis('off')\n    axes[0].set_title(os.path.basename(image_path), fontsize=8)\n\n    # Load the mask as multilabel\n    mask = load_mask(mask_path)\n    levels = np.unique(mask)[:-1] + 0.5\n\n    # Display image with mask contour in the second column\n    axes[1].imshow(img) # Display the original image\n\n    # Find and draw contours on the second column axes\n    axes[1].contour(mask, levels=levels, colors=mask_colors, linewidths=1)\n    axes[1].axis('off')\n    axes[1].set_title(\"Mask Contour\", fontsize=8)\n\n    # Display mask in the third column\n    # Assuming the mask is a grayscale or binary image, adjust colormap if necessary\n    axes[2].imshow(mask, cmap='viridis', interpolation='nearest')\n    axes[2].axis('off')\n    axes[2].set_title(os.path.basename(mask_path), fontsize=8)\n    fig.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:46.232222Z","iopub.execute_input":"2025-12-29T11:30:46.232487Z","iopub.status.idle":"2025-12-29T11:30:50.920237Z","shell.execute_reply.started":"2025-12-29T11:30:46.232460Z","shell.execute_reply":"2025-12-29T11:30:50.919643Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<div style=\"\n    background: linear-gradient(135deg, #2a103b 0%, #3f1d54 50%, #5e2d7f 100%);\n    border: 2px solid #c084fc;\n    border-radius: 15px;\n    padding: 25px;\n    margin: 20px 0;\n    box-shadow: 0 0 30px rgba(192, 132, 252, 0.4),\n                inset 0 0 20px rgba(255, 255, 255, 0.1);\n    color: #f5f3ff;\n    font-family: 'Segoe UI', system-ui, sans-serif;\n    position: relative;\n    overflow: hidden;\n\">\n\n<div style=\"\n    position: absolute;\n    top: -20px;\n    right: -20px;\n    width: 100px;\n    height: 100px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.25) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<div style=\"\n    position: absolute;\n    bottom: -40px;\n    left: -40px;\n    width: 120px;\n    height: 120px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.2) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<h1 style=\"\n    color: #c084fc;\n    margin: 0 0 20px 0;\n    text-align: center;\n    font-weight: 700;\n    font-size: 1.8em;\n    text-shadow: 0 0 15px rgba(192, 132, 252, 0.6);\n    position: relative;\n    z-index: 1;\n\">\n    Stats about image sizes\n</h1>\n","metadata":{}},{"cell_type":"code","source":"all_sizes = []\n\n# Authentic images\nfor file in os.listdir(paths['train_authentic'])[:50]:\n    img_path = os.path.join(paths['train_authentic'], file)\n    img = Image.open(img_path)\n    all_sizes.append(img.size)\n\n# Forged images  \nfor file in os.listdir(paths['train_forged'])[:50]:\n    img_path = os.path.join(paths['train_forged'], file)\n    img = Image.open(img_path)\n    all_sizes.append(img.size)\n\nsizes_df = pd.DataFrame(all_sizes, columns=['width', 'height'])\nprint(\"Image size Statistics:\")\nprint(sizes_df.describe())\n\n# Visualization of the size distribution\nplt.figure(figsize=(12, 4))\n\nplt.subplot(1, 2, 1)\nplt.hist(sizes_df['width'], bins=20, alpha=0.7, color='blue')\nplt.title('Width distribution')\nplt.xlabel('Width')\nplt.ylabel('Frequency')\n\nplt.subplot(1, 2, 2)\nplt.hist(sizes_df['height'], bins=20, alpha=0.7, color='red')\nplt.title('Height distribution')\nplt.xlabel('Height')\nplt.ylabel('Frequency')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:50.922981Z","iopub.execute_input":"2025-12-29T11:30:50.923220Z","iopub.status.idle":"2025-12-29T11:30:51.333887Z","shell.execute_reply.started":"2025-12-29T11:30:50.923200Z","shell.execute_reply":"2025-12-29T11:30:51.333083Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<div style=\"\n    background: linear-gradient(135deg, #2a103b 0%, #3f1d54 50%, #5e2d7f 100%);\n    border: 2px solid #c084fc;\n    border-radius: 15px;\n    padding: 25px;\n    margin: 20px 0;\n    box-shadow: 0 0 30px rgba(192, 132, 252, 0.4),\n                inset 0 0 20px rgba(255, 255, 255, 0.1);\n    color: #f5f3ff;\n    font-family: 'Segoe UI', system-ui, sans-serif;\n    position: relative;\n    overflow: hidden;\n\">\n\n<div style=\"\n    position: absolute;\n    top: -20px;\n    right: -20px;\n    width: 100px;\n    height: 100px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.25) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<div style=\"\n    position: absolute;\n    bottom: -40px;\n    left: -40px;\n    width: 120px;\n    height: 120px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.2) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<h1 style=\"\n    color: #c084fc;\n    margin: 0 0 20px 0;\n    text-align: center;\n    font-weight: 700;\n    font-size: 1.8em;\n    text-shadow: 0 0 15px rgba(192, 132, 252, 0.6);\n    position: relative;\n    z-index: 1;\n\">\n    Creating a vision foundation model uses ViT as a feature extractor \n</h1>","metadata":{}},{"cell_type":"code","source":"class Decoder(nn.Module):\n    \n    def __init__(self, in_ch=768, out_ch=1):\n        super().__init__()\n        self.net = nn.Sequential(\n            nn.Conv2d(in_ch, 256, 3, padding=1), nn.ReLU(),\n            nn.Conv2d(256, 64, 3, padding=1), nn.ReLU(),\n            nn.Conv2d(64, out_ch, 1)\n        )\n    \n    def forward(self, f, size):\n        return self.net(F.interpolate(f, size=size, mode=\"bilinear\", align_corners=False))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:51.334760Z","iopub.execute_input":"2025-12-29T11:30:51.334967Z","iopub.status.idle":"2025-12-29T11:30:51.340171Z","shell.execute_reply.started":"2025-12-29T11:30:51.334948Z","shell.execute_reply":"2025-12-29T11:30:51.339423Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class DinoSegmenter(nn.Module):\n    \n    def __init__(self, encoder, processor):\n        super().__init__()\n        self.encoder = encoder\n        self.processor = processor\n        self.seg_head = Decoder(768, 1)\n    \n    def forward_features(self, x):\n        imgs = (x*255).clamp(0, 255).byte().permute(0, 2, 3, 1).cpu().numpy()\n        inputs = self.processor(images=list(imgs), return_tensors=\"pt\").to(x.device)\n        \n        with torch.no_grad():\n            feats = self.encoder(**inputs).last_hidden_state\n        \n        B, N, C = feats.shape\n        fmap = feats[:, 1:, :].permute(0, 2, 1)\n        \n        s = int(math.sqrt(N-1))\n        fmap = fmap.reshape(B, C, s, s)\n        \n        return fmap\n    \n    def forward_seg(self, x):\n        fmap = self.forward_features(x)\n        return self.seg_head(fmap, (CONFIG.img_size, CONFIG.img_size))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:51.340945Z","iopub.execute_input":"2025-12-29T11:30:51.341203Z","iopub.status.idle":"2025-12-29T11:30:51.355394Z","shell.execute_reply.started":"2025-12-29T11:30:51.341184Z","shell.execute_reply":"2025-12-29T11:30:51.354768Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<div style=\"\n    background: linear-gradient(135deg, #2d0c3a 0%, #4a1a5e 50%, #6b2d7b 100%);\n    border: 2px solid #c084fc;\n    border-radius: 15px;\n    padding: 25px;\n    margin: 20px 0;\n    box-shadow: 0 0 30px rgba(192, 132, 252, 0.4),\n                inset 0 0 20px rgba(255, 255, 255, 0.1);\n    color: #f1e8ff;\n    font-family: 'Segoe UI', system-ui, sans-serif;\n    position: relative;\n    overflow: hidden;\n\">\n\n<div style=\"\n    position: absolute;\n    top: -20px;\n    right: -20px;\n    width: 100px;\n    height: 100px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.25) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<div style=\"\n    position: absolute;\n    bottom: -40px;\n    left: -40px;\n    width: 120px;\n    height: 120px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.2) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<h1 style=\"\n    color: #e9d5ff;\n    margin: 0 0 20px 0;\n    text-align: center;\n    font-weight: 700;\n    font-size: 1.8em;\n    text-shadow: 0 0 15px rgba(216, 180, 254, 0.7);\n    position: relative;\n    z-index: 1;\n\">\n    Learn our vision foundation model\n</h1>\n\n</div>","metadata":{}},{"cell_type":"code","source":"class Model(nn.Module):\n    \n    def __init__(self):\n        super().__init__()\n        self.encoder = nn.Sequential(\n            nn.Conv2d(3, 32, 3, padding=1), nn.ReLU(),\n            nn.Conv2d(32, 32, 3, padding=1), nn.ReLU(),\n            nn.MaxPool2d(2),\n            nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(),\n            nn.Conv2d(64, 64, 3, padding=1), nn.ReLU(),\n            nn.MaxPool2d(2),\n        )\n        \n        self.decoder = nn.Sequential(\n            nn.Conv2d(64, 32, 3, padding=1), nn.ReLU(),\n            nn.Upsample(scale_factor=2, mode='bilinear'),\n            nn.Conv2d(32, 32, 3, padding=1), nn.ReLU(),\n            nn.Upsample(scale_factor=2, mode='bilinear'),\n            nn.Conv2d(32, 1, 1),\n        )\n    \n    def forward(self, x):\n        x = self.encoder(x)\n        x = self.decoder(x)\n        x = F.interpolate(x, size=(CONFIG.img_size, CONFIG.img_size), mode='bilinear', align_corners=False)\n        \n        return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:51.356196Z","iopub.execute_input":"2025-12-29T11:30:51.356435Z","iopub.status.idle":"2025-12-29T11:30:51.374250Z","shell.execute_reply.started":"2025-12-29T11:30:51.356409Z","shell.execute_reply":"2025-12-29T11:30:51.373521Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<div style=\"\n    background: linear-gradient(135deg, #2d0c3a 0%, #4a1a5e 50%, #6b2d7b 100%);\n    border: 2px solid #c084fc;\n    border-radius: 15px;\n    padding: 25px;\n    margin: 20px 0;\n    box-shadow: 0 0 30px rgba(192, 132, 252, 0.4),\n                inset 0 0 20px rgba(255, 255, 255, 0.1);\n    color: #f6edff;\n    font-family: 'Segoe UI', system-ui, sans-serif;\n    position: relative;\n    overflow: hidden;\n\">\n\n<div style=\"\n    position: absolute;\n    top: -20px;\n    right: -20px;\n    width: 100px;\n    height: 100px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.25) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<div style=\"\n    position: absolute;\n    bottom: -40px;\n    left: -40px;\n    width: 120px;\n    height: 120px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.2) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<h1 style=\"\n    color: #e9d5ff;\n    margin: 0 0 20px 0;\n    text-align: center;\n    font-weight: 700;\n    font-size: 1.8em;\n    text-shadow: 0 0 15px rgba(216, 180, 254, 0.7);\n    position: relative;\n    z-index: 1;\n\">\n    Load and preprocess test images\n</h1>\n</div>\n","metadata":{}},{"cell_type":"code","source":"def load_model(model_path):\n    try:\n        checkpoint = torch.load(model_path, map_location=CONFIG.device)\n        \n        if isinstance(checkpoint, dict):\n            state_dict = None\n            if 'model_state_dict' in checkpoint:\n                state_dict = checkpoint['model_state_dict']\n            elif 'state_dict' in checkpoint:\n                state_dict = checkpoint['state_dict']\n            elif 'model' in checkpoint:\n                model = checkpoint['model']\n                if hasattr(model, 'eval'):\n                    model.eval()\n                return model.to(CONFIG.device)\n            else:\n                state_dict = checkpoint\n            \n            try:\n                processor = AutoImageProcessor.from_pretrained(CONFIG.dino_path, local_files_only=True)\n                encoder = AutoModel.from_pretrained(CONFIG.dino_path, local_files_only=True).eval().to(CONFIG.device)\n                model = DinoSegmenter(encoder, processor).to(CONFIG.device)\n                \n                if state_dict is not None:\n                    model.load_state_dict(state_dict, strict=False)\n                \n                model.eval()\n                return model\n            except:\n                try:\n                    model = Model().to(CONFIG.device)\n                    if state_dict is not None:\n                        model.load_state_dict(state_dict, strict=False)\n                    model.eval()\n                    return model\n                except:\n                    return None\n        \n        elif hasattr(checkpoint, 'eval'):\n            checkpoint.eval()\n            return checkpoint.to(CONFIG.device)\n        \n        return None\n    except Exception as e:\n        print(f\"Error {Path(model_path).name}: {e}\")\n        return None","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:51.375049Z","iopub.execute_input":"2025-12-29T11:30:51.375329Z","iopub.status.idle":"2025-12-29T11:30:51.391494Z","shell.execute_reply.started":"2025-12-29T11:30:51.375308Z","shell.execute_reply":"2025-12-29T11:30:51.390933Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict_with_tta(model, image_tensor):\n    predictions = []\n    \n    with torch.no_grad():\n        if hasattr(model, 'forward_seg'):\n            pred = torch.sigmoid(model.forward_seg(image_tensor))\n        else:\n            pred = torch.sigmoid(model(image_tensor))\n    \n    predictions.append(pred)\n    \n    with torch.no_grad():\n        if hasattr(model, 'forward_seg'):\n            pred = torch.sigmoid(model.forward_seg(torch.flip(image_tensor, dims=[3])))\n        else:\n            pred = torch.sigmoid(model(torch.flip(image_tensor, dims=[3])))\n    \n    predictions.append(torch.flip(pred, dims=[3]))\n    \n    with torch.no_grad():\n        if hasattr(model, 'forward_seg'):\n            pred = torch.sigmoid(model.forward_seg(torch.flip(image_tensor, dims=[2])))\n        else:\n            pred = torch.sigmoid(model(torch.flip(image_tensor, dims=[2])))\n    \n    predictions.append(torch.flip(pred, dims=[2]))\n    \n    if CONFIG.use_tta:\n        with torch.no_grad():\n            if hasattr(model, 'forward_seg'):\n                pred = torch.sigmoid(model.forward_seg(torch.rot90(image_tensor, 1, [2, 3])))\n            else:\n                pred = torch.sigmoid(model(torch.rot90(image_tensor, 1, [2, 3])))\n        \n        predictions.append(torch.rot90(pred, -1, [2, 3]))\n        \n        return torch.stack(predictions).mean(0)[0, 0].detach().cpu().numpy()\n    else:\n        return predictions[0][0, 0].detach().cpu().numpy()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:51.392295Z","iopub.execute_input":"2025-12-29T11:30:51.393281Z","iopub.status.idle":"2025-12-29T11:30:51.412912Z","shell.execute_reply.started":"2025-12-29T11:30:51.393248Z","shell.execute_reply":"2025-12-29T11:30:51.412087Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def postprocess(pred, original_size):\n    pred = cv2.GaussianBlur(pred, (3, 3), 0)\n    mean_val = np.mean(pred)\n    std_val = np.std(pred)\n    thr = mean_val + 0.3 * std_val\n    mask = (pred > thr).astype(np.uint8)\n    \n    if mask.sum() > 0:\n        num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(mask, connectivity=8)\n        for i in range(1, num_labels):\n            if stats[i, cv2.CC_STAT_AREA] < 30:\n                mask[labels == i] = 0\n        \n        mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((5, 5), np.uint8))\n        mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, np.ones((3, 3), np.uint8))\n    \n    mask = cv2.resize(mask, original_size, interpolation=cv2.INTER_NEAREST)\n    return mask","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:51.413865Z","iopub.execute_input":"2025-12-29T11:30:51.414146Z","iopub.status.idle":"2025-12-29T11:30:51.432306Z","shell.execute_reply.started":"2025-12-29T11:30:51.414125Z","shell.execute_reply":"2025-12-29T11:30:51.431647Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def rle_encode(mask):\n    pixels = mask.T.flatten()\n    dots = np.where(pixels == 1)[0]\n    \n    if len(dots) == 0:\n        return \"authentic\"\n    \n    run_lengths = []\n    prev = -2\n    \n    for b in dots:\n        if b > prev + 1:\n            run_lengths.extend((b + 1, 0))\n        run_lengths[-1] += 1\n        prev = b\n    \n    return json.dumps([int(x) for x in run_lengths])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:51.433177Z","iopub.execute_input":"2025-12-29T11:30:51.433399Z","iopub.status.idle":"2025-12-29T11:30:51.450071Z","shell.execute_reply.started":"2025-12-29T11:30:51.433381Z","shell.execute_reply":"2025-12-29T11:30:51.449374Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model1 = load_model(CONFIG.model1_path)\nmodel2 = load_model(CONFIG.model2_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:51.450827Z","iopub.execute_input":"2025-12-29T11:30:51.451012Z","iopub.status.idle":"2025-12-29T11:30:59.088894Z","shell.execute_reply.started":"2025-12-29T11:30:51.450996Z","shell.execute_reply":"2025-12-29T11:30:59.088034Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"models = {}\nif model1:\n    models['model1'] = model1\n    print(f\"model 1 success!\")\nif model2:\n    models['model2'] = model2\n    print(f\"model 2 success!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:59.089993Z","iopub.execute_input":"2025-12-29T11:30:59.090464Z","iopub.status.idle":"2025-12-29T11:30:59.094891Z","shell.execute_reply.started":"2025-12-29T11:30:59.090432Z","shell.execute_reply":"2025-12-29T11:30:59.094142Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions = []\nimage_files = sorted([f for f in os.listdir(CONFIG.test_images_path) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.tiff', '.bmp'))])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:59.095678Z","iopub.execute_input":"2025-12-29T11:30:59.095909Z","iopub.status.idle":"2025-12-29T11:30:59.111100Z","shell.execute_reply.started":"2025-12-29T11:30:59.095891Z","shell.execute_reply":"2025-12-29T11:30:59.110563Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for image_name in image_files:\n    image_path = Path(CONFIG.test_images_path) / image_name\n    image = Image.open(image_path).convert(\"RGB\")\n    \n    original_width, original_height = image.size\n    total_pixels = original_width * original_height\n    \n    min_pixels_threshold = int(total_pixels * CONFIG.min_area_percent / 100.0)\n    \n    image_array = np.array(image.resize((CONFIG.img_size, CONFIG.img_size)), np.float32) / 255\n    image_tensor = torch.from_numpy(image_array).permute(2, 0, 1)[None].to(CONFIG.device)\n    \n    ensemble_preds = []\n    for model in models.values():\n        pred = predict_with_tta(model, image_tensor)\n        ensemble_preds.append(pred)\n    \n    final_pred = np.mean(ensemble_preds, axis=0) if ensemble_preds else np.zeros((CONFIG.img_size, CONFIG.img_size))\n        \n    mask = postprocess(final_pred, (original_width, original_height))\n    mask_pixels = int(mask.sum())\n    \n    if mask_pixels > 0:\n        mask_resized = cv2.resize(mask, (CONFIG.img_size, CONFIG.img_size), interpolation=cv2.INTER_NEAREST)\n        mean_inside = float(final_pred[mask_resized == 1].mean()) if (mask_resized == 1).any() else 0.0\n    else:\n        mean_inside = 0.0\n        \n    if mask_pixels < min_pixels_threshold or mean_inside < CONFIG.min_confidence:\n        annotation = \"authentic\"\n    else:\n        annotation = rle_encode(mask)\n        \n    area_percent = (mask_pixels / total_pixels) * 100 if total_pixels > 0 else 0\n        \n    predictions.append({\n        \"case_id\": Path(image_name).stem,\n        \"annotation\": annotation\n    })","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:30:59.111889Z","iopub.execute_input":"2025-12-29T11:30:59.112122Z","iopub.status.idle":"2025-12-29T11:31:01.400410Z","shell.execute_reply.started":"2025-12-29T11:30:59.112103Z","shell.execute_reply":"2025-12-29T11:31:01.399612Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions_df = pd.DataFrame(predictions)\npredictions_df[\"case_id\"] = predictions_df[\"case_id\"].astype(str)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:31:01.401294Z","iopub.execute_input":"2025-12-29T11:31:01.401576Z","iopub.status.idle":"2025-12-29T11:31:01.407427Z","shell.execute_reply.started":"2025-12-29T11:31:01.401546Z","shell.execute_reply":"2025-12-29T11:31:01.406811Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<div style=\"\n    background: linear-gradient(135deg, #2d0c3a 0%, #4a1a5e 50%, #6b2d7b 100%);\n    border: 2px solid #c084fc;\n    border-radius: 15px;\n    padding: 25px;\n    margin: 20px 0;\n    box-shadow: 0 0 30px rgba(192, 132, 252, 0.4),\n                inset 0 0 20px rgba(255, 255, 255, 0.1);\n    color: #f6edff;\n    font-family: 'Segoe UI', system-ui, sans-serif;\n    position: relative;\n    overflow: hidden;\n\">\n\n<div style=\"\n    position: absolute;\n    top: -20px;\n    right: -20px;\n    width: 100px;\n    height: 100px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.25) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<div style=\"\n    position: absolute;\n    bottom: -40px;\n    left: -40px;\n    width: 120px;\n    height: 120px;\n    background: radial-gradient(circle, rgba(192, 132, 252, 0.2) 0%, transparent 70%);\n    border-radius: 50%;\n\"></div>\n\n<h1 style=\"\n    color: #e9d5ff;\n    margin: 0 0 20px 0;\n    text-align: center;\n    font-weight: 700;\n    font-size: 1.8em;\n    text-shadow: 0 0 15px rgba(216, 180, 254, 0.7);\n    position: relative;\n    z-index: 1;\n\">\n    Create submission file\n</h1>\n</div>","metadata":{}},{"cell_type":"code","source":"submission = pd.read_csv(CONFIG.sample_sub_path)\nsubmission[\"case_id\"] = submission[\"case_id\"].astype(str)\nsubmission = submission[[\"case_id\"]].merge(predictions_df[[\"case_id\", \"annotation\"]], on=\"case_id\", how=\"left\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:31:01.408352Z","iopub.execute_input":"2025-12-29T11:31:01.408647Z","iopub.status.idle":"2025-12-29T11:31:01.440409Z","shell.execute_reply.started":"2025-12-29T11:31:01.408618Z","shell.execute_reply":"2025-12-29T11:31:01.439921Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission[\"annotation\"] = submission[\"annotation\"].fillna(\"authentic\")\nsubmission[[\"case_id\", \"annotation\"]].to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-29T11:31:01.441153Z","iopub.execute_input":"2025-12-29T11:31:01.441423Z","iopub.status.idle":"2025-12-29T11:31:01.450248Z","shell.execute_reply.started":"2025-12-29T11:31:01.441394Z","shell.execute_reply":"2025-12-29T11:31:01.449546Z"}},"outputs":[],"execution_count":null}]}