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