OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <algorithm> | |
6 #include <cmath> | |
7 #include <vector> | |
8 | |
9 #include "base/logging.h" | |
10 #include "skia/ext/recursive_gaussian_convolution.h" | |
11 | |
12 namespace skia { | |
13 | |
14 namespace { | |
15 | |
16 // Takes the value produced by accumulating element-wise product of image with | |
17 // a kernel and brings it back into range. | |
18 // All of the filter scaling factors are in fixed point with kShiftBits bits of | |
19 // fractional part. | |
20 template<bool take_absolute> | |
21 inline unsigned char FloatTo8(float f) { | |
22 int a = static_cast<int>(f + 0.5f); | |
23 if (take_absolute) | |
24 a = std::abs(a); | |
25 else if (a < 0) | |
26 return 0; | |
27 if (a < 256) | |
28 return a; | |
29 return 255; | |
30 } | |
31 | |
32 template<RecursiveFilter::Order order> | |
33 inline float ForwardFilter(float in_n_1, | |
34 float in_n, | |
35 float in_n1, | |
36 const std::vector<float>& w, | |
37 int n, | |
38 const float* b) { | |
39 switch (order) { | |
40 case RecursiveFilter::FUNCTION: | |
41 return b[0] * in_n + b[1] * w[n-1] + b[2] * w[n-2] + b[3] * w[n-3]; | |
42 case RecursiveFilter::FIRST_DERIVATIVE: | |
43 return b[0] * 0.5f * (in_n1 - in_n_1) + | |
44 b[1] * w[n-1] + b[2] * w[n-2] + b[3] * w[n-3]; | |
45 case RecursiveFilter::SECOND_DERIVATIVE: | |
46 return b[0] * (in_n - in_n_1) + | |
47 b[1] * w[n-1] + b[2] * w[n-2] + b[3] * w[n-3]; | |
48 } | |
49 | |
50 NOTREACHED(); | |
51 return 0.0f; | |
52 } | |
53 | |
54 template<RecursiveFilter::Order order> | |
55 inline float BackwardFilter(const std::vector<float>& out, | |
56 int n, | |
57 float w_n, | |
58 float w_n1, | |
59 const float* b) { | |
60 switch (order) { | |
61 case RecursiveFilter::FUNCTION: | |
62 case RecursiveFilter::FIRST_DERIVATIVE: | |
63 return b[0] * w_n + | |
64 b[1] * out[n + 1] + b[2] * out[n + 2] + b[3] * out[n + 3]; | |
65 case RecursiveFilter::SECOND_DERIVATIVE: | |
66 return b[0] * (w_n1 - w_n) + | |
67 b[1] * out[n + 1] + b[2] * out[n + 2] + b[3] * out[n + 3]; | |
68 } | |
69 NOTREACHED(); | |
70 return 0.0f; | |
71 } | |
72 | |
73 template<RecursiveFilter::Order order, bool absolute_values> | |
74 unsigned char SingleChannelRecursiveFilter( | |
75 const unsigned char* const source_data, | |
76 int source_pixel_stride, | |
77 int source_row_stride, | |
78 int row_width, | |
79 int row_count, | |
80 unsigned char* const output, | |
81 int output_pixel_stride, | |
82 int output_row_stride, | |
83 const float* b) { | |
84 const int intermediate_buffer_size = row_width + 6; | |
85 std::vector<float> w(intermediate_buffer_size); | |
86 const unsigned char* in = source_data; | |
87 unsigned char* out = output; | |
88 unsigned char max_output = 0; | |
89 for (int r = 0; r < row_count; | |
90 ++r, in += source_row_stride, out += output_row_stride) { | |
91 // Compute forward filter. | |
92 // First initialize start of the w (temporary) vector. | |
93 if (order == RecursiveFilter::FUNCTION) | |
94 w[0] = w[1] = w[2] = in[0]; | |
95 else | |
96 w[0] = w[1] = w[2] = 0.0f; | |
97 // Note that special-casing of w[3] is needed because of derivatives. | |
98 w[3] = ForwardFilter<order>( | |
99 in[0], in[0], in[source_pixel_stride], w, 3, b); | |
100 int n = 4; | |
101 int c = 1; | |
102 int byte_index = source_pixel_stride; | |
103 for (; c < row_width - 1; ++c, ++n, byte_index += source_pixel_stride) { | |
104 w[n] = ForwardFilter<order>(in[byte_index - source_pixel_stride], | |
105 in[byte_index], | |
106 in[byte_index + source_pixel_stride], | |
107 w, n, b); | |
108 } | |
109 | |
110 // The value of w corresponding to the last image pixel needs to be computed | |
111 // separately, again because of derivatives. | |
112 w[n] = ForwardFilter<order>(in[byte_index - source_pixel_stride], | |
113 in[byte_index], | |
114 in[byte_index], | |
115 w, n, b); | |
116 // Now three trailing bytes set to the same value as current w[n]. | |
117 w[n + 1] = w[n]; | |
118 w[n + 2] = w[n]; | |
119 w[n + 3] = w[n]; | |
120 | |
121 // Now apply the back filter. | |
122 float w_n1 = w[n + 1]; | |
123 int output_index = (row_width - 1) * output_pixel_stride; | |
124 for (; c >= 0; output_index -= output_pixel_stride, --c, --n) { | |
125 float w_n = BackwardFilter<order>(w, n, w[n], w_n1, b); | |
126 w_n1 = w[n]; | |
127 w[n] = w_n; | |
128 out[output_index] = FloatTo8<absolute_values>(w_n); | |
129 max_output = std::max(max_output, out[output_index]); | |
130 } | |
131 } | |
132 return max_output; | |
133 } | |
134 | |
135 unsigned char SingleChannelRecursiveFilter( | |
136 const unsigned char* const source_data, | |
137 int source_pixel_stride, | |
138 int source_row_stride, | |
139 int row_width, | |
140 int row_count, | |
141 unsigned char* const output, | |
142 int output_pixel_stride, | |
143 int output_row_stride, | |
144 const float* b, | |
145 RecursiveFilter::Order order, | |
146 bool absolute_values) { | |
147 if (absolute_values) { | |
148 switch (order) { | |
149 case RecursiveFilter::FUNCTION: | |
150 return SingleChannelRecursiveFilter<RecursiveFilter::FUNCTION, true>( | |
151 source_data, source_pixel_stride, source_row_stride, | |
152 row_width, row_count, | |
153 output, output_pixel_stride, output_row_stride, b); | |
154 case RecursiveFilter::FIRST_DERIVATIVE: | |
155 return SingleChannelRecursiveFilter< | |
156 RecursiveFilter::FIRST_DERIVATIVE, true>( | |
157 source_data, source_pixel_stride, source_row_stride, | |
158 row_width, row_count, | |
159 output, output_pixel_stride, output_row_stride, b); | |
160 case RecursiveFilter::SECOND_DERIVATIVE: | |
161 return SingleChannelRecursiveFilter< | |
162 RecursiveFilter::SECOND_DERIVATIVE, true>( | |
163 source_data, source_pixel_stride, source_row_stride, | |
164 row_width, row_count, | |
165 output, output_pixel_stride, output_row_stride, b); | |
166 } | |
167 } else { | |
168 switch (order) { | |
169 case RecursiveFilter::FUNCTION: | |
170 return SingleChannelRecursiveFilter<RecursiveFilter::FUNCTION, false>( | |
171 source_data, source_pixel_stride, source_row_stride, | |
172 row_width, row_count, | |
173 output, output_pixel_stride, output_row_stride, b); | |
174 case RecursiveFilter::FIRST_DERIVATIVE: | |
175 return SingleChannelRecursiveFilter< | |
176 RecursiveFilter::FIRST_DERIVATIVE, false>( | |
177 source_data, source_pixel_stride, source_row_stride, | |
178 row_width, row_count, | |
179 output, output_pixel_stride, output_row_stride, b); | |
180 case RecursiveFilter::SECOND_DERIVATIVE: | |
181 return SingleChannelRecursiveFilter< | |
182 RecursiveFilter::SECOND_DERIVATIVE, false>( | |
183 source_data, source_pixel_stride, source_row_stride, | |
184 row_width, row_count, | |
185 output, output_pixel_stride, output_row_stride, b); | |
186 } | |
187 } | |
188 | |
189 NOTREACHED(); | |
190 return 0; | |
191 } | |
192 | |
193 } | |
194 | |
195 float RecursiveFilter::qFromSigma(float sigma) { | |
196 DCHECK_GE(sigma, 0.5f); | |
197 if (sigma <= 2.5f) | |
198 return 3.97156f - 4.14554f * std::sqrt(1.0f - 0.26891f * sigma); | |
199 return 0.98711f * sigma - 0.96330f; | |
200 } | |
201 | |
202 void RecursiveFilter::computeCoefficients(float q, float b[4]) { | |
203 b[0] = 1.57825f + 2.44413f * q + 1.4281f * q * q + 0.422205f * q * q * q; | |
204 b[1] = 2.4413f * q + 2.85619f * q * q + 1.26661f * q * q * q; | |
205 b[2] = - 1.4281f * q * q - 1.26661f * q * q * q; | |
206 b[3] = 0.422205f * q * q * q; | |
207 | |
208 // The above is exactly like in the paper. To cut down on computations, | |
209 // we can fix up these numbers a bit now. | |
210 float b_norm = 1.0f - (b[1] + b[2] + b[3]) / b[0]; | |
211 b[1] /= b[0]; | |
212 b[2] /= b[0]; | |
213 b[3] /= b[0]; | |
214 b[0] = b_norm; | |
215 } | |
216 | |
217 RecursiveFilter::RecursiveFilter(float sigma, Order order) | |
218 : order_(order), q_(qFromSigma(sigma)) { | |
219 computeCoefficients(q_, b_); | |
220 } | |
221 | |
222 unsigned char SingleChannelRecursiveGaussianX(const unsigned char* source_data, | |
223 int source_byte_row_stride, | |
224 int input_channel_index, | |
225 int input_channel_count, | |
226 const RecursiveFilter& filter, | |
227 const SkISize& image_size, | |
228 unsigned char* output, | |
229 int output_byte_row_stride, | |
230 int output_channel_index, | |
231 int output_channel_count, | |
232 bool absolute_values) { | |
233 return SingleChannelRecursiveFilter(source_data + input_channel_index, | |
234 input_channel_count, | |
235 source_byte_row_stride, | |
236 image_size.width(), | |
237 image_size.height(), | |
238 output + output_channel_index, | |
239 output_channel_count, | |
240 output_byte_row_stride, | |
241 filter.b(), | |
242 filter.order(), | |
243 absolute_values); | |
244 } | |
245 | |
246 unsigned char SingleChannelRecursiveGaussianY(const unsigned char* source_data, | |
247 int source_byte_row_stride, | |
248 int input_channel_index, | |
249 int input_channel_count, | |
250 const RecursiveFilter& filter, | |
251 const SkISize& image_size, | |
252 unsigned char* output, | |
253 int output_byte_row_stride, | |
254 int output_channel_index, | |
255 int output_channel_count, | |
256 bool absolute_values) { | |
257 return SingleChannelRecursiveFilter(source_data + input_channel_index, | |
258 source_byte_row_stride, | |
259 input_channel_count, | |
260 image_size.height(), | |
261 image_size.width(), | |
262 output + output_channel_index, | |
263 output_byte_row_stride, | |
264 output_channel_count, | |
265 filter.b(), | |
266 filter.order(), | |
267 absolute_values); | |
268 } | |
269 | |
270 } // namespace skia | |
OLD | NEW |