-
Notifications
You must be signed in to change notification settings - Fork 110
/
p_scharr3x3.c
175 lines (166 loc) · 3.87 KB
/
p_scharr3x3.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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include <pal.h>
#define C0 (3.3333333f) // 10/3
#define C1 (0.09375f) // 3/32
#define FMA(a,b,c) __builtin_fmaf(a,b,c)
static __inline __attribute((__always_inline__)) float my_hypot( float a, float b );
/*
* A Scharr 3x3 convolution filter with the following convolution matrix:
*
* | 3 0 -3 |
* Gx = | 10 0 -10 | * 1/32
* | 3 0 -3 |
*
* | 3 10 3 |
* Gy = | 0 0 0 | * 1/32
* | -3 -10 -3 |
*
* G = sqrt (Gx^2 + Gy^2)
*
* Gradient Direction (theta) = atan2(Gy,Gx)
*
* @param x Pointer to input image, a 2D array of size 'rows' x 'cols'
*
* @param r Pointer to output image
*
* @param rows Number of rows in input image
*
* @param cols Number of columns in input image
*
*/
void p_scharr3x3_f32(const float *x, float *r, int rows, int cols)
{
int i, j;
float a02, a03, a04, a05;
float a12, a13, a14, a15;
float a22, a23, a24, a25;
float cx2, cx3, cx4, cx5;
float cy2, cy3, cy4, cy5;
float Gx2, Gx3, Gx4, Gx5;
float Gy2, Gy3, Gy4, Gy5;
const float* px = x;
float* pr = r+cols+1;
for (j = 0; j < (rows - 2); j++) {
a04 = px[0];
a05 = px[1];
a14 = px[cols+0];
a15 = px[cols+1];
a24 = px[2*cols+0];
a25 = px[2*cols+1];
cx4 = FMA(C0,a14,a04+a24);
cx5 = FMA(C0,a15,a05+a25);
cy4 = a24 - a04;
cy5 = a25 - a05;
for (i = 0; i < (cols - 5); i+=4) { // unroll 4x
a02 = px[2];
a12 = px[cols+2];
a22 = px[2*cols+2];
a03 = px[3];
a13 = px[cols+3];
a23 = px[2*cols+3];
a04 = px[4];
a14 = px[cols+4];
a24 = px[2*cols+4];
a05 = px[5];
a15 = px[cols+5];
a25 = px[2*cols+5];
cx2 = FMA(C0,a12,a02+a22);
cy2 = a22 - a02;
Gx2 = cx2 - cx4;
Gy2 = FMA(C0,cy5,cy4+cy2);
cx3 = FMA(C0,a13,a03+a23);
cy3 = a23 - a03;
Gx3 = cx3 - cx5;
Gy3 = FMA(C0,cy2,cy5+cy3);
cx4 = FMA(C0,a14,a04+a24);
cy4 = a24 - a04;
Gx4 = cx4 - cx2;
Gy4 = FMA(C0,cy3,cy2+cy4);
cx5 = FMA(C0,a15,a05+a25);
cy5 = a25 - a05;
Gx5 = cx5 - cx3;
Gy5 = FMA(C0,cy4,cy3+cy5);
*(pr++) = my_hypot(Gx2, Gy2) * C1;
*(pr++) = my_hypot(Gx3, Gy3) * C1;
*(pr++) = my_hypot(Gx4, Gy4) * C1;
*(pr++) = my_hypot(Gx5, Gy5) * C1;
px += 4;
}
switch(cols-i) { // catching remainder
case 5:
a05 = px[2];
a15 = px[cols+2];
a25 = px[2*cols+2];
cx3 = cx4;
cx4 = cx5;
cy3 = cy4;
cy4 = cy5;
cx5 = FMA(C0,a15,a05+a25);
cy5 = a25 - a05;
Gx5 = cx5 - cx3;
Gy5 = FMA(C0,cy4,cy3+cy5);
*(pr++) = my_hypot(Gx5, Gy5) * C1;
px++;
case 4:
a05 = px[2];
a15 = px[cols+2];
a25 = px[2*cols+2];
cx3 = cx4;
cx4 = cx5;
cy3 = cy4;
cy4 = cy5;
cx5 = FMA(C0,a15,a05+a25);
cy5 = a25 - a05;
Gx5 = cx5 - cx3;
Gy5 = FMA(C0,cy4,cy3+cy5);
*(pr++) = my_hypot(Gx5, Gy5) * C1;
px++;
case 3:
a05 = px[2];
a15 = px[cols+2];
a25 = px[2*cols+2];
cx3 = cx4;
cx4 = cx5;
cy3 = cy4;
cy4 = cy5;
cx5 = FMA(C0,a15,a05+a25);
cy5 = a25 - a05;
Gx5 = cx5 - cx3;
Gy5 = FMA(C0,cy4,cy3+cy5);
*(pr++) = my_hypot(Gx5, Gy5) * C1;
px++;
}
pr += 2;
px += 2;
}
return;
}
/**
* Approximates the hypotenuse given two sides of a right triangle using
* a two Newton iterations for calculating the square root operation. The
* second iteration can be removed for higher performance and smaller code
* size at the expense of precision.
* /|
* / |
* 's'/ | 'a'
* / |
* /____|
* 'b'
* s = sqrt (a^2 + b^2)
*
* @param a Length of one side
*
* @param b Length of the second side
*
* @return The length of the hypotenuse
*/
static __inline __attribute((__always_inline__)) float my_hypot( float a, float b )
{
float s2 = FMA(a,a,b * b);
float x = s2 * -0.5f;
long i = * ( long * ) &s2;
i = 0x5f375a86 - ( i >> 1 );
float y = * ( float * ) &i;
y = y * FMA(x, y*y, 1.5f); // 1st Newton iteration
y = y * FMA(x, y*y, 1.5f); // 2nd iteration, this can be removed
return s2 * y;
}