{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":14774,"databundleVersionId":875431,"sourceType":"competition"},{"sourceId":12208517,"sourceType":"datasetVersion","datasetId":7690742}],"dockerImageVersionId":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Importing Required Libraries","metadata":{}},{"cell_type":"code","source":"import os\nimport copy\nimport timm\nimport random\nimport time\nimport torch\nimport cv2\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.optim.optimizer\nimport concurrent.futures\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom PIL import Image\nfrom collections import OrderedDict\nfrom torch.utils.data import Dataset, DataLoader, Subset, random_split\nfrom torch.cuda import amp\nfrom torchvision import transforms as T\nfrom torchvision.io import read_image\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.utils.class_weight import compute_class_weight\nfrom sklearn.metrics import accuracy_score, confusion_matrix, f1_score, classification_report\nfrom tqdm import tqdm\n\nprint(torch.__version__)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-06-16T04:57:01.939801Z","iopub.execute_input":"2025-06-16T04:57:01.940083Z","iopub.status.idle":"2025-06-16T04:57:16.457016Z","shell.execute_reply.started":"2025-06-16T04:57:01.940054Z","shell.execute_reply":"2025-06-16T04:57:16.456211Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Seeds for Reproducibility","metadata":{}},{"cell_type":"code","source":"def seed_everything(seed):\n    \"\"\"\n    Sets seeds for reproducibility in training.\n\n    Args:\n        seed (int): Seed value to ensure determinism.\n    \"\"\"\n    random.seed(seed)\n    os.environ[\"PYTHONHASHSEED\"] = str(seed)  # Seed for hash-based operations\n    np.random.seed(seed)  # Seed for NumPy\n    torch.manual_seed(seed)  # Seed for PyTorch (CPU)\n    torch.cuda.manual_seed(seed)  # Seed for PyTorch (GPU)\n    torch.backends.cudnn.deterministic = True  # Make CuDNN deterministic\n    torch.backends.cudnn.benchmark = False  # Enable benchmark mode for CuDNN","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T04:57:16.457839Z","iopub.execute_input":"2025-06-16T04:57:16.458360Z","iopub.status.idle":"2025-06-16T04:57:16.463156Z","shell.execute_reply.started":"2025-06-16T04:57:16.458317Z","shell.execute_reply":"2025-06-16T04:57:16.461968Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"seed_everything(42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T04:57:16.463990Z","iopub.execute_input":"2025-06-16T04:57:16.464410Z","iopub.status.idle":"2025-06-16T04:57:16.492589Z","shell.execute_reply.started":"2025-06-16T04:57:16.464352Z","shell.execute_reply":"2025-06-16T04:57:16.491853Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# EDA","metadata":{}},{"cell_type":"code","source":"data = pd.read_csv('../input/aptos2019-blindness-detection/train.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T04:57:16.493519Z","iopub.execute_input":"2025-06-16T04:57:16.493910Z","iopub.status.idle":"2025-06-16T04:57:16.520956Z","shell.execute_reply.started":"2025-06-16T04:57:16.493879Z","shell.execute_reply":"2025-06-16T04:57:16.520323Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('Number of samples: ', data.shape[0])\ndisplay(data.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T04:57:16.521644Z","iopub.execute_input":"2025-06-16T04:57:16.521843Z","iopub.status.idle":"2025-06-16T04:57:16.549279Z","shell.execute_reply.started":"2025-06-16T04:57:16.521825Z","shell.execute_reply":"2025-06-16T04:57:16.548593Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data['diagnosis'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T04:57:16.551718Z","iopub.execute_input":"2025-06-16T04:57:16.551967Z","iopub.status.idle":"2025-06-16T04:57:16.569083Z","shell.execute_reply.started":"2025-06-16T04:57:16.551947Z","shell.execute_reply":"2025-06-16T04:57:16.568325Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"f, ax = plt.subplots(figsize=(14, 8.7))\nax = sns.countplot(x=\"diagnosis\", data=data, palette=\"GnBu_d\")\nsns.despine()\nplt.savefig('Distruption class', dpi=300, transparent=True)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T04:57:16.570252Z","iopub.execute_input":"2025-06-16T04:57:16.570550Z","iopub.status.idle":"2025-06-16T04:57:17.375467Z","shell.execute_reply.started":"2025-06-16T04:57:16.570523Z","shell.execute_reply":"2025-06-16T04:57:17.374294Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Setting the style for the plot\nsns.set_style(\"white\")\n\n# Mapping class labels to their corresponding categories\nlevel_to_category = {\n    0: \"No_DR\",\n    1: \"Mild\",\n    2: \"Moderate\",\n    3: \"Severe\",\n    4: \"Proliferate_DR\"\n}\n\n# Plotting the first 15 images along with their labels\ncount = 1\nplt.figure(figsize=[20, 20])\n\nfor img_name in data['id_code'][:15]:  # Assuming 'train' contains the dataset\n    img = cv2.imread(f\"../input/aptos2019-blindness-detection/train_images/{img_name}.png\")[..., [2, 1, 0]]  # Reading the image\n    \n    # Getting the label (class) for the image\n    label = data[data['id_code'] == img_name]['diagnosis'].values[0]  # Assuming 'diagnosis' is the label column\n    \n    # Setting up the subplot with image and label\n    plt.subplot(5, 5, count)\n    plt.imshow(img)\n    plt.title(f\"Image {count}: {level_to_category[label]}\")  # Display the class label\n    count += 1\n    \n# Display the plot\nplt.savefig('/kaggle/working/imagebeforepreprecssing.png')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T04:57:17.376520Z","iopub.execute_input":"2025-06-16T04:57:17.376888Z","iopub.status.idle":"2025-06-16T04:57:38.294055Z","shell.execute_reply.started":"2025-06-16T04:57:17.376851Z","shell.execute_reply":"2025-06-16T04:57:38.293108Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Data Preprocessing","metadata":{}},{"cell_type":"code","source":"# Function to crop the image based on grayscale threshold\ndef crop_image_from_gray(img, tol=7):\n    if img.ndim == 2:\n        mask = img > tol\n        return img[np.ix_(mask.any(1), mask.any(0))]\n    elif img.ndim == 3:\n        gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n        mask = gray_img > tol\n        \n        check_shape = img[:,:,0][np.ix_(mask.any(1), mask.any(0))].shape[0]\n        if check_shape == 0:  # Image is too dark so that we crop out everything\n            return img  # Return original image\n        else:\n            img1 = img[:,:,0][np.ix_(mask.any(1), mask.any(0))]\n            img2 = img[:,:,1][np.ix_(mask.any(1), mask.any(0))]\n            img3 = img[:,:,2][np.ix_(mask.any(1), mask.any(0))]\n            img = np.stack([img1, img2, img3], axis=-1)\n        return img","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T04:57:38.294988Z","iopub.execute_input":"2025-06-16T04:57:38.295245Z","iopub.status.idle":"2025-06-16T04:57:38.301190Z","shell.execute_reply.started":"2025-06-16T04:57:38.295223Z","shell.execute_reply":"2025-06-16T04:57:38.300344Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Set input and output directories\ninput_dir = '/kaggle/input/aptos2019-blindness-detection/train_images/'\noutput_dir = '/kaggle/working/processed_images/'\n\n# Ensure the output directory exists\nos.makedirs(output_dir, exist_ok=True)\n\n# Load the CSV containing image names and labels\ncsv_path = '/kaggle/input/aptos2019-blindness-detection/train.csv'\ndf = pd.read_csv(csv_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T04:57:38.302118Z","iopub.execute_input":"2025-06-16T04:57:38.302381Z","iopub.status.idle":"2025-06-16T04:57:38.316113Z","shell.execute_reply.started":"2025-06-16T04:57:38.302361Z","shell.execute_reply":"2025-06-16T04:57:38.315210Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def process_image(row, sigmaX=10):\n    sample_image_id = row['id_code']\n    sample_image_file = sample_image_id + '.png'\n    sample_image_path = os.path.join(input_dir, sample_image_file)\n    \n    if os.path.exists(sample_image_path):\n        # Ben Graham's preprocessing\n        image = cv2.imread(sample_image_path)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        image = crop_image_from_gray(image)\n        image = cv2.resize(image, (384, 384))\n        image = cv2.addWeighted(image, 4, cv2.GaussianBlur(image, (0, 0), sigmaX), -4, 128)\n        \n        # Save the processed image to the output directory\n        output_path = os.path.join(output_dir, sample_image_file)\n        cv2.imwrite(output_path, cv2.cvtColor(image, cv2.COLOR_RGB2BGR))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T04:57:38.317030Z","iopub.execute_input":"2025-06-16T04:57:38.317401Z","iopub.status.idle":"2025-06-16T04:57:38.331397Z","shell.execute_reply.started":"2025-06-16T04:57:38.317370Z","shell.execute_reply":"2025-06-16T04:57:38.330571Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Using ThreadPoolExecutor to process images in parallel\nwith concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor:\n    list(tqdm(executor.map(process_image, [row for _, row in df.iterrows()]), total=df.shape[0], desc=\"Processing images\", unit=\"image\"))\n\nprint(\"Processing complete for all images.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T05:12:06.155869Z","iopub.execute_input":"2025-06-16T05:12:06.156210Z","iopub.status.idle":"2025-06-16T05:16:53.718007Z","shell.execute_reply.started":"2025-06-16T05:12:06.156180Z","shell.execute_reply":"2025-06-16T05:16:53.716986Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Setting the style for the plot\nsns.set_style(\"white\")\n\n# Mapping class labels to their corresponding categories`\nlevel_to_category = {\n    0: \"No_DR\",\n    1: \"Mild\",\n    2: \"Moderate\",\n    3: \"Severe\",\n    4: \"Proliferate_DR\"\n}\n\n# Plotting the first 15 images along with their labels\ncount = 1\nplt.figure(figsize=[20, 20])\n\nfor img_name in data['id_code'][:15]:  # Assuming 'train' contains the dataset\n    img = cv2.imread(f\"/kaggle/working/processed_images/{img_name}.png\")[..., [2, 1, 0]]  # Reading the image\n    \n    # Getting the label (class) for the image\n    label = data[data['id_code'] == img_name]['diagnosis'].values[0]  # Assuming 'diagnosis' is the label column\n    \n    # Setting up the subplot with image and label\n    plt.subplot(5, 5, count)\n    plt.imshow(img)\n    plt.title(f\"Image {count}: {level_to_category[label]}\")  # Display the class label\n    count += 1\n\n# Display the plot\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T05:16:53.719128Z","iopub.execute_input":"2025-06-16T05:16:53.719406Z","iopub.status.idle":"2025-06-16T05:16:57.334683Z","shell.execute_reply.started":"2025-06-16T05:16:53.719383Z","shell.execute_reply":"2025-06-16T05:16:57.333414Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Setelah print(\"Processing complete for all images.\")\n\n# ---------------------------------------------------\n# Tampilkan & simpan Before & After untuk 5 sampel\n# ---------------------------------------------------\n\n# Buat direktori untuk menyimpan sampel jika belum ada\nsample_dir = '/kaggle/working/samples_again/'\nos.makedirs(sample_dir, exist_ok=True)\n\n# Ambil 5 sample pertama\nnum_samples = 15\nsample_ids = data['id_code'][:num_samples]\n\nplt.figure(figsize=(12, num_samples * 4))\n\nfor idx, img_name in enumerate(sample_ids):\n    # ---- Before preprocessing ----\n    orig = cv2.imread(os.path.join(input_dir, img_name + '.png'))\n    orig = cv2.cvtColor(orig, cv2.COLOR_BGR2RGB)\n    # Crop abu-abu lalu resize ke 384×384 agar match After\n    orig_cropped = crop_image_from_gray(orig)\n    orig_resized = cv2.resize(orig_cropped, (384, 384))\n    \n    # ---- After preprocessing (Ben Graham) ----\n    proc = cv2.imread(os.path.join(output_dir, img_name + '.png'))[..., [2,1,0]]  # BGR->RGB\n    # (Assume proc sudah 384×384 dari proses sebelumnya)\n\n    # Subplot: dua kolom (Before | After)\n    ax_before = plt.subplot(num_samples, 2, idx * 2 + 1)\n    ax_before.imshow(orig_resized)\n    ax_before.set_title(f\"{img_name} — Before\", fontsize=10)\n    ax_before.axis('off')\n\n    ax_after = plt.subplot(num_samples, 2, idx * 2 + 2)\n    ax_after.imshow(proc)\n    ax_after.set_title(f\"{img_name} — After\", fontsize=10)\n    ax_after.axis('off')\n\n    # Simpan masing-masing sebagai PNG\n    # Konversi kembali ke BGR untuk imwrite\n    orig_bgr = cv2.cvtColor(orig_resized, cv2.COLOR_RGB2BGR)\n    proc_bgr = cv2.cvtColor(proc, cv2.COLOR_RGB2BGR)\n    cv2.imwrite(os.path.join(sample_dir, f\"{img_name}_before.png\"), orig_bgr)\n    cv2.imwrite(os.path.join(sample_dir, f\"{img_name}_after.png\"),  proc_bgr)\n\nplt.tight_layout()\nplt.show()\n\nprint(f\"Sampel saved in {sample_dir}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T05:28:12.944907Z","iopub.execute_input":"2025-06-16T05:28:12.945351Z","iopub.status.idle":"2025-06-16T05:28:24.374210Z","shell.execute_reply.started":"2025-06-16T05:28:12.945311Z","shell.execute_reply":"2025-06-16T05:28:24.373340Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n# ——————————————\n# Definisi Ben Graham preprocessing\n# ——————————————\ndef ben_graham_preprocessing(img, radius=300, sigmaX=10, crop_ratio=0.9):\n    \"\"\"\n    1) Resize so that min-distance-from-center = radius\n    2) Subtract local average (map to 50% gray)\n    3) Center-crop crop_ratio (e.g. 0.9) to remove boundary effects\n    \"\"\"\n    h, w = img.shape[:2]\n    cx, cy = w // 2, h // 2\n    r0 = min(cx, cy)\n    scale = radius / r0\n    img = cv2.resize(img, None, fx=scale, fy=scale, interpolation=cv2.INTER_AREA)\n\n    # subtract local mean → high-pass + 50% gray\n    blur = cv2.GaussianBlur(img, (0, 0), sigmaX)\n    img = cv2.addWeighted(img, 4, blur, -4, 128)\n\n    # center-crop\n    h2, w2 = img.shape[:2]\n    crop_size = int(min(h2, w2) * crop_ratio)\n    x0 = (w2 - crop_size) // 2\n    y0 = (h2 - crop_size) // 2\n    img = img[y0:y0+crop_size, x0:x0+crop_size]\n\n    return img\n\n# ——————————————\n# Setelah print(\"Processing complete for all images.\")\n# ——————————————\n\n# ---------------------------------------------------\n# Tampilkan & simpan Before & After untuk 5 sampel\n# ---------------------------------------------------\n\n# Buat direktori untuk menyimpan sampel jika belum ada\nsample_dir = '/kaggle/working/samples_again/'\nos.makedirs(sample_dir, exist_ok=True)\n\n# Ambil 5 sample pertama\nnum_samples = 15\nsample_ids = data['id_code'][:num_samples]\n\nplt.figure(figsize=(12, num_samples * 4))\n\nfor idx, img_name in enumerate(sample_ids):\n    # ---- Before preprocessing ----\n    orig = cv2.imread(os.path.join(input_dir, img_name + '.png'))\n    orig = cv2.cvtColor(orig, cv2.COLOR_BGR2RGB)\n    #orig_cropped = crop_image_from_gray(orig)            # biar background gelap ter-crop\n    #orig_resized = cv2.resize(orig_cropped, (384, 384))  # ukuran match After\n\n    # ---- After preprocessing (Ben Graham) ----\n    # langsung terapkan Graham ke gambar RGB asli\n    proc = ben_graham_preprocessing(orig, radius=300, sigmaX=10, crop_ratio=0.9)\n    proc = cv2.resize(proc, (384, 384))                  # resize output akhir\n\n    # ---- Plot ----\n    ax_before = plt.subplot(num_samples, 2, idx * 2 + 1)\n    ax_before.imshow(orig_resized)\n    ax_before.set_title(f\"{img_name} — Before\", fontsize=10)\n    ax_before.axis('off')\n\n    ax_after = plt.subplot(num_samples, 2, idx * 2 + 2)\n    ax_after.imshow(proc)\n    ax_after.set_title(f\"{img_name} — After\", fontsize=10)\n    ax_after.axis('off')\n\n    # ---- Save PNGs ----\n    orig_bgr = cv2.cvtColor(orig_resized, cv2.COLOR_RGB2BGR)\n    proc_bgr = cv2.cvtColor(proc,       cv2.COLOR_RGB2BGR)\n    cv2.imwrite(os.path.join(sample_dir, f\"{img_name}_before.png\"), orig_bgr)\n    cv2.imwrite(os.path.join(sample_dir, f\"{img_name}_after.png\"),  proc_bgr)\n\nplt.tight_layout()\nplt.show()\n\nprint(f\"Sampel saved in {sample_dir}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-16T05:26:38.709843Z","iopub.execute_input":"2025-06-16T05:26:38.710211Z","iopub.status.idle":"2025-06-16T05:26:49.988355Z","shell.execute_reply.started":"2025-06-16T05:26:38.710178Z","shell.execute_reply":"2025-06-16T05:26:49.987307Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n# 1) Fungsi crop background abu-abu\n# Function to crop the image based on grayscale threshold\ndef crop_image_from_gray(img, tol=7):\n    if img.ndim == 2:\n        mask = img > tol\n        return img[np.ix_(mask.any(1), mask.any(0))]\n    elif img.ndim == 3:\n        gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)\n        mask = gray_img > tol\n        \n        check_shape = img[:,:,0][np.ix_(mask.any(1), mask.any(0))].shape[0]\n        if check_shape == 0:  # Image is too dark so that we crop out everything\n            return img  # Return original image\n        else:\n            img1 = img[:,:,0][np.ix_(mask.any(1), mask.any(0))]\n            img2 = img[:,:,1][np.ix_(mask.any(1), mask.any(0))]\n            img3 = img[:,:,2][np.ix_(mask.any(1), mask.any(0))]\n            img = np.stack([img1, img2, img3], axis=-1)\n        return img\n\n# 2) Fungsi resize by radius\ndef resize_by_radius(img, target_radius=300):\n    h, w = img.shape[:2]\n    cx, cy = w//2, h//2\n    r0 = min(cx, cy)\n    scale = target_radius / r0\n    return cv2.resize(img, (384, 384))\n\n# 3) Fungsi subtract local mean (high-pass + map mean→128)\ndef highpass_graymapping(img, sigmaX=10):\n    blur = cv2.GaussianBlur(img, (0,0), sigmaX)\n    return cv2.addWeighted(img, 4, cv2.GaussianBlur(img, (0, 0), sigmaX), -4, 128)\n    \n# 4) Fungsi center-crop\ndef center_crop(img, crop_ratio=0.9):\n    h, w = img.shape[:2]\n    c = int(min(h, w) * crop_ratio)\n    x0 = (w - c)//2\n    y0 = (h - c)//2\n    return img[y0:y0+c, x0:x0+c]\n\n# ————————————————————————————————————————————\n# Demo satu gambar\n# ————————————————————————————————————————————\ninput_dir = \"/kaggle/input/aptos2019-blindness-detection/train_images\"\nfname     = \"0083ee8054ee.png\"\n\n# baca & konversi ke RGB\nimg_bgr = cv2.imread(os.path.join(input_dir, fname))\nimg = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)\n\n# Langkah 1: Crop abu-abu\nstep1 = crop_image_from_gray(img)\n\n# Langkah 2: Resize by radius\nstep2 = resize_by_radius(step1, target_radius=384)\n\n# Langkah 3: Subtract local mean\nstep3 = highpass_graymapping(step2, sigmaX=10)\n\n\n\n\n\n# Langkah 2: Resize by radius\nstep4 = resize_by_radius(step1, target_radius=384)\n\n\n# Plot hasil setiap langkah\ntitles = [\"Original\", \n          \"1) Cropping Gray Background\", \n          \"2) Resize to 384px\",\n          \"3) Subtractive Normalization\"\n         ]\nimages = [img\n          , step1, step2, step3\n         ]\n\nplt.figure(figsize=(15, 4))\nfor i, (im, t) in enumerate(zip(images, titles), 1):\n    ax = plt.subplot(1, 5, i)\n    ax.imshow(im.astype(np.uint8))\n    ax.set_title(t, fontsize=10, fontweight='bold')\n    ax.axis(\"off\")\n\nplt.tight_layout()\nplt.savefig(\"preprocessing_steps.png\", dpi=500)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-21T17:19:59.927503Z","iopub.execute_input":"2025-06-21T17:19:59.928071Z","iopub.status.idle":"2025-06-21T17:20:07.595636Z","shell.execute_reply.started":"2025-06-21T17:19:59.928044Z","shell.execute_reply":"2025-06-21T17:20:07.594573Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport glob\nimport numpy as np\nimport matplotlib.pyplot as plt\n\ndef scaleRadius(img, scale):\n    \"\"\"\n    1) Hitung intensitas baris tengah → proyeksi gray (sum channel)\n    2) Tentukan r = (jumlah pixel > mean(gray)/10) / 2\n    3) s = scale / r\n    4) resize img dengan faktor s\n    \"\"\"\n    # ambil baris tengah, sum jika color\n    mid = img.shape[0] // 2\n    if img.ndim == 3:\n        proj = img[mid, :, :].sum(axis=1)\n    else:\n        proj = img[mid, :]\n    thresh = proj.mean() / 10.0\n    mask  = proj > thresh\n    r = mask.sum() / 2.0\n    if r == 0:\n        return img\n    s = scale / r\n    return cv2.resize(img, None, fx=s, fy=s, interpolation=cv2.INTER_AREA)\n\ndef ben_graham_preprocess(img, scale=300):\n    \"\"\"\n    1) scaleRadius\n    2) subtract local mean (high-pass + map to 50% gray)\n    3) mask outer 10% → isi 50% gray\n    \"\"\"\n    # 1) Resize by radius\n    a = scaleRadius(img, scale)\n\n    # 2) Subtract lokal mean\n    sigma = scale / 30.0\n    blur  = cv2.GaussianBlur(a, (0, 0), sigma)\n    a     = cv2.addWeighted(a, 4, blur, -4, 128)\n\n    # 3) Remove outer 10% via circular mask\n    h, w = a.shape[:2]\n    radius = int(min(h, w) * 0.9 / 2)\n    mask   = np.zeros((h, w), dtype=np.uint8)\n    cv2.circle(mask, (w//2, h//2), radius, 1, -1)\n\n    # terapkan mask, di luar lingkaran diisi 128\n    if a.ndim == 3:\n        for c in range(3):\n            a[:,:,c] = a[:,:,c] * mask + 128 * (1-mask)\n    else:\n        a = a * mask + 128 * (1-mask)\n\n    return a\n\n# ————————————————————————————————————————————\n# Demo satu gambar & plot tiap langkah\n# ————————————————————————————————————————————\ninput_dir = \"/kaggle/input/aptos2019-blindness-detection/train_images\"\nfname     = \"000c1434d8d7.png\"\n\n# Load BGR → RGB\nimg_bgr = cv2.imread(os.path.join(input_dir, fname))\nimg     = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)\n\n# Langkah‑langkah Graham\nstep1 = scaleRadius(img, scale=300)\nstep2 = highpass = cv2.GaussianBlur(step1, (0,0), 300/30.0)\nstep2 = cv2.addWeighted(step1, 4, step2, -4, 128)\nstep3 = ben_graham_preprocess(img, scale=300)  # sudah termasuk semua langkah\n\n# Plot\ntitles = [\"Original\",\n          \"1) scaleRadius\",\n          \"2) high-pass + graymap\",\n          \"3) remove outer 10%\"]\nimages = [img, step1, step2, step3]\n\nplt.figure(figsize=(12, 4))\nfor i, (im, t) in enumerate(zip(images, titles), 1):\n    ax = plt.subplot(1, 4, i)\n    ax.imshow(im.astype(np.uint8))\n    ax.set_title(t, fontsize=10, fontweight='bold')\n    ax.axis(\"off\")\n\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-21T17:18:33.745508Z","iopub.execute_input":"2025-06-21T17:18:33.745838Z","iopub.status.idle":"2025-06-21T17:18:35.199792Z","shell.execute_reply.started":"2025-06-21T17:18:33.745814Z","shell.execute_reply":"2025-06-21T17:18:35.198684Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}