{"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":14774,"databundleVersionId":875431,"sourceType":"competition"}],"dockerImageVersionId":31192,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport pandas as pd\nimport shutil\nimport multiprocessing\nfrom tqdm import tqdm\nfrom joblib import Parallel, delayed\n\n# Configuration\nRAW_CSV_PATH = \"/kaggle/input/aptos2019-blindness-detection/train.csv\"\nRAW_IMG_DIR = \"/kaggle/input/aptos2019-blindness-detection/train_images\"\n\n# Output directory settings\nSAVE_DIR = \"./processed_images_224\"\nIMG_SIZE = 224\n\n# Create output directory if it doesn't exist\nif not os.path.exists(SAVE_DIR):\n    os.makedirs(SAVE_DIR)\n\n# Core Image Processing Functions\ndef crop_image_from_gray(img, tol=7):\n    \"\"\"\n    Crops the black background borders from the fundus images.\n    \"\"\"\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_BGR2GRAY)\n        mask = gray_img > tol\n        check_shape = img[:,:,0][np.ix_(mask.any(1), mask.any(0))].shape[0]\n        if (check_shape == 0): \n            return img \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\ndef load_ben_color(image, sigmaX=10):\n    \"\"\"\n    Applies Ben Graham's preprocessing method to enhance vascular contrast.\n    Formula: image = 4 * image - 4 * GaussianBlur(image) + 128\n    \"\"\"\n    image = cv2.addWeighted(image, 4, cv2.GaussianBlur(image, (0,0), sigmaX), -4, 128)\n    return image\n\n# Single Image Wrapper (For Parallelization)\ndef process_single_image(img_name, raw_dir, save_dir, img_size):\n    \"\"\"\n    Pipeline: Read -> Crop -> Resize -> Ben's Color -> Save\n    Returns: Boolean indicating success.\n    \"\"\"\n    img_path = os.path.join(raw_dir, img_name + \".png\")\n    save_path = os.path.join(save_dir, img_name + \".png\")\n    \n    # Optional: Skip if already exists\n    # if os.path.exists(save_path): return True \n\n    try:\n        image = cv2.imread(img_path)\n        if image is None:\n            return False\n            \n        # 1. Crop black borders\n        image = crop_image_from_gray(image)\n        # 2. Resize\n        image = cv2.resize(image, (img_size, img_size))\n        # 3. Ben's Preprocessing\n        image = load_ben_color(image, sigmaX=10)\n        \n        # 4. Save\n        cv2.imwrite(save_path, image)\n        return True\n        \n    except Exception:\n        # Fallback: Create black image to prevent dataloader errors later\n        black_img = np.zeros((img_size, img_size, 3), dtype=np.uint8)\n        cv2.imwrite(save_path, black_img)\n        return False\n\n# Main Execution\nif __name__ == \"__main__\":\n    df = pd.read_csv(RAW_CSV_PATH)\n    \n    # Auto-detect available CPU cores\n    num_cores = multiprocessing.cpu_count()\n    \n    # execute parallel processing\n    # Backend 'threading' is often faster for I/O bound tasks like image saving\n    results = Parallel(n_jobs=num_cores, backend=\"threading\")(\n        delayed(process_single_image)(\n            row['id_code'], \n            RAW_IMG_DIR, \n            SAVE_DIR, \n            IMG_SIZE\n        ) for _, row in tqdm(df.iterrows(), total=len(df), desc=\"Preprocessing\")\n    )\n    \n    # Compress the output folder to a single zip file for easy export/download\n    shutil.make_archive(\"processed_images\", 'zip', SAVE_DIR)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-04T03:09:18.592116Z","iopub.execute_input":"2025-12-04T03:09:18.592430Z","iopub.status.idle":"2025-12-04T03:15:00.119769Z","shell.execute_reply.started":"2025-12-04T03:09:18.592409Z","shell.execute_reply":"2025-12-04T03:15:00.118416Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T06:48:42.355020Z","iopub.execute_input":"2025-12-04T06:48:42.355403Z","iopub.status.idle":"2025-12-04T06:54:27.480512Z","shell.execute_reply.started":"2025-12-04T06:48:42.355377Z","shell.execute_reply":"2025-12-04T06:54:27.479078Z"}},"outputs":[],"execution_count":null}]}