diff options
Diffstat (limited to 'src/find_peaks.c')
-rw-r--r-- | src/find_peaks.c | 62 |
1 files changed, 53 insertions, 9 deletions
diff --git a/src/find_peaks.c b/src/find_peaks.c index e3a2fc6..05d8c15 100644 --- a/src/find_peaks.c +++ b/src/find_peaks.c @@ -7,6 +7,30 @@ #include "optics.h" #include <math.h> /* for exp() */ +typedef struct peak { + size_t i; + size_t j; + double value; +} peak; + +/* Compare two different peaks. + * + * Note: We return 1 if peak b is greater than peak b and -1 if peak a is + * greater than peak b. This is backwards from what you would normally expect, + * but it's because we want to keep the peaks sorted in *descending* order. */ +static int peak_compare(const void *a, const void *b) +{ + const peak *pa = (peak *) a; + const peak *pb = (peak *) b; + + if (pa->value > pb->value) + return -1; + else if (pa->value < pb->value) + return 1; + + return 0; +} + void find_peaks_array(double *x, size_t n, size_t m, size_t *imax, size_t *jmax, size_t *npeaks, size_t max_peaks, double threshold) { /* Find a maximum of `max_peaks` in the 2D array `x` indexed as: @@ -17,37 +41,47 @@ void find_peaks_array(double *x, size_t n, size_t m, size_t *imax, size_t *jmax, * * Peaks are defined as any array element which is greater than all 8 of * it's neighbors. Peaks are also required to be at least max*threshold - * times as high as the highest peak. */ + * times as high as the highest peak. + * + * The returned peaks will always be the *highest* peaks and they will be + * returned in sorted order from highest to lowest. */ size_t i, j; double max; + peak *p; if (n*m == 0) { *npeaks = 0; return; } + p = malloc(sizeof(peak)*(max_peaks+1)); + /* First, find the highest value in the array (which is guaranteed to be a peak). */ max = x[0]; - imax[0] = 0; - jmax[0] = 0; + p[0].i = 0; + p[0].j = 0; + p[0].value = max; for (i = 0; i < n; i++) { for (j = 0; j < m; j++) { if (x[i*m + j] > max) { max = x[i*m + j]; - imax[0] = i; - jmax[0] = j; + p[0].i = i; + p[0].j = j; + p[0].value = max; } } } *npeaks = 1; + if (*npeaks >= max_peaks) goto end; + /* Now we look for other peaks which are at least max*threshold high. */ for (i = 0; i < n; i++) { for (j = 0; j < m; j++) { if (x[i*m + j] <= max*threshold) continue; - if (i == imax[0] && j == jmax[0]) continue; + if (i == p[0].i && j == p[0].j) continue; /* Check to see if it is actually a peak. */ if (x[i*m + (j+1) % m] < x[i*m + j] && /* 0 +1 */ @@ -58,16 +92,26 @@ void find_peaks_array(double *x, size_t n, size_t m, size_t *imax, size_t *jmax, x[((i+n-1) % n)*m + j] < x[i*m + j] && /* -1 0 */ x[((i+n-1) % n)*m + (j+1) % m] < x[i*m + j] && /* -1 +1 */ x[((i+n-1) % n)*m + (j+m-1) % m] < x[i*m + j]) { /* -1 -1 */ - imax[*npeaks] = i; - jmax[*npeaks] = j; + p[*npeaks].i = i; + p[*npeaks].j = j; + p[*npeaks].value = x[i*m+j]; *npeaks += 1; - if (*npeaks >= max_peaks) goto end; + qsort(p,*npeaks,sizeof(peak),peak_compare); + + if (*npeaks >= max_peaks) *npeaks = max_peaks; } } } end: + for (i = 0; i < *npeaks; i++) { + imax[i] = p[i].i; + jmax[i] = p[i].j; + } + + free(p); + return; } |