{"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":97984,"databundleVersionId":14096757,"sourceType":"competition"}],"dockerImageVersionId":31239,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\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# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-28T18:12:15.585902Z","iopub.execute_input":"2025-12-28T18:12:15.586158Z","iopub.status.idle":"2025-12-28T18:12:23.683788Z","shell.execute_reply.started":"2025-12-28T18:12:15.586133Z","shell.execute_reply":"2025-12-28T18:12:23.682443Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# <span style=\"color:darkblue\">📝 Introduction / Overview</span>\n\nThis notebook demonstrates a **<span style=\"color:darkred;font-weight:bold\">baseline method</span>** for the <span style=\"color:green;font-weight:bold\">PhysioNet - Digitization of ECG Images</span> competition.  \n\n---\n\n### <span style=\"color:darkblue\">1️⃣ Import Libraries</span>\nLoaded necessary Python libraries for **image processing, visualization, and data handling**.  \n\n---\n\n### <span style=\"color:darkblue\">2️⃣ Load and Visualize Data</span>\n- Listed all ECG images from the competition dataset.  \n- Displayed several example images to understand variations (**size, noise, grid lines, etc.**)  \n\n---\n\n### <span style=\"color:darkblue\">3️⃣ Preprocessing</span>\n- Converted images to **grayscale**  \n- Applied **Gaussian blur** to reduce noise  \n- Applied **binary threshold** to highlight ECG lines  \n\n---\n\n### <span style=\"color:darkblue\">4️⃣ Baseline Digitalization</span>\n- For each column, calculated the **average y-position of white pixels**  \n- Converted **pixel positions into numerical signal** (digital ECG)  \n\n---\n\n### <span style=\"color:darkblue\">5️⃣ Process All Images and Export CSV</span>\n- Applied the **baseline method** to the entire dataset  \n- Saved all digital signals into a **CSV file** for Kaggle submission  \n\n> **Note:** This is a **baseline approach**. Accuracy can be improved using **advanced preprocessing** or **deep learning models** (e.g., U-Net segmentation).\n","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport cv2\nfrom glob import glob\nfrom PIL import Image\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-28T18:12:12.665757Z","iopub.execute_input":"2025-12-28T18:12:12.666093Z","iopub.status.idle":"2025-12-28T18:12:15.570520Z","shell.execute_reply.started":"2025-12-28T18:12:12.666063Z","shell.execute_reply":"2025-12-28T18:12:15.568588Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_files = glob(\"/kaggle/input/physionet-ecg-image-digitization/test/2352854581.png\")\n\nprint(f\"Toplam görüntü sayısı: {len(image_files)}\")\n\nfor i, file in enumerate(image_files[:3]):\n    img = cv2.imread(file)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # Renk düzeltme\n    plt.figure(figsize=(10,3))\n    plt.imshow(img)\n    plt.title(f\"ECG Görüntüsü {i+1}\")\n    plt.axis('off')\n    plt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-28T18:15:17.855759Z","iopub.execute_input":"2025-12-28T18:15:17.856573Z","iopub.status.idle":"2025-12-28T18:15:18.647721Z","shell.execute_reply.started":"2025-12-28T18:15:17.856531Z","shell.execute_reply":"2025-12-28T18:15:18.646526Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img = cv2.imread(image_files[0], cv2.IMREAD_GRAYSCALE)\nblur = cv2.GaussianBlur(img, (5,5), 0)\n_, thresh = cv2.threshold(blur, 128, 255, cv2.THRESH_BINARY_INV)\n\nplt.figure(figsize=(12,4))\nplt.subplot(1,2,1)\nplt.imshow(img, cmap='gray')\nplt.title(\"Orijinal Grayscale\")\nplt.axis('off')\n\nplt.subplot(1,2,2)\nplt.imshow(thresh, cmap='gray')\nplt.title(\"Binary Threshold\")\nplt.axis('off')\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-28T18:15:50.617362Z","iopub.execute_input":"2025-12-28T18:15:50.617694Z","iopub.status.idle":"2025-12-28T18:15:51.543879Z","shell.execute_reply.started":"2025-12-28T18:15:50.617671Z","shell.execute_reply":"2025-12-28T18:15:51.542792Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"height = thresh.shape[0]\nsignal = []\n\nfor col in range(thresh.shape[1]):\n    y_positions = np.where(thresh[:, col] == 255)[0]\n    if len(y_positions) > 0:\n        y_mean = np.mean(y_positions)\n        \n        signal.append(height - y_mean)\n    else:\n        signal.append(height / 2)  \n\nsignal = np.array(signal)\n\nplt.figure(figsize=(15,4))\nplt.plot(signal, color='blue')\nplt.title(\"Dijitalleştirilmiş ECG Sinyali (Baseline)\")\nplt.xlabel(\"Zaman (pixel sütun)\")\nplt.ylabel(\"Voltaj (piksel dönüşümü)\")\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-28T18:15:57.894104Z","iopub.execute_input":"2025-12-28T18:15:57.894455Z","iopub.status.idle":"2025-12-28T18:15:58.156730Z","shell.execute_reply.started":"2025-12-28T18:15:57.894429Z","shell.execute_reply":"2025-12-28T18:15:58.155777Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"This method is called the baseline approach. For each vertical column, we calculate the average position of the white pixels and convert it into a numerical signal. Later, more accurate results can be obtained using advanced image processing or deep learning models.","metadata":{}},{"cell_type":"code","source":"# Create a dictionary to store all signals\nall_signals = {}\n\nfor file in image_files:\n    # Load image in grayscale\n    img = cv2.imread(file, cv2.IMREAD_GRAYSCALE)\n    # Apply Gaussian blur\n    blur = cv2.GaussianBlur(img, (5,5), 0)\n    # Binary threshold\n    _, thresh = cv2.threshold(blur, 128, 255, cv2.THRESH_BINARY_INV)\n    \n    height = thresh.shape[0]\n    signal = []\n    \n    for col in range(thresh.shape[1]):\n        y_positions = np.where(thresh[:, col] == 255)[0]\n        if len(y_positions) > 0:\n            y_mean = np.mean(y_positions)\n            signal.append(height - y_mean)\n        else:\n            signal.append(height / 2)\n    \n    # Store signal in dictionary, key = image name\n    image_name = file.split(\"/\")[-1].replace(\".png\",\"\")\n    all_signals[image_name] = signal\n\n# Convert dictionary to DataFrame\ndf_signals = pd.DataFrame.from_dict(all_signals, orient='index').transpose()\n\n# Save to CSV (for submission)\ndf_signals.to_csv(\"digital_ecg_signals_baseline.csv\", index=False)\nprint(\"All ECG signals saved to CSV successfully!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-28T18:18:49.153817Z","iopub.execute_input":"2025-12-28T18:18:49.154249Z","iopub.status.idle":"2025-12-28T18:18:49.332630Z","shell.execute_reply.started":"2025-12-28T18:18:49.154127Z","shell.execute_reply":"2025-12-28T18:18:49.331319Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}