{"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":22990,"datasetId":1136396,"databundleVersionId":2048213,"isSourceIdPinned":false},{"sourceType":"datasetVersion","sourceId":14720177,"datasetId":9405435,"databundleVersionId":15567004},{"sourceType":"datasetVersion","sourceId":15903251,"datasetId":9424822,"databundleVersionId":16858538},{"sourceType":"datasetVersion","sourceId":15863985,"datasetId":10170547,"databundleVersionId":16816164}],"dockerImageVersionId":31260,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# ==================================================================================================\n# 1. SETUP & LIBRARIES\n# ==================================================================================================\nprint(\"⚙️ Kütüphaneler Kuruluyor (OpenSlide Devre Dışı, Tifffile Kullanılacak)...\")\n!pip install -q ultralytics tifffile\n!pip install -q git+https://github.com/facebookresearch/segment-anything.git\n\nimport os\nimport glob\nimport sys\nimport gc\nimport cv2\nimport torch\nimport numpy as np\nimport pandas as pd\nimport tifffile\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\nfrom ultralytics import YOLO\nfrom segment_anything import sam_model_registry\n\n# GPU Check\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"✅ Device: {DEVICE}\")\n\n# ==================================================================================================\n# 2. HEDEF WSI'LAR VE DOSYA YOLLARI\n# ==================================================================================================\nTARGET_WSI_IDS = ['26dc41664', '54f2eec69']\n\n# HuBMAP Veriseti Yolları\nHUBMAP_DIR = '/kaggle/input/hubmap-kidney-segmentation'\nTRAIN_IMG_DIR = os.path.join(HUBMAP_DIR, 'train')\nCSV_PATH = os.path.join(HUBMAP_DIR, 'train.csv')\n\n# Model Yolları\nMODEL_SEARCH_PATH = '/kaggle/input/thesis-models'\n\nprint(\"\\n🔍 Modeller Aranıyor...\")\nyolo_files = glob.glob(os.path.join(MODEL_SEARCH_PATH, '**', 'yolo11s_best.pt'), recursive=True)\nif not yolo_files: sys.exit(f\"❌ YOLO Modeli bulunamadı!\")\nyolo_path = yolo_files[0]\nprint(f\"   📂 YOLO: {yolo_path}\")\n\nmedsam_files = glob.glob(os.path.join(MODEL_SEARCH_PATH, '**', 'medsam_best.pth'), recursive=True)\nif not medsam_files: sys.exit(f\"❌ MedSAM Modeli bulunamadı!\")\nmedsam_path = medsam_files[0]\nprint(f\"   📂 MedSAM: {medsam_path}\")\n\n# ==================================================================================================\n# 3. YARDIMCI FONKSİYONLAR VE MODEL YÜKLEME\n# ==================================================================================================\ndef rle2mask(mask_rle, shape):\n    \"\"\"HuBMAP RLE formatını 2D Numpy maskesine çevirir. Shape = (Genişlik, Yükseklik) olmalıdır.\"\"\"\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0] * shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T\n\nprint(\"\\n🔄 Modeller Belleğe Yükleniyor...\")\nmodel_yolo = YOLO(yolo_path)\n\nchkpt = \"sam_vit_b_01ec64.pth\"\nif not os.path.exists(chkpt):\n    !wget -q https://dl.fbaipublicfiles.com/segment_anything/sam_vit_b_01ec64.pth\nmedsam = sam_model_registry[\"vit_b\"](checkpoint=chkpt).to(DEVICE)\nmedsam.load_state_dict(torch.load(medsam_path, map_location=DEVICE))\nmedsam.eval()\n\npixel_mean = np.array([123.675, 116.28, 103.53])\npixel_std = np.array([58.395, 57.12, 57.375])\nkernel = np.ones((5,5), np.uint8)\n\ndf_train = pd.read_csv(CSV_PATH)\nfinal_results = {}\n\n# ==================================================================================================\n# 4. 🏆 THE GOLDEN RUN: WSI TARAMA DÖNGÜSÜ\n# ==================================================================================================\nprint(\"\\n\" + \"=\"*80)\nprint(\"🚀 Starting The Golden Run (Targeted WSI Edition)...\")\nprint(f\"🎯 Hedef WSI'lar: {TARGET_WSI_IDS}\")\nprint(\"=\"*80)\n\nfor wsi_id in TARGET_WSI_IDS:\n    wsi_path = os.path.join(TRAIN_IMG_DIR, f\"{wsi_id}.tiff\")\n    if not os.path.exists(wsi_path):\n        print(f\"❌ HATA: {wsi_path} bulunamadı. Atlanıyor...\")\n        continue\n        \n    print(f\"\\n🔬 İşleniyor: {wsi_id}\")\n    print(\"   TIFF dosyası RAM'e yükleniyor (Level 0 - En yüksek çözünürlük)...\")\n    \n    # 1. 1x1 HATASINI ÇÖZEN KISIM: Sadece Level 0'ı (Asıl resmi) zorla okutuyoruz\n    with tifffile.TiffFile(wsi_path) as tif:\n        wsi_image = tif.pages[0].asarray()\n    \n    # Kanal boyutlarını düzelt (C, H, W geldiyse H, W, C yap)\n    if len(wsi_image.shape) == 3 and wsi_image.shape[0] == 3:\n        wsi_image = np.transpose(wsi_image, (1, 2, 0)) \n    elif len(wsi_image.shape) == 2:\n        wsi_image = cv2.cvtColor(wsi_image, cv2.COLOR_GRAY2RGB)\n    elif len(wsi_image.shape) == 3 and wsi_image.shape[2] > 3:\n        wsi_image = wsi_image[:, :, :3] \n        \n    wsi_h, wsi_w = wsi_image.shape[:2]\n    patch_size = 1024\n    \n    print(f\"   📏 Gerçek Boyutlar: {wsi_w}x{wsi_h}\")\n    \n    # 2. Devasa Boş Tahmin Maskesi\n    wsi_pred_mask = np.zeros((wsi_h, wsi_w), dtype=np.uint8)\n    total_patches = (wsi_h // patch_size + 1) * (wsi_w // patch_size + 1)\n    skipped = 0\n    \n    # 3. Kayan Pencere (Sliding Window) Döngüsü\n    with tqdm(total=total_patches, desc=f\"Scanning {wsi_id}\", unit=\"patch\") as pbar:\n        for y in range(0, wsi_h, patch_size):\n            for x in range(0, wsi_w, patch_size):\n                try:\n                    img_slice = wsi_image[y:y+patch_size, x:x+patch_size]\n                    \n                    img = np.zeros((patch_size, patch_size, 3), dtype=np.uint8)\n                    img[:img_slice.shape[0], :img_slice.shape[1]] = img_slice[:, :, :3]\n                    \n                    final_pred_mask = np.zeros((1024, 1024), dtype=np.uint8)\n                    \n                    # HSV Filtresi\n                    hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)\n                    if hsv[:, :, 1].mean() < 8: \n                        skipped += 1\n                    else:\n                        # YOLO\n                        yolo_res = model_yolo.predict(img, conf=0.20, verbose=False)\n                        boxes = yolo_res[0].boxes.xyxy.cpu().numpy()\n                        \n                        if len(boxes) > 0:\n                            for box in boxes:\n                                x1, y1, x2, y2 = box\n                                x1 = max(0, x1); y1 = max(0, y1)\n                                x2 = min(1024, x2); y2 = min(1024, y2)\n                                \n                                # MedSAM\n                                box_t = torch.tensor([[x1, y1, x2, y2]]).float().to(DEVICE).unsqueeze(1)\n                                img_norm = (img - pixel_mean) / pixel_std\n                                img_t = torch.tensor(img_norm).permute(2, 0, 1).float().unsqueeze(0).to(DEVICE)\n                                \n                                with torch.no_grad():\n                                    img_embed = medsam.image_encoder(img_t)\n                                    sparse, dense = medsam.prompt_encoder(points=None, boxes=box_t, masks=None)\n                                    masks_pred, iou_pred = medsam.mask_decoder(\n                                        image_embeddings=img_embed,\n                                        image_pe=medsam.prompt_encoder.get_dense_pe(),\n                                        sparse_prompt_embeddings=sparse, dense_prompt_embeddings=dense, multimask_output=True \n                                    )\n                                    best_idx = torch.argmax(iou_pred, dim=1)[0]\n                                    m_prob = torch.sigmoid(masks_pred[0, best_idx, :, :])\n                                    m_resized = torch.nn.functional.interpolate(\n                                        m_prob.unsqueeze(0).unsqueeze(0), size=(1024, 1024), mode='bilinear', align_corners=False\n                                    )\n                                    m_bin = (m_resized > 0.5).cpu().numpy().squeeze()\n                                    \n                                    # Shape Filter\n                                    temp_mask = m_bin.astype(np.uint8)\n                                    contours, _ = cv2.findContours(temp_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)\n                                    for cnt in contours:\n                                        area = cv2.contourArea(cnt)\n                                        perimeter = cv2.arcLength(cnt, True)\n                                        if area < 300: continue \n                                        if perimeter > 0:\n                                            circularity = 4 * np.pi * (area / (perimeter * perimeter))\n                                            if circularity > 0.4: \n                                                cv2.drawContours(final_pred_mask, [cnt], -1, 1, thickness=cv2.FILLED)\n\n                    if final_pred_mask.sum() > 0:\n                        final_pred_mask = cv2.morphologyEx(final_pred_mask, cv2.MORPH_CLOSE, kernel)\n                    \n                    wsi_pred_mask[y:y+img_slice.shape[0], x:x+img_slice.shape[1]] = final_pred_mask[:img_slice.shape[0], :img_slice.shape[1]]\n\n                except Exception as e:\n                    pass\n                \n                pbar.update(1)\n\n    print(f\"✅ Tarama tamam. {skipped} boş yama atlandı.\")\n    \n    # 4. Ground Truth (RLE) Oluşturma ve Metrik Hesaplama\n    print(\"📊 Ground Truth çözülüyor ve metrikler hesaplanıyor...\")\n    try:\n        rle_string = df_train[df_train['id'] == wsi_id]['encoding'].values[0]\n        wsi_gt = rle2mask(rle_string, (wsi_w, wsi_h))\n        \n        pred_flat = wsi_pred_mask.flatten().astype(bool)\n        gt_flat = wsi_gt.flatten().astype(bool)\n        \n        intersection = np.logical_and(pred_flat, gt_flat).sum()\n        dice = (2. * intersection + 1e-6) / (pred_flat.sum() + gt_flat.sum() + 1e-6)\n        iou = (intersection + 1e-6) / (np.logical_or(pred_flat, gt_flat).sum() + 1e-6)\n        precision = (intersection + 1e-6) / (pred_flat.sum() + 1e-6)\n        recall = (intersection + 1e-6) / (gt_flat.sum() + 1e-6)\n        \n        final_results[wsi_id] = {'Dice': dice, 'IoU': iou, 'Precision': precision, 'Recall': recall}\n        print(f\"🏅 {wsi_id} -> Dice: {dice:.4f} | IoU: {iou:.4f} | Recall: {recall:.4f}\")\n        \n        # ---------------------------------------------------------\n        # DEBUG GÖRSELLEŞTİRME (2000x2000'lik Merkez Kesiti)\n        # ---------------------------------------------------------\n        print(f\"📸 {wsi_id} için Hata Ayıklama (Debug) görseli oluşturuluyor...\")\n        \n        # Tam merkeze yakın bir nokta seçiyoruz\n        center_y, center_x = wsi_h // 2, wsi_w // 2\n        c_size = 2000\n        \n        # Sınırları taşmamak için güvenlik kontrolü\n        sy = max(0, center_y - c_size // 2)\n        sx = max(0, center_x - c_size // 2)\n        ey = min(wsi_h, sy + c_size)\n        ex = min(wsi_w, sx + c_size)\n        \n        img_crop = wsi_image[sy:ey, sx:ex]\n        gt_crop = wsi_gt[sy:ey, sx:ex]\n        pred_crop = wsi_pred_mask[sy:ey, sx:ex]\n        \n        plt.figure(figsize=(18, 6))\n        \n        plt.subplot(1, 3, 1)\n        plt.title(f\"Orijinal Doku (Crop {c_size}x{c_size})\")\n        plt.imshow(img_crop)\n        plt.axis('off')\n        \n        plt.subplot(1, 3, 2)\n        plt.title(\"Gerçek Maske (Ground Truth - Yeşil)\")\n        plt.imshow(img_crop)\n        if gt_crop.sum() > 0:\n            plt.imshow(np.ma.masked_where(gt_crop == 0, gt_crop), cmap='Greens', alpha=0.6, vmin=0, vmax=1)\n        plt.axis('off')\n        \n        plt.subplot(1, 3, 3)\n        plt.title(\"Model Tahmini (Prediction - Kırmızı)\")\n        plt.imshow(img_crop)\n        if pred_crop.sum() > 0:\n            plt.imshow(np.ma.masked_where(pred_crop == 0, pred_crop), cmap='Reds', alpha=0.6, vmin=0, vmax=1)\n        plt.axis('off')\n        \n        plt.tight_layout()\n        plt.savefig(f'/kaggle/working/debug_visual_{wsi_id}.png')\n        plt.show()\n\n    except Exception as e:\n        print(f\"❌ {wsi_id} metrik/görsel hesaplamasında hata: {e}\")\n        \n    # KAGGLE RAM TEMİZLİĞİ\n    del wsi_pred_mask\n    if 'wsi_gt' in locals(): del wsi_gt\n    if 'wsi_image' in locals(): del wsi_image\n    gc.collect()\n\n# ==================================================================================================\n# 5. FİNAL SONUÇ RAPORU (STANDART SAPMA EKLENDİ)\n# ==================================================================================================\nprint(\"\\n\" + \"=\"*60)\nprint(\"🏆 THE GOLDEN RUN: WSI TEST SONUÇLARI\")\nprint(\"=\"*60)\n\nif final_results:\n    df_results = pd.DataFrame.from_dict(final_results, orient='index')\n    print(df_results.to_string())\n    print(\"-\" * 60)\n    print(\"İstatistiksel Özet (Ortalama ve Standart Sapma):\")\n    # Hem mean hem std hesaplanıp tablo olarak yazdırılır\n    print(df_results.agg(['mean', 'std']).to_string())\nelse:\n    print(\"Test edilecek sonuç bulunamadı.\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}