ECG Library¶

Suggested pipeline¶

Load ECG images¶

In [ ]:
import os

from PIL import Image
import numpy as np
In [ ]:
dirname = 'examples/example_images/'
files = sorted(os.listdir(dirname), key=lambda a: int(a.split('.')[0]))
assert files == list(map(lambda n: f'{n}.png', range(1, 13)))
In [ ]:
images = [Image.open(dirname + filename) for filename in files]

Look at images¶

In [ ]:
images[1]
Out[ ]:
In [ ]:
Image.fromarray(np.concatenate(images, axis=0))
Out[ ]:

Convert images to signal¶

In [ ]:
import ECG.api as api
C:\Users\Denis\AppData\Roaming\Python\Python37\site-packages\tqdm\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm
In [ ]:
import ECG.api as api
In [ ]:
signal = [api.convert_image_to_signal(np.asarray(image)[:,:,:3]) for image in images]

functions for displaying explanations¶

In [ ]:
def display_text_explanation(explanation:api.TextExplanation):
    print('Text explanation:', explanation.content)

def display_text_and_image_explanation(explanation:api.TextAndImageExplanation):
    print('Text explanation:', explanation.text)
    print('GradCAM visualization:')
    return explanation.image

Get signal of all 12 ECG leads¶

Recommended sampling rate is 500

In [ ]:
sampling_rate = 500
In [ ]:
mm_per_mv = 10
In [ ]:
signal = np.asarray([s / mm_per_mv for s in signal])
In [ ]:
assert len(signal.shape) == 2
assert signal.shape[0] == 12

Check whether ST-elevation is present¶

In [ ]:
res = api.check_ST_elevation(signal, sampling_rate=sampling_rate)
print('Result:', res[0])
print('Explanation:')
display_text_explanation(res[1])
Result: ElevatedST.Abscent
Explanation:
Text explanation: ST elevation value in lead V3 (0.04126003416910934 mV) did not exceed the threshold 0.2, therefore ST elevation was not detected.
In [ ]:
res = api.check_ST_elevation_with_NN(signal)
print('Result:', res[0])
print('Explanation:')
display_text_and_image_explanation(res[1])
Load model at ./ECG/NN_based_approach/Models/Conv1_ste_model.pt
Result: ElevatedST.Abscent
Explanation:
Text explanation: Significant ST elevation probability is 0.3325
GradCAM visualization:
Out[ ]:

Evaluate risk markers¶

In [ ]:
api.evaluate_risk_markers(signal, sampling_rate=sampling_rate)
Out[ ]:
RiskMarkers(Ste60_V3=0.04126003416910934, QTc=419, RA_V4=0.9481276953640756)

Perform differential diagnosis¶

In [ ]:
res = api.diagnose_with_risk_markers(signal, sampling_rate=sampling_rate)
print('Result:', res[0])
print('Explanation:')
display_text_explanation(res[1])
Result: Diagnosis.BER
Explanation:
Text explanation: Criterion value calculated as follows: (1.196 * [STE60 V3 in mm]) + (0.059 * [QTc in ms]) – (0.326 * [RA V4 in mm])) = 22.123573721775664 did not exceed the threshold 23.4, therefore the diagnosis is Benign Early Repolarization
In [ ]:
res = api.check_BER_with_NN(signal)
print('Result:', res[0])
print('Explanation:')
display_text_and_image_explanation(res[1])
Load model at ./ECG/NN_based_approach/Models/Conv_ber_model.pt
Result: True
Explanation:
Text explanation: BER probability is 0.9278
GradCAM visualization:
Out[ ]:
In [ ]:
res = api.check_MI_with_NN(signal)
print('Result:', res[0])
print('Explanation:')
display_text_and_image_explanation(res[1])
Load model at ./ECG/NN_based_approach/Models/Conv_mi_model.pt
Result: False
Explanation:
Text explanation: MI probability is 0.0017
GradCAM visualization:
Out[ ]:

Check if the ECG is normal or not¶

In [ ]:
from ECG.api import ECGClass
In [ ]:
res = api.check_ecg_is_normal(signal[:, :4000], ECGClass.ALL)
print('Result:', res[0])
display_text_and_image_explanation(res[1])
Result: False
Text explanation: The signal has some abnormalities
GradCAM visualization:
Out[ ]:

Get QRS complex¶

In [ ]:
# for better view let's take a shorter signal
short_signal = signal[:, :2000]
In [ ]:
cleaned_signal, peaks = api.get_qrs_complex(short_signal, sampling_rate)
In [ ]:
api.show_channel_qrs_complex(cleaned_signal, peaks, 0)
Out[ ]:
In [ ]:
api.show_full_qrs_complex(cleaned_signal, peaks)
Out[ ]: