Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / skia / ext / recursive_gaussian_convolution.cc
blob195fca8deaeaeb6bba3ccf52a6dc212c3e49ec97
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.
5 #include <algorithm>
6 #include <cmath>
7 #include <vector>
9 #include "base/logging.h"
10 #include "skia/ext/recursive_gaussian_convolution.h"
12 namespace skia {
14 namespace {
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;
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];
50 NOTREACHED();
51 return 0.0f;
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];
69 NOTREACHED();
70 return 0.0f;
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);
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];
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]);
132 return max_output;
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);
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);
189 NOTREACHED();
190 return 0;
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;
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;
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;
217 RecursiveFilter::RecursiveFilter(float sigma, Order order)
218 : order_(order), q_(qFromSigma(sigma)) {
219 computeCoefficients(q_, b_);
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);
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);
270 } // namespace skia