{"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":"gpu","dataSources":[{"sourceId":61446,"databundleVersionId":6962461,"sourceType":"competition"}],"dockerImageVersionId":31260,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"![](https://www.bibalex.org/SCIplanet/Attachments/Article/MediumImage/YsutavnirT_20171116115905498.jpg)","metadata":{}},{"cell_type":"code","source":"from keras.models import Model, Sequential\nfrom keras.layers import Activation, Dense, BatchNormalization, Dropout, Conv2D, Conv2DTranspose, MaxPooling2D, UpSampling2D, Input, Reshape\nfrom keras.callbacks import EarlyStopping\nfrom keras import backend as K\nfrom keras.optimizers import Adam, SGD\nimport tensorflow as tf\nimport numpy as np\nimport pandas as pd\nimport glob\nimport PIL\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport cv2\n%matplotlib inline\nfrom PIL import Image\nimport os\nimport re\n\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom sklearn.model_selection import train_test_split\nfrom warnings import filterwarnings\n\nfilterwarnings('ignore')\nplt.rcParams[\"axes.grid\"] = False\nnp.random.seed(101)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:09:19.935492Z","iopub.execute_input":"2026-02-09T10:09:19.935745Z","iopub.status.idle":"2026-02-09T10:09:23.722149Z","shell.execute_reply.started":"2026-02-09T10:09:19.935710Z","shell.execute_reply":"2026-02-09T10:09:23.721548Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"path = \"/kaggle/input/blood-vessel-segmentation\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:09:23.723111Z","iopub.execute_input":"2026-02-09T10:09:23.723683Z","iopub.status.idle":"2026-02-09T10:09:23.727098Z","shell.execute_reply.started":"2026-02-09T10:09:23.723648Z","shell.execute_reply":"2026-02-09T10:09:23.726524Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"numbers = re.compile(r'(\\d+)')\ndef numericalSort(value):\n    parts = numbers.split(value)\n    parts[1::2] = map(int, parts[1::2])\n    return parts\n\ntrain_path = os.path.join(path, \"train\")\n\nfilelist_train = sorted(\n    glob.glob(os.path.join(train_path, \"**\", \"images\", \"*.tif\"), recursive=True),\n    key=numericalSort\n)\n\nIMG_SIZE = 256\n\nX_train = []\n\nfor f in filelist_train:\n    img = cv2.imread(f, cv2.IMREAD_GRAYSCALE)\n    img = cv2.resize(img, (IMG_SIZE, IMG_SIZE))\n    X_train.append(img)\n\nX_train = np.array(X_train)\n\nprint(\"Number of training images:\", len(X_train))\nprint(\"X_train shape:\", X_train.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:09:23.728966Z","iopub.execute_input":"2026-02-09T10:09:23.729274Z","iopub.status.idle":"2026-02-09T10:15:00.808863Z","shell.execute_reply.started":"2026-02-09T10:09:23.729252Z","shell.execute_reply":"2026-02-09T10:15:00.808055Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"filelist_mask = sorted(\n    glob.glob(os.path.join(train_path, \"**\", \"labels\", \"*.tif\"), recursive=True),\n    key=numericalSort\n)\n\nY_train = []\n\nfor f in filelist_mask:\n    mask = cv2.imread(f, cv2.IMREAD_GRAYSCALE)\n    mask = cv2.resize(mask, (IMG_SIZE, IMG_SIZE))\n    Y_train.append(mask)\n\nY_train = np.array(Y_train)\n\nprint(\"Y_train shape:\", Y_train.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:15:00.809726Z","iopub.execute_input":"2026-02-09T10:15:00.809932Z","iopub.status.idle":"2026-02-09T10:17:50.529296Z","shell.execute_reply.started":"2026-02-09T10:15:00.809912Z","shell.execute_reply":"2026-02-09T10:17:50.528469Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from glob import glob\nimport pandas as pd\n\nBASE_PATH = \"/kaggle/input/blood-vessel-segmentation\"\n\nmask_paths = sorted(glob(f\"{BASE_PATH}/train/*/labels/*.tif\"))\n\ndf = pd.DataFrame({\"mask_path\": mask_paths})\n\ndf[\"dataset\"] = df.mask_path.map(lambda x: x.split(\"/\")[-3])\ndf[\"slice\"] = df.mask_path.map(lambda x: x.split(\"/\")[-1].replace(\".tif\", \"\"))\n\ndf = df[~df.dataset.str.contains(\"kidney_3_sparse\")]\n\ndf[\"image_path\"] = df.mask_path.str.replace(\"labels\", \"images\", regex=False)\n\ndf[\"image_path\"] = df.image_path.str.replace(\n    \"kidney_3_dense\",\n    \"kidney_3_sparse\",\n    regex=False\n)\n\ndf.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:17:50.530116Z","iopub.execute_input":"2026-02-09T10:17:50.530339Z","iopub.status.idle":"2026-02-09T10:17:50.600234Z","shell.execute_reply.started":"2026-02-09T10:17:50.530318Z","shell.execute_reply":"2026-02-09T10:17:50.599538Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"CHANNELS = 3\nSTRIDE = 3\n\nfor i in range(CHANNELS):\n    df[f'image_path_{i:02d}'] = df.groupby(['dataset'])['image_path'].shift(-i*STRIDE).ffill()\n\ndf['image_paths'] = df[[f'image_path_{i:02d}' for i in range(CHANNELS)]].values.tolist()\n\ndf.image_paths.iloc[0]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:17:50.601068Z","iopub.execute_input":"2026-02-09T10:17:50.601354Z","iopub.status.idle":"2026-02-09T10:17:50.630671Z","shell.execute_reply.started":"2026-02-09T10:17:50.601332Z","shell.execute_reply":"2026-02-09T10:17:50.630083Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport cv2\nimport random\n\nprint(\"Total samples:\", len(df))\nprint(df['dataset'].value_counts())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:17:50.631441Z","iopub.execute_input":"2026-02-09T10:17:50.631648Z","iopub.status.idle":"2026-02-09T10:17:50.638464Z","shell.execute_reply.started":"2026-02-09T10:17:50.631629Z","shell.execute_reply":"2026-02-09T10:17:50.637732Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img = cv2.imread(df.image_paths.iloc[0][1],0)\n\nplt.figure(figsize=(6,4))\nplt.hist(img.flatten(), bins=100)\nplt.title(\"Pixel Intensity Distribution\")\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:17:50.639516Z","iopub.execute_input":"2026-02-09T10:17:50.639793Z","iopub.status.idle":"2026-02-09T10:17:50.961564Z","shell.execute_reply.started":"2026-02-09T10:17:50.639767Z","shell.execute_reply":"2026-02-09T10:17:50.960909Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"samples = df.sample(5).reset_index(drop=True)\n\nplt.figure(figsize=(10,20))\n\nfor i in range(5):\n    img_path = samples.loc[i, \"image_paths\"][1]\n    mask_path = samples.loc[i, \"mask_path\"]\n\n    img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)\n    mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)\n\n    plt.subplot(5,2,2*i+1)\n    plt.imshow(img, cmap=\"gray\")\n    plt.title(\"Image\")\n    plt.axis(\"off\")\n\n    plt.subplot(5,2,2*i+2)\n    plt.imshow(mask, cmap=\"gray\")\n    plt.title(\"Mask\")\n    plt.axis(\"off\")\n\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:17:50.962384Z","iopub.execute_input":"2026-02-09T10:17:50.962661Z","iopub.status.idle":"2026-02-09T10:17:53.426451Z","shell.execute_reply.started":"2026-02-09T10:17:50.962625Z","shell.execute_reply":"2026-02-09T10:17:53.425680Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IMG_SIZE = 256\nBATCH = 8\nEPOCHS = 30\nLR = 1e-4","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:17:53.427355Z","iopub.execute_input":"2026-02-09T10:17:53.427590Z","iopub.status.idle":"2026-02-09T10:17:53.431619Z","shell.execute_reply.started":"2026-02-09T10:17:53.427567Z","shell.execute_reply":"2026-02-09T10:17:53.430901Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nimport cv2\nimport numpy as np\n\ndef read_image(paths):\n    imgs = []\n    for p in paths:\n        img = cv2.imread(p.decode(),0)\n        img = cv2.resize(img,(IMG_SIZE,IMG_SIZE))\n        imgs.append(img)\n    img = np.stack(imgs,-1)\n    img = img/255.0\n    return img.astype(np.float32)\n\ndef read_mask(path):\n    mask = cv2.imread(path.decode(),0)\n    mask = cv2.resize(mask,(IMG_SIZE,IMG_SIZE))\n    mask = mask/255.0\n    return np.expand_dims(mask,-1).astype(np.float32)\n\ndef tf_parse(x,y):\n    img = tf.numpy_function(read_image,[x],tf.float32)\n    mask = tf.numpy_function(read_mask,[y],tf.float32)\n    img.set_shape((IMG_SIZE,IMG_SIZE,3))\n    mask.set_shape((IMG_SIZE,IMG_SIZE,1))\n    return img,mask\n\ndef build_dataset(df):\n    X = np.array(df.image_paths.tolist())\n    Y = np.array(df.mask_path.tolist())\n    ds = tf.data.Dataset.from_tensor_slices((X,Y))\n    ds = ds.map(tf_parse,num_parallel_calls=tf.data.AUTOTUNE)\n    ds = ds.shuffle(512).batch(BATCH).prefetch(tf.data.AUTOTUNE)\n    return ds\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:17:53.432429Z","iopub.execute_input":"2026-02-09T10:17:53.432784Z","iopub.status.idle":"2026-02-09T10:17:53.445961Z","shell.execute_reply.started":"2026-02-09T10:17:53.432763Z","shell.execute_reply":"2026-02-09T10:17:53.445293Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\ntrain_df,val_df = train_test_split(df,test_size=0.15,random_state=42)\n\ntrain_ds = build_dataset(train_df)\nval_ds = build_dataset(val_df)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:17:53.446855Z","iopub.execute_input":"2026-02-09T10:17:53.447507Z","iopub.status.idle":"2026-02-09T10:17:54.256251Z","shell.execute_reply.started":"2026-02-09T10:17:53.447484Z","shell.execute_reply":"2026-02-09T10:17:54.255542Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.layers import *\nfrom tensorflow.keras.models import Model\n\ndef conv_block(x,f):\n    x = Conv2D(f,3,padding=\"same\")(x)\n    x = BatchNormalization()(x)\n    x = Activation(\"relu\")(x)\n    x = Conv2D(f,3,padding=\"same\")(x)\n    x = BatchNormalization()(x)\n    x = Activation(\"relu\")(x)\n    return x\n\ndef unet():\n    inp = Input((IMG_SIZE,IMG_SIZE,3))\n\n    c1 = conv_block(inp,64); p1 = MaxPooling2D()(c1)\n    c2 = conv_block(p1,128); p2 = MaxPooling2D()(c2)\n    c3 = conv_block(p2,256); p3 = MaxPooling2D()(c3)\n    c4 = conv_block(p3,512); p4 = MaxPooling2D()(c4)\n\n    bn = conv_block(p4,1024)\n\n    u1 = UpSampling2D()(bn); u1 = concatenate([u1,c4])\n    u1 = conv_block(u1,512)\n\n    u2 = UpSampling2D()(u1); u2 = concatenate([u2,c3])\n    u2 = conv_block(u2,256)\n\n    u3 = UpSampling2D()(u2); u3 = concatenate([u3,c2])\n    u3 = conv_block(u3,128)\n\n    u4 = UpSampling2D()(u3); u4 = concatenate([u4,c1])\n    u4 = conv_block(u4,64)\n\n    out = Conv2D(1,1,activation=\"sigmoid\")(u4)\n\n    return Model(inp,out)\n\nmodel = unet()\nmodel.summary()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:17:54.259402Z","iopub.execute_input":"2026-02-09T10:17:54.259607Z","iopub.status.idle":"2026-02-09T10:17:55.876996Z","shell.execute_reply.started":"2026-02-09T10:17:54.259588Z","shell.execute_reply":"2026-02-09T10:17:55.876316Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def dice(y_true,y_pred):\n    smooth=1\n    y_true=tf.reshape(y_true,[-1])\n    y_pred=tf.reshape(y_pred,[-1])\n    inter=tf.reduce_sum(y_true*y_pred)\n    return (2*inter+smooth)/(tf.reduce_sum(y_true)+tf.reduce_sum(y_pred)+smooth)\n\ndef dice_loss(y_true,y_pred):\n    return 1-dice(y_true,y_pred)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:17:55.877996Z","iopub.execute_input":"2026-02-09T10:17:55.878321Z","iopub.status.idle":"2026-02-09T10:17:55.882838Z","shell.execute_reply.started":"2026-02-09T10:17:55.878288Z","shell.execute_reply":"2026-02-09T10:17:55.882190Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = unet()\n\nmodel.compile(\n    optimizer=tf.keras.optimizers.Adam(LR),\n    loss=dice_loss,\n    metrics=[dice]\n)\n\nhistory = model.fit(\n    train_ds,\n    validation_data=val_ds,\n    epochs=EPOCHS\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T10:17:55.883678Z","iopub.execute_input":"2026-02-09T10:17:55.883922Z","iopub.status.idle":"2026-02-09T12:06:00.880331Z","shell.execute_reply.started":"2026-02-09T10:17:55.883893Z","shell.execute_reply":"2026-02-09T12:06:00.877640Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Plot Loss\nplt.figure(figsize=(12,5))\n\nplt.subplot(1,2,1)\nplt.plot(history.history['loss'], label='Training Loss', marker='o')\nplt.plot(history.history['val_loss'], label='Validation Loss', marker='o')\nplt.title('Loss over Epochs')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.legend()\nplt.grid(True)\n\n# Plot Dice Score\nplt.subplot(1,2,2)\nplt.plot(history.history['dice'], label='Training Dice', marker='o')\nplt.plot(history.history['val_dice'], label='Validation Dice', marker='o')\nplt.title('Dice Score over Epochs')\nplt.xlabel('Epoch')\nplt.ylabel('Dice Score')\nplt.legend()\nplt.grid(True)\n\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:07:57.874057Z","iopub.execute_input":"2026-02-09T12:07:57.874703Z","iopub.status.idle":"2026-02-09T12:07:58.275168Z","shell.execute_reply.started":"2026-02-09T12:07:57.874672Z","shell.execute_reply":"2026-02-09T12:07:58.274415Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport glob\nfrom PIL import Image\n\ntest_path = \"/kaggle/input/blood-vessel-segmentation/test/kidney_5/images\"\nsave_path = \"/kaggle/working/test_images_png\"\nos.makedirs(save_path, exist_ok=True)\n\ntif_files = glob.glob(os.path.join(test_path, \"*.tif\"))\n\nfor tif_file in tif_files:\n    img = Image.open(tif_file)\n    base_name = os.path.basename(tif_file).replace(\".tif\", \".png\")\n    png_path = os.path.join(save_path, base_name)\n    img.save(png_path)\n\nprint(f\"Converted {len(tif_files)} images to {save_path}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:16:24.567207Z","iopub.execute_input":"2026-02-09T12:16:24.567962Z","iopub.status.idle":"2026-02-09T12:16:25.264492Z","shell.execute_reply.started":"2026-02-09T12:16:24.567937Z","shell.execute_reply":"2026-02-09T12:16:25.263891Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport numpy as np\n\n# Choose 3 random samples from the validation dataset\nval_images = list(val_ds)  # convert tf.data.Dataset to list\nrandom_samples = np.random.choice(len(val_images), 3, replace=False)\n\nplt.figure(figsize=(12, 12))\nIMG_SIZE = 256  # match your model input\n\nfor i, idx in enumerate(random_samples):\n    img_array, mask_true = val_images[idx]  # unpack image and ground truth mask\n    img_array = img_array[0]  # get image from batch if batch_size=1\n    mask_true = mask_true[0]  # get mask from batch if batch_size=1\n\n    pred = model.predict(img_array[np.newaxis, ...])[0, ..., 0]  # predict mask\n    pred_mask = (pred > 0.5).astype(np.float32)\n\n    # Plot original image\n    plt.subplot(3, 2, i*2 + 1)\n    plt.imshow(img_array)\n    plt.title(\"Image\")\n    plt.axis(\"off\")\n\n    # Plot predicted mask\n    plt.subplot(3, 2, i*2 + 2)\n    plt.imshow(pred_mask, cmap=\"gray\")\n    plt.title(\"Prediction\")\n    plt.axis(\"off\")\n\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-09T12:19:01.667829Z","iopub.execute_input":"2026-02-09T12:19:01.668623Z","iopub.status.idle":"2026-02-09T12:19:16.416150Z","shell.execute_reply.started":"2026-02-09T12:19:01.668590Z","shell.execute_reply":"2026-02-09T12:19:16.415305Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}