I\'m trying to read a image from a electrocardiography and detect each one of the main waves in it (P wave, QRS complex and T wave). Now I can read the image and get a vector li
The first thing that I would do is see what is already out there. Indeed, this specific problem has already been heavily researched. Here is a brief overview of some really simple methods: link.
I must respond to another answer, as well. I do research in signal processing and music information retrieval. On the surface, this problem does appear similar to onset detection, but the problem context is not the same. This type of biological signal processing, i.e., detection of the P, QRS, and T phases, can exploit knowledge of specific time-domain characteristics of each of these waveforms. Onset detection in MIR doesn't, really. (Not reliably, at least.)
One approach that would work well for QRS detection (but not necessarily for note onset detection) is dynamic time warping. When time-domain characteristics remain invariant, DTW can work remarkably well. Here is a short IEEE paper that uses DTW for this problem: link.
This is a nice IEEE magazine article that compares many methods: link. You'll see that many common signal processing models have been tried. Skim the paper, and try one that you understand at a basic level.
EDIT: After browsing these articles, a wavelet-based approach seems most intuitive to me. DTW will work well, too, and there exist DTW modules out there, but the wavelet approach seems best to me. Someone else answered by exploiting derivatives of the signal. My first link examines methods from before 1990 that do that, but I suspect that they are not as robust as more modern methods.
EDIT: I'll try to give a simple solution when I get the chance, but the reason why I think wavelets are suited here are because they are useful at parameterizing a wide variety of shapes regardless of time or amplitude scaling. In other words, if you have a signal with the same repeated temporal shape but at varying time scales and amplitudes, wavelet analysis can still recognize these shapes as being similar (roughly speaking). Also note that I am sort of lumping filter banks into this category. Similar things.
Instead of analyzing absolute data, analyze the amount of change from one data point to the next.
Here is a quick one liner that will take ;
separated data as input, and output the delta of that data.
perl -0x3b -ple'( $last, $_ ) = ( $_, $_-$last )' < test.in > test.out
Running it on the data you provided, this is the output:
0;0;20;0;0;-1;-1;-1;0;0;0;0;-1;0;0;0;0;0;0;1;0;1;1;1;1;1;1;0;0;2;0;-2;-1;-2;-1;-2;-1;0;-2;-1;1;-1;0;-1;0;0;0; 0;-1;0;-1;2;4;6;9;7;7;6;-4;-6;-8;-7;-5;-4;0;-1;0;-1;1;1;0;1;0;-1;1;0;0;0;0;0;0;-1;0;1;1;-1;0;1;0;0;0;1;0;-1;1; 2;2;0;1;1;1;1;1;1;1;0;0;1;0;0;-1;-2;-1;-2;-2;-2;-2;0;-1;-1;0;-1;0;-1;0;-1;0;1;-1;0;0;0;0;0;0;0;0;-1;1;1;0;0;0; 0;0;0;0;0;-1;1;-1;0;0;1;0;0;0;0;0;0;0;-1;1;0;0;0;0;-1;0;0;0;0;1;0;1;1;0;1;0;0;1;1;1;0;0;0;-1;-1;-2;-1;0;-2;0; -1;0;-1;0;1;-1;0;0;-1;0;0;0;1;5;5;7;8;9;4;-7;-5;-8;-7;-6;-2;-1;0;0;0;0;0;1;0;0;1;-1;0;1;0;-1;1;0;0;0;1;0;0;0; 1;0;1;0;0;0;1;1;0;2;1;1;1;1;1;1;1;1;1;-1;1;0;0;-1;-2;-2;-2;-2;-1;0;-1;-2;-1;0;-1;-1;0;1;-1;1;0;-1;1;-1;1;0;-1; 0;0;0;-1;1;0;0;1;0;-1;0;1;0;0;1;-1;0;-1;1;0;-1;0;0;0;0;1;-1;0;1;-1;0;0;0;0;0;0;1;-1;0;1;0;0;2;0;1;0;1;1;1;-1; 0;-2;0;-1;-2;0;-1;-1;-2;-1;0;0;0;0;0;0;0;0;-1;0;0;4;3;9;8;11;4;-5;-6;-8;-8;-4;-2;-2;0;0;0;-1;1;0;0;1;0;0;1;-1; 0;1;0;0;0;1;-1;0;1;1;0;0;0;0;1;0;1;0;1;2;1;1;2;0;1;1;1;1;0;0;1;1;0;0;-35;0;0;0;
There are new-lines inserted in the above text not originally present in the output.
After you have done that it is trivial to find the qrs complex.
perl -F';' -ane'@F = map { abs($_) > 2 and $_ } @F; print join ";", @F'< test.out
;;20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4;6;9;7;7;6;-4;-6;-8;-7;-5;-4;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5;5;7;8;9;4;-7;-5;-8;-7;-6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4;3;9;8;11;4;-5;-6;-8;-8;-4;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-35;;;
The 20
and -35
data points result from the original data starting and ending with 0
.
To find the other data points you will have to rely on pattern matching.
If you look at the first p wave, you can clearly see a pattern.
0;0;0;0;0;0;1;0;1;1;1;1;1;1;0;0;2;0;-2;-1;-2;-1;-2;-1;0;-2;-1;1;-1;0;-1;0;0;0;0;
# \________ up _______/ \________ down _________/
It isn't as easy to see the pattern on the second p wave though. This is because the second one is spread out further
0;0;0;1;0;1;1;0;1;0;0;1;1;1;0;0;0;-1;-1;-2;-1;0;-2;0;-1;0;-1;0;1;-1;0;0;-1;0;0;0;
# \________ up _______/ \________________ down ________________/
The third p wave is a little more erratic than the other two.
0;0;0;0;0;1;-1;0;1;0;0;2;0;1;0;1;1;1;-1;0;-2;0;-1;-2;0;-1;-1;-2;-1;0;0;0;0;0;
# \_______ up ______/ \__________ down __________/
You would find the t waves in a similar manner to the p waves. The main difference is when they occur.
The two one-liners are for example only, not recommended for daily use.
"Wavelet transform" may be a relevant keyword. I've once attended a presentation by someone who used this technique to detect different heartbeat phases in a noisy ecg.
As far as my limited understanding goes, it's somewhat like a Fourier transform, but using (scaled) copies of a, in your case heartbeat-shaped, pulse.
One approach that will very likely yield good results is curve fitting:
Define a model function that can be used to approximate all possible variations of electrocardiographic curves. This is not as difficult as it seems first. The model function can be constructed as a sum of three functions with parameters for the origin (t_), amplitude (a_) and width (w_) of each wave.
f_model(t) = a_p * f_p ((t-t_p )/w_p) + a_qrs * f_qrs((t-t_qrs)/w_qrs) + a_t * f_t ((t-t_t )/w_t)
The functions f_p(t)
, f_qrs(t)
, f_t(t)
are some simple function that can be uses to model each of the three waves.
Use a fitting algorithm (e.g. the Levenberg-Marquardt-Algorithm http://en.wikipedia.org/wiki/Levenberg%E2%80%93Marquardt_algorithm) to determine the fitting parameters a_p, t_p, w_p, a_qrs, t_qrs, w_qrs, a_t, t_t, w_t for the dataset of each intervall.
The parameters t_p, t_qrs and t_p are the ones you are interested in.
You can use cross-correlation. Take a model sample of each pattern and correlate them with the signal. You will get peaks where the correlation is high. I would expect good results with this technique extracting qrs and t waves. After that, you can extract p waves by looking for peaks on the correlation signal that are before qrs.
Cross-correlation is a pretty easy to implement algorithm. Basically:
x is array with your signal of length Lx
y is an array containing a sample of the signal you want to recognize of length Ly
r is the resulting correlation
for (i=0; i<Lx - Ly; i++){
r[i] = 0;
for (j=0; j<Ly ; j++){
r[i] += x[i+j]*y[j];
}
}
And look for peaks in r (values over a threshold, for instance)
Wavelets have been shown to be the best tool for locating peaks in this type of data where the peaks are "different sizes" - the scaling properties of wavelets make it an ideal tool for this type of multi-scale peak detection. This looks like a non-stationary signal so using a DFT would not be the right tool as some have suggested, but if this is an exploratory project you could look at using the spectrum of the signal (estimated using essentially the FFT of the autocorrelation of the signal.)
Here is a great paper reviewing several peak detection methods - this would be a good place to start.
-Paul