Home | History | Annotate | Download | only in kernels
      1 /* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
      2 
      3 Licensed under the Apache License, Version 2.0 (the "License");
      4 you may not use this file except in compliance with the License.
      5 You may obtain a copy of the License at
      6 
      7     http://www.apache.org/licenses/LICENSE-2.0
      8 
      9 Unless required by applicable law or agreed to in writing, software
     10 distributed under the License is distributed on an "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 See the License for the specific language governing permissions and
     13 limitations under the License.
     14 ==============================================================================*/
     15 
     16 #ifndef TENSORFLOW_CORE_KERNELS_SAMPLING_KERNELS_H_
     17 #define TENSORFLOW_CORE_KERNELS_SAMPLING_KERNELS_H_
     18 
     19 #include <cmath>
     20 
     21 #include "tensorflow/core/lib/core/stringpiece.h"
     22 
     23 namespace tensorflow {
     24 namespace functor {
     25 // Defines functions for different types of sampling kernels.
     26 enum SamplingKernelType {
     27   // Lanczos kernel with radius 1.  Aliases but does not ring.
     28   Lanczos1Kernel,
     29 
     30   // Lanczos kernel with radius 3.  High-quality practical filter but may have
     31   // some ringing especially on synthetic images.
     32   Lanczos3Kernel,
     33 
     34   // Lanczos kernel with radius 5.  Very-high-quality filter but may have
     35   // stronger ringing.
     36   Lanczos5Kernel,
     37 
     38   // Gaussian kernel with radius 3, sigma = 1.5 / 3.  Less commonly used.
     39   GaussianKernel,
     40 
     41   // Rectangle function.  Equivalent to "nearest" sampling when upscaling.
     42   // Has value 1 in interval (-0.5, 0.5), value 0.5 on edge, and 0 elsewhere.
     43   BoxKernel,
     44 
     45   // Hat/tent function with radius 1.  Equivalent to "bilinear" reconstruction
     46   // when upsampling.
     47   // Has value zero at -1.0 and 1.0.
     48   TriangleKernel,
     49 
     50   // Cubic interpolant of Keys.  Equivalent to Catmull-Rom kernel.  Reasonably
     51   // good quality and faster than Lanczos3Kernel.
     52   KeysCubicKernel,
     53 
     54   // Cubic non-interpolating scheme.  For synthetic images (especially those
     55   // lacking proper prefiltering), less ringing than Keys cubic kernel but less
     56   // sharp.
     57   MitchellCubicKernel,
     58 
     59   // Always insert new kernel types before this.
     60   SamplingKernelTypeEnd
     61 };
     62 
     63 // Converts a string into the corresponding kernel type.
     64 // Returns SamplingKernelTypeEnd if the string couldn't be converted.
     65 SamplingKernelType SamplingKernelTypeFromString(const StringPiece str);
     66 
     67 // A function object for a Lanczos kernel.
     68 struct LanczosKernelFunc {
     69   // Pass 1 for Lanczos1 kernel, 3 for Lanczos3 etc.
     70   explicit LanczosKernelFunc(float _radius) : radius(_radius) {}
     71   float operator()(float x) const {
     72     constexpr float kPI = 3.14159265359;
     73     x = std::abs(x);
     74     if (x > radius) return 0.0;
     75     // Need to special case the limit case of sin(x) / x when x is zero.
     76     if (x <= 1e-3) {
     77       return 1.0;
     78     }
     79     return radius * std::sin(kPI * x) * std::sin(kPI * x / radius) /
     80            (kPI * kPI * x * x);
     81   }
     82   float Radius() const { return radius; }
     83   const float radius;
     84 };
     85 
     86 struct GaussianKernelFunc {
     87   static constexpr float kRadiusMultiplier = 3.0f;
     88   // https://en.wikipedia.org/wiki/Gaussian_function
     89   // We use sigma = 0.5, as suggested on p. 4 of Ken Turkowski's "Filters
     90   // for Common Resampling Tasks" for kernels with a support of 3 pixels:
     91   // www.realitypixels.com/turk/computergraphics/ResamplingFilters.pdf
     92   // This implies a radius of 1.5,
     93   explicit GaussianKernelFunc(float _radius = 1.5f)
     94       : radius(_radius), sigma(_radius / kRadiusMultiplier) {}
     95   float operator()(float x) const {
     96     x = std::abs(x);
     97     if (x >= radius) return 0.0;
     98     return std::exp(-x * x / (2.0 * sigma * sigma));
     99   }
    100   float Radius() const { return radius; }
    101   const float radius;
    102   const float sigma;  // Gaussian standard deviation
    103 };
    104 
    105 struct BoxKernelFunc {
    106   float operator()(float x) const {
    107     x = std::abs(x);
    108     return x < 0.5f ? 1. : x == 0.5f ? 0.5f : 0.0f;
    109   }
    110   float Radius() const { return 1.f; }
    111 };
    112 
    113 struct TriangleKernelFunc {
    114   // https://en.wikipedia.org/wiki/Triangle_function
    115   float operator()(float x) const {
    116     x = std::abs(x);
    117     return x < 1.0f ? 1.0f - x : 0.0f;
    118   }
    119   float Radius() const { return 1.f; }
    120 };
    121 
    122 struct KeysCubicKernelFunc {
    123   // http://ieeexplore.ieee.org/document/1163711/
    124   // R. G. Keys. Cubic convolution interpolation for digital image
    125   // processing. IEEE Transactions on Acoustics, Speech, and Signal
    126   // Processing, 29(6):11531160, 1981.
    127   float operator()(float x) const {
    128     x = std::abs(x);
    129     if (x >= 2.0f) {
    130       return 0.0f;
    131     } else if (x >= 1.0f) {
    132       return ((-0.5f * x + 2.5f) * x - 4.0f) * x + 2.0f;
    133     } else {
    134       return ((1.5f * x - 2.5f) * x) * x + 1.0f;
    135     }
    136   }
    137   float Radius() const { return 2.f; }
    138 };
    139 
    140 struct MitchellCubicKernelFunc {
    141   // https://doi.org/10.1145/378456.378514
    142   // D. P. Mitchell and A. N. Netravali. Reconstruction filters in computer
    143   // graphics.  Computer Graphics (Proceedings of ACM SIGGRAPH 1988),
    144   // 22(4):221228, 1988.
    145   float operator()(float x) const {
    146     x = std::abs(x);
    147     if (x >= 2.0f) {
    148       return 0.0f;
    149     } else if (x >= 1.0f) {
    150       return (((-7.0f / 18.0f) * x + 2.0f) * x - 10.0f / 3.0f) * x +
    151              16.0f / 9.0f;
    152     } else {
    153       return (((7.0f / 6.0f) * x - 2.0f) * x) * x + 8.0f / 9.0f;
    154     }
    155   }
    156   float Radius() const { return 2.f; }
    157 };
    158 
    159 inline LanczosKernelFunc CreateLanczos1Kernel() {
    160   return LanczosKernelFunc(1.0);
    161 }
    162 
    163 inline LanczosKernelFunc CreateLanczos3Kernel() {
    164   return LanczosKernelFunc(3.0);
    165 }
    166 
    167 inline LanczosKernelFunc CreateLanczos5Kernel() {
    168   return LanczosKernelFunc(5.0);
    169 }
    170 
    171 inline GaussianKernelFunc CreateGaussianKernel() {
    172   return GaussianKernelFunc(1.5);
    173 }
    174 
    175 inline BoxKernelFunc CreateBoxKernel() { return BoxKernelFunc(); }
    176 
    177 inline TriangleKernelFunc CreateTriangleKernel() {
    178   return TriangleKernelFunc();
    179 }
    180 
    181 inline KeysCubicKernelFunc CreateKeysCubicKernel() {
    182   return KeysCubicKernelFunc();
    183 }
    184 
    185 inline MitchellCubicKernelFunc CreateMitchellCubicKernel() {
    186   return MitchellCubicKernelFunc();
    187 }
    188 
    189 }  // namespace functor
    190 }  // namespace tensorflow
    191 
    192 #endif  // TENSORFLOW_CORE_KERNELS_SAMPLING_KERNELS_H_
    193