{
  "id": 614318,
  "title": "At last: a supervised learning model",
  "url": "/competitions/physionet-ecg-image-digitization/discussion/614318",
  "author_name": "",
  "post_date": "2025-11-03T06:12:07.034346600Z",
  "votes": 10,
  "comment_count": 3,
  "views": 0,
  "content": "<p>The plane sweep algorithm for ECG digitization fails for noisy images and can't even handle black gridlines. Let's turn to machine learning!</p>\n<p>We know where the ECG lines begin and end, and we can even map the true labels to pixels of the image. If we slice the image between the endpoints into thin vertical stripes (600 pixels high, 11 pixels wide), the ECG lines will intersect the stripes at various heights, and we can formulate a regression task:</p>\n<blockquote>\n  <p>Given the 6600 pixel values, predict at which height the ECG line intersects the stripe.</p>\n</blockquote>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F7917824%2F12cee88716fee8e01dd47cd839800f85%2Fstripes2.png?generation=1762149724391177&amp;alt=media\" alt=\"stripes\"></p>\n<p>Look at the diagram above, which presents some of the stripes. The regression targets (numbers between 0 and 600) are shown above every stripe. Try to discern the following items:</p>\n<ol>\n<li>ECG lines intersecting the stripe (the stripes are high enough so that there is often more than one line, one of them should be at the position indicated at the top of the diagram)</li>\n<li>horizontal gridlines</li>\n<li>vertical gridlines</li>\n<li>markers showing the start of a lead</li>\n<li>lead designations (letters 'a' and 'V')</li>\n<li>other noise</li>\n</ol>\n<p>The size of the stripes (600*11 = 6600 pixels) has been chosen so that a neural network (or perhaps another regression model with 6600 inputs and one output) can be trained easily in Kaggle notebooks.</p>\n<p>Source code is in my public notebook.</p>",
  "messages": [
    {
      "id": "3310522",
      "postDate": "11/03/2025 06:12:07",
      "content": "<p>The plane sweep algorithm for ECG digitization fails for noisy images and can't even handle black gridlines. Let's turn to machine learning!</p>\n<p>We know where the ECG lines begin and end, and we can even map the true labels to pixels of the image. If we slice the image between the endpoints into thin vertical stripes (600 pixels high, 11 pixels wide), the ECG lines will intersect the stripes at various heights, and we can formulate a regression task:</p>\n<blockquote>\n  <p>Given the 6600 pixel values, predict at which height the ECG line intersects the stripe.</p>\n</blockquote>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F7917824%2F12cee88716fee8e01dd47cd839800f85%2Fstripes2.png?generation=1762149724391177&amp;alt=media\" alt=\"stripes\"></p>\n<p>Look at the diagram above, which presents some of the stripes. The regression targets (numbers between 0 and 600) are shown above every stripe. Try to discern the following items:</p>\n<ol>\n<li>ECG lines intersecting the stripe (the stripes are high enough so that there is often more than one line, one of them should be at the position indicated at the top of the diagram)</li>\n<li>horizontal gridlines</li>\n<li>vertical gridlines</li>\n<li>markers showing the start of a lead</li>\n<li>lead designations (letters 'a' and 'V')</li>\n<li>other noise</li>\n</ol>\n<p>The size of the stripes (600*11 = 6600 pixels) has been chosen so that a neural network (or perhaps another regression model with 6600 inputs and one output) can be trained easily in Kaggle notebooks.</p>\n<p>Source code is in my public notebook.</p>",
      "rawMarkdown": "The plane sweep algorithm for ECG digitization fails for noisy images and can't even handle black gridlines. Let's turn to machine learning!\n\nWe know where the ECG lines begin and end, and we can even map the true labels to pixels of the image. If we slice the image between the endpoints into thin vertical stripes (600 pixels high, 11 pixels wide), the ECG lines will intersect the stripes at various heights, and we can formulate a regression task:\n\n> Given the 6600 pixel values, predict at which height the ECG line intersects the stripe.\n\n![stripes](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F7917824%2F12cee88716fee8e01dd47cd839800f85%2Fstripes2.png?generation=1762149724391177&alt=media)\n\nLook at the diagram above, which presents some of the stripes. The regression targets (numbers between 0 and 600) are shown above every stripe. Try to discern the following items:\n\n1. ECG lines intersecting the stripe (the stripes are high enough so that there is often more than one line, one of them should be at the position indicated at the top of the diagram)\n1. horizontal gridlines\n1. vertical gridlines\n1. markers showing the start of a lead\n1. lead designations (letters 'a' and 'V')\n1. other noise\n\nThe size of the stripes (600\\*11 = 6600 pixels) has been chosen so that a neural network (or perhaps another regression model with 6600 inputs and one output) can be trained easily in Kaggle notebooks.\n\nSource code is in my public notebook.",
      "votes": null
    },
    {
      "id": "3310554",
      "postDate": "11/03/2025 06:44:20",
      "content": "<p>You method assume the plot is unrotated. If it is rotated, moving from a signal point to horizontal grid line ( at shortest  distance) is not vertical </p>",
      "rawMarkdown": "You method assume the plot is unrotated. If it is rotated, moving from a signal point to horizontal grid line ( at shortest  distance) is not vertical",
      "votes": null
    },
    {
      "id": "3310559",
      "postDate": "11/03/2025 06:56:54",
      "content": "<p><a href=\"https://www.kaggle.com/hengck23\" target=\"_blank\">@hengck23</a> Sure, this is the simplifying assumption which can be removed in a later stage.</p>",
      "rawMarkdown": "hengck23 Sure, this is the simplifying assumption which can be removed in a later stage.",
      "votes": null
    },
    {
      "id": "3311873",
      "postDate": "11/06/2025 00:46:25",
      "content": "<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F113660%2Fc1a9a88bba4109d76e096dad70be0973%2FSelection_913.png?generation=1762389974685687&amp;alt=media\" alt=\"\"></p>\n<p>typo: should have been (pi * yi).sum()</p>\n<hr>\n<p>i am doing mask refinement like this. \ni first use a network to learn a better ground truth mask that will get high SNR &gt; 30.\nafter i get this perfect mask M_final, i learn another pixelwise segmentation net to predict the mask from input image.</p>\n<hr>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F113660%2F24b386550d458ad5e975e65163e14892%2FSelection_916.png?generation=1762394106440358&amp;alt=media\" alt=\"\"></p>\n<p>how the refined mask looks like and snr&gt;60</p>",
      "rawMarkdown": "![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F113660%2Fc1a9a88bba4109d76e096dad70be0973%2FSelection_913.png?generation=1762389974685687&alt=media)\n\ntypo: should have been (pi * yi).sum()\n\n---\n\ni am doing mask refinement like this. \ni first use a network to learn a better ground truth mask that will get high SNR > 30.\nafter i get this perfect mask M\\_final, i learn another pixelwise segmentation net to predict the mask from input image.\n\n\n----\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F113660%2F24b386550d458ad5e975e65163e14892%2FSelection_916.png?generation=1762394106440358&alt=media)\n\nhow the refined mask looks like and snr>60",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 3310554,
      "author_name": "hengck23",
      "author_url": "",
      "post_date": "11/03/2025 06:44:20",
      "content": "<p>You method assume the plot is unrotated. If it is rotated, moving from a signal point to horizontal grid line ( at shortest  distance) is not vertical </p>",
      "votes": null,
      "replies": [
        {
          "id": 3310559,
          "author_name": "ambrosm",
          "author_url": "",
          "post_date": "11/03/2025 06:56:54",
          "content": "<p><a href=\"https://www.kaggle.com/hengck23\" target=\"_blank\">@hengck23</a> Sure, this is the simplifying assumption which can be removed in a later stage.</p>",
          "votes": null,
          "replies": []
        }
      ]
    },
    {
      "id": 3311873,
      "author_name": "hengck23",
      "author_url": "",
      "post_date": "11/06/2025 00:46:25",
      "content": "<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F113660%2Fc1a9a88bba4109d76e096dad70be0973%2FSelection_913.png?generation=1762389974685687&amp;alt=media\" alt=\"\"></p>\n<p>typo: should have been (pi * yi).sum()</p>\n<hr>\n<p>i am doing mask refinement like this. \ni first use a network to learn a better ground truth mask that will get high SNR &gt; 30.\nafter i get this perfect mask M_final, i learn another pixelwise segmentation net to predict the mask from input image.</p>\n<hr>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F113660%2F24b386550d458ad5e975e65163e14892%2FSelection_916.png?generation=1762394106440358&amp;alt=media\" alt=\"\"></p>\n<p>how the refined mask looks like and snr&gt;60</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "3310522": "The plane sweep algorithm for ECG digitization fails for noisy images and can't even handle black gridlines. Let's turn to machine learning!\n\nWe know where the ECG lines begin and end, and we can even map the true labels to pixels of the image. If we slice the image between the endpoints into thin vertical stripes (600 pixels high, 11 pixels wide), the ECG lines will intersect the stripes at various heights, and we can formulate a regression task:\n\n> Given the 6600 pixel values, predict at which height the ECG line intersects the stripe.\n\n![stripes](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F7917824%2F12cee88716fee8e01dd47cd839800f85%2Fstripes2.png?generation=1762149724391177&alt=media)\n\nLook at the diagram above, which presents some of the stripes. The regression targets (numbers between 0 and 600) are shown above every stripe. Try to discern the following items:\n\n1. ECG lines intersecting the stripe (the stripes are high enough so that there is often more than one line, one of them should be at the position indicated at the top of the diagram)\n1. horizontal gridlines\n1. vertical gridlines\n1. markers showing the start of a lead\n1. lead designations (letters 'a' and 'V')\n1. other noise\n\nThe size of the stripes (600\\*11 = 6600 pixels) has been chosen so that a neural network (or perhaps another regression model with 6600 inputs and one output) can be trained easily in Kaggle notebooks.\n\nSource code is in my public notebook.",
    "3310554": "You method assume the plot is unrotated. If it is rotated, moving from a signal point to horizontal grid line ( at shortest  distance) is not vertical",
    "3310559": "hengck23 Sure, this is the simplifying assumption which can be removed in a later stage.",
    "3311873": "![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F113660%2Fc1a9a88bba4109d76e096dad70be0973%2FSelection_913.png?generation=1762389974685687&alt=media)\n\ntypo: should have been (pi * yi).sum()\n\n---\n\ni am doing mask refinement like this. \ni first use a network to learn a better ground truth mask that will get high SNR > 30.\nafter i get this perfect mask M\\_final, i learn another pixelwise segmentation net to predict the mask from input image.\n\n\n----\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F113660%2F24b386550d458ad5e975e65163e14892%2FSelection_916.png?generation=1762394106440358&alt=media)\n\nhow the refined mask looks like and snr>60"
  },
  "source": "meta"
}