/
ff_median.c
91 lines (77 loc) · 2.53 KB
/
ff_median.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include "func.h"
#include "parser.h"
#include "window.h"
float local_maximum(Window* w, float threshold, float ignore);
Var* ff_local_maximum(vfuncptr func, Var* arg)
{
Var *obj = NULL, *rval = NULL;
float ignore = FLT_MIN;
float* out;
int x, y, i, j;
int size = 3;
float threshold = FLT_MIN;
Window* w;
Alist alist[9];
alist[0] = make_alist("object", ID_VAL, NULL, &obj);
alist[1] = make_alist("size", DV_INT32, NULL, &size);
alist[2] = make_alist("ignore", DV_FLOAT, NULL, &ignore);
alist[3] = make_alist("threshold", DV_FLOAT, NULL, &threshold);
alist[4].name = NULL;
if (parse_args(func, arg, alist) == 0) return (NULL);
if (obj == NULL) {
parse_error("%s: No object specified\n", func->name);
return (NULL);
}
x = GetX(obj);
y = GetY(obj);
w = create_window(size, size, DV_FLOAT);
out = calloc(x * y, sizeof(float));
rval = newVal(BSQ, x, y, 1, DV_FLOAT, out);
for (i = 0; i < x; i += 1) {
load_window(w, obj, i, 0, ignore);
for (j = 0; j < y; j += 1) {
if (j) roll_window(w, obj, i, j, ignore);
out[cpos(i, j, 0, rval)] = local_maximum(w, threshold, ignore);
}
}
free_window(w);
return (rval);
}
float local_maximum(Window* w, float threshold, float ignore)
{
float v;
int i, j;
float max;
v = ((float*)w->row[w->height / 2])[w->width / 2];
if (v == ignore) return (ignore);
max = v;
for (i = 0; i < w->width; i += 1) {
for (j = 0; j < w->height; j += 1) {
v = ((float*)w->row[j])[i];
if (v == ignore || v < threshold) continue;
if (v > max) return (ignore);
}
}
return (max);
}
/*
** Given a 2-D array of data, compute it's median
** this algorithm currently just qsorts the entire NxN array and
** then counts up to the N/2th element,
** N has to get modified by the number of ignore values in the array
**
** This was the fastest way to get it to work, but it'll be slow.
** Michael's merge sort idea is a better way, but it's tightly coupled
** with window generation. It will eventually be:
**
**** Sort each row, then merge-find (merge-sort without move) across
**** rows. You can leave the N-1 rows sorted and just replace
**** the last one, reducing the problem down to sorting a single N-element
**** array and then merge sorting across arrays to find the smallest N/2
**** elements.
**
**** One thing I learned when implementing it the cheezy way, you can't
**** just find the N/2 smallest values if there are ignore values involved.
**** If you're certain <ignore> is the smallest value, you can count them
**** first and then find the (N-nignore)/2 smallest values.
*/