{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":22990,"databundleVersionId":2048213,"sourceType":"competition"},{"sourceId":13583888,"sourceType":"datasetVersion","datasetId":8630132},{"sourceId":13603633,"sourceType":"datasetVersion","datasetId":8644414},{"sourceId":211097053,"sourceType":"kernelVersion"}],"dockerImageVersionId":31153,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-11-04T15:15:38.263809Z","iopub.execute_input":"2025-11-04T15:15:38.264538Z","iopub.status.idle":"2025-11-04T15:15:38.809441Z","shell.execute_reply.started":"2025-11-04T15:15:38.264507Z","shell.execute_reply":"2025-11-04T15:15:38.808492Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\narchive_path = \"/kaggle/input/ultralytics-for-offline-install/archive.tar.gz\"\n\n# Install silently (no internet needed)\nos.system(f\"pip install --no-deps {archive_path} > /dev/null\")\n\nprint(\"ultralytics installed offline successfully!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-04T15:15:42.427686Z","iopub.execute_input":"2025-11-04T15:15:42.428090Z","iopub.status.idle":"2025-11-04T15:16:44.291537Z","shell.execute_reply.started":"2025-11-04T15:15:42.428064Z","shell.execute_reply":"2025-11-04T15:16:44.290598Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install --no-deps --force-reinstall /kaggle/input/imagecodecs/imagecodecs-2024.9.22-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-04T15:16:44.292929Z","iopub.execute_input":"2025-11-04T15:16:44.293271Z","iopub.status.idle":"2025-11-04T15:16:48.173120Z","shell.execute_reply.started":"2025-11-04T15:16:44.293242Z","shell.execute_reply":"2025-11-04T15:16:48.172153Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import imagecodecs\nprint(\"imagecodecs version:\", imagecodecs.__version__)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-04T15:16:48.174220Z","iopub.execute_input":"2025-11-04T15:16:48.174457Z","iopub.status.idle":"2025-11-04T15:16:48.187285Z","shell.execute_reply.started":"2025-11-04T15:16:48.174431Z","shell.execute_reply":"2025-11-04T15:16:48.186237Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Offline install: ultralytics + dependencies\n\nimport os\n\n# Extract the archive (tar.gz) to a temp folder\nos.system(\"mkdir -p /kaggle/temp_ultra && tar -xzf /kaggle/input/ultralytics-for-offline-install/archive.tar.gz -C /kaggle/temp_ultra\")\n\n# Install from the local wheels, no internet needed\nos.system(\"pip install --no-index --find-links=/kaggle/temp_ultra/packages ultralytics==8.3.40 > /dev/null\")\n\nprint(\"ultralytics and dependencies installed offline!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-04T15:17:37.699731Z","iopub.execute_input":"2025-11-04T15:17:37.699998Z","iopub.status.idle":"2025-11-04T15:19:02.749122Z","shell.execute_reply.started":"2025-11-04T15:17:37.699977Z","shell.execute_reply":"2025-11-04T15:19:02.748238Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from ultralytics import YOLO\nprint(\"Ultralytics imported successfully!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-04T15:19:02.750583Z","iopub.execute_input":"2025-11-04T15:19:02.750886Z","iopub.status.idle":"2025-11-04T15:19:09.552132Z","shell.execute_reply.started":"2025-11-04T15:19:02.750859Z","shell.execute_reply":"2025-11-04T15:19:09.551071Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# HuBMAP Kidney Segmentation - Offline Submission","metadata":{}},{"cell_type":"code","source":"\nimport gc, torch, numpy as np, pandas as pd, tifffile as tiff\nfrom pathlib import Path\nfrom ultralytics import YOLO\n\n# Paths\nDATA = Path(\"/kaggle/input/hubmap-kidney-segmentation/\")\nTEST_DIR = DATA / \"test\"\nSAMPLE_SUB = DATA / \"sample_submission.csv\"\nWEIGHTS = Path(\"/kaggle/input/hubmap-yolo-seg/best.pt\")\nOUT_CSV = Path(\"/kaggle/working/submission.csv\")\n\nSAMPLE_PATH = \"/kaggle/input/hubmap-kidney-segmentation/sample_submission.csv\"\nFINAL_PATH  = \"submission.csv\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-04T15:19:09.552921Z","iopub.execute_input":"2025-11-04T15:19:09.553308Z","iopub.status.idle":"2025-11-04T15:19:09.927930Z","shell.execute_reply.started":"2025-11-04T15:19:09.553288Z","shell.execute_reply":"2025-11-04T15:19:09.927076Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport gc, torch\nfrom pathlib import Path\nfrom PIL import Image, ImageFile\nimport matplotlib.pyplot as plt\nfrom ultralytics import YOLO\nimport tifffile as tiff\nimport imagecodecs\n\n# CONFIG\n\n#TEST_DIR = Path(\"/kaggle/input/hubmap-kidney-segmentation/test\")\nSUB_PATH = Path(\"/kaggle/working/submission.csv\")\nMODEL_PATH = Path(\"/kaggle/input/hubmap-yolo-seg/best.pt\")  # adjust!\nTILE, STRIDE = 512, 512\nDOWNSAMPLE = 2  # 2–4 recommended for safety\n\ndevice = 0 if torch.cuda.is_available() else \"cpu\"\nprint(f\"Device: {device}\")\n\n# Safety setup\nImage.MAX_IMAGE_PIXELS = 3_000_000_000  # allow huge TIFFs\nImageFile.LOAD_TRUNCATED_IMAGES = True\n\n# Safe TIFF reader\ndef read_tiff_safe(path, downsample=2):\n    with tiff.TiffFile(str(path)) as tif:\n        arr = tif.pages[0].asarray()\n    if downsample > 1:\n        arr = arr[::downsample, ::downsample]\n    if arr.ndim == 2:\n        arr = np.stack([arr]*3, -1)\n    elif arr.shape[2] > 3:\n        arr = arr[:, :, :3]\n    return arr\n\n\n# RLE encoder\ndef mask_to_rle(mask):\n    pixels = mask.T.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\n# Tile-based prediction\ndef predict_tiff(model, path, tile=512, stride=512, downsample=2, device=0):\n    img = read_tiff_safe(path, downsample=downsample)\n    if img is None:\n        print(f\"Skipping {path.name} (unreadable TIFF)\")\n        return np.zeros((512, 512), dtype=np.uint8)\n\n    H, W = img.shape[:2]\n    print(f\"🧬 {path.name}: {W}x{H} (downsample={downsample})\")\n\n    full_mask = np.zeros((H, W), dtype=np.uint8)\n    for y in range(0, H, stride):\n        for x in range(0, W, stride):\n            crop = img[y:y+tile, x:x+tile]\n            if crop.shape[0] < tile or crop.shape[1] < tile:\n                pad = np.zeros((tile, tile, 3), dtype=crop.dtype)\n                pad[:crop.shape[0], :crop.shape[1]] = crop\n                crop = pad\n\n            results = model.predict(\n                source=crop,\n                conf=0.1,\n                imgsz=tile,\n                verbose=False,\n                device=device\n            )\n            if results and results[0].masks is not None:\n                mask = results[0].masks.data.sum(0).cpu().numpy()\n                mask = (mask > 0).astype(np.uint8)\n                full_mask[y:y+tile, x:x+tile] = np.maximum(\n                    full_mask[y:y+tile, x:x+tile],\n                    mask[:min(tile, H-y), :min(tile, W-x)]\n                )\n        gc.collect()\n    return full_mask\nimport os\n\n# Dynamically collect all test TIFFs for inference\n\n# Recursively find all .tiff or .tif files\ntest_tiffs = []\nfor root, dirs, files in os.walk(TEST_DIR):\n    for f in files:\n        if f.lower().endswith((\".tiff\", \".tif\")):\n            test_tiffs.append(Path(root) / f)\n\ntest_tiffs = sorted(test_tiffs)\nprint(f\"Found {len(test_tiffs)} test images:\")\nfor t in test_tiffs:\n    print(\"  \", t.name)\n\n# Run inference and build submission\n\nmodel = YOLO(str(MODEL_PATH))\nmodel.to(device)\nprint(\"Model loaded!\")\n\ntest_tiffs = sorted(TEST_DIR.glob(\"*.tiff\"))\npred_rows = []\n\nfor wsi in test_tiffs:\n    mask = predict_tiff(model, wsi, TILE, STRIDE, DOWNSAMPLE, device)\n    rle = mask_to_rle(mask) if mask.sum() > 0 else \"\"\n    pred_rows.append({\"id\": wsi.stem, \"predicted\": rle})\n    gc.collect()\n\n# Save submission\nsub_df = pd.DataFrame(pred_rows)\nsample = pd.read_csv(\"/kaggle/input/hubmap-kidney-segmentation/sample_submission.csv\")\nfinal = sample[[\"id\"]].merge(sub_df, on=\"id\", how=\"left\").fillna(\"\")\nfinal.to_csv(\"submission.csv\", index=False)\nprint(\"Submission saved with\", len(final), \"rows\")\n\n'''\n# Optional overlay preview\n\ntry:\n    preview = test_tiffs[0]\n    print(f\"Rendering overlay for {preview.stem}...\")\n    img = read_tiff_safe(preview, downsample=4)\n    mask = (mask > 0).astype(np.uint8)\n    overlay = img.copy()\n    overlay[mask == 1] = [255, 0, 0]  # red mask overlay\n    plt.figure(figsize=(10, 10))\n    plt.imshow(overlay)\n    plt.title(f\"Overlay: {preview.stem}\")\n    plt.axis(\"off\")\n    plt.show()\nexcept Exception as e:\n    print(\"Visualization skipped:\", e)\n'''","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-04T15:19:09.929984Z","iopub.execute_input":"2025-11-04T15:19:09.930302Z","iopub.status.idle":"2025-11-04T15:57:24.125432Z","shell.execute_reply.started":"2025-11-04T15:19:09.930280Z","shell.execute_reply":"2025-11-04T15:57:24.124352Z"}},"outputs":[],"execution_count":null}]}