{"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":[{"sourceType":"competition","sourceId":117682,"databundleVersionId":15062069}],"dockerImageVersionId":31260,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport zipfile\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\nfrom PIL import Image\nimport tifffile as tiff\nfrom scipy.ndimage import gaussian_filter, label\n\nINPUT_DIR = \"/kaggle/input/vesuvius-challenge-surface-detection\"\nTEST_IMG_DIR = os.path.join(INPUT_DIR, \"test_images\")\nOUTPUT_DIR = \"/kaggle/working/preds\"\nZIP_PATH = \"/kaggle/working/submission.zip\"\n\nos.makedirs(OUTPUT_DIR, exist_ok=True)\n\n# Load test metadata\n\ntest_df = pd.read_csv(os.path.join(INPUT_DIR, \"test.csv\"))\nprint(f\"Found {len(test_df)} test volumes\")\n\n# LZW-safe TIFF reader\n\ndef read_tiff_stack_pil(path):\n    imgs = []\n    with Image.open(path) as img:\n        i = 0\n        while True:\n            try:\n                img.seek(i)\n                imgs.append(np.array(img))\n                i += 1\n            except EOFError:\n                break\n    return np.stack(imgs, axis=0)\n\n# Surface detection\n\ndef improved_surface_detection(volume):\n    \"\"\"\n    Topology-safe surface extraction using:\n    - Z-gradient ridge detection\n    - 3D smoothing\n    - connected component cleanup\n    \"\"\"\n    Z, Y, X = volume.shape\n\n    # normalize\n    v = volume.astype(np.float32)\n    v = (v - v.min()) / (v.max() - v.min() + 1e-6)\n\n    # Z-gradient magnitude\n    grad = np.abs(np.diff(v, axis=0, prepend=v[:1]))\n\n    # smooth gradients\n    grad = gaussian_filter(grad, sigma=(1.2, 1.0, 1.0))\n\n    # per-column normalization\n    grad /= (grad.max(axis=0, keepdims=True) + 1e-6)\n\n    # soft surface probability\n    prob = grad ** 1.5\n\n    # global threshold\n    thresh = np.quantile(prob, 0.88)\n    mask = (prob > thresh).astype(np.uint8)\n\n    # thicken surface conservatively in Z\n    thick = np.zeros_like(mask)\n    for dz in (-1, 0, 1):\n        z0 = max(0, dz)\n        z1 = Z + min(0, dz)\n        thick[z0:z1] |= mask[z0 - dz:z1 - dz]\n    mask = thick\n\n    # keep largest connected component only (26-connectivity)\n    labeled, ncc = label(mask)\n    if ncc > 1:\n        sizes = np.bincount(labeled.ravel())\n        sizes[0] = 0\n        keep = sizes.argmax()\n        mask = (labeled == keep).astype(np.uint8)\n\n    return mask\n\n# Run inference\n\nfor _, row in tqdm(test_df.iterrows(), total=len(test_df)):\n    vid = row[\"id\"]\n    img_path = os.path.join(TEST_IMG_DIR, f\"{vid}.tif\")\n\n    volume = read_tiff_stack_pil(img_path)\n    pred = improved_surface_detection(volume)\n\n    tiff.imwrite(\n        os.path.join(OUTPUT_DIR, f\"{vid}.tif\"),\n        pred.astype(np.uint8)\n    )\n\n# Submission\n\nwith zipfile.ZipFile(ZIP_PATH, \"w\", zipfile.ZIP_DEFLATED) as z:\n    for fname in os.listdir(OUTPUT_DIR):\n        z.write(os.path.join(OUTPUT_DIR, fname), fname)\n\nwith zipfile.ZipFile(ZIP_PATH, \"r\") as z:\n    print(\"Submission created!\")\n    print(\"Files:\", len(z.namelist()))\n    print(\"Example:\", z.namelist()[:5])\n\nprint(\"READY TO SUBMIT:\", ZIP_PATH)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T07:56:08.103064Z","iopub.execute_input":"2026-02-27T07:56:08.103813Z","iopub.status.idle":"2026-02-27T07:56:12.134628Z","shell.execute_reply.started":"2026-02-27T07:56:08.103781Z","shell.execute_reply":"2026-02-27T07:56:12.133970Z"}},"outputs":[],"execution_count":null}]}