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 271