Home | History | Annotate | Download | only in ext
      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