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