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.
LanczosKernelFuncLanczosKernelFunc70 explicit LanczosKernelFunc(float _radius) : radius(_radius) {}
operatorLanczosKernelFunc71 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 }
RadiusLanczosKernelFunc82 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)
radiusGaussianKernelFunc94 : radius(_radius), sigma(_radius / kRadiusMultiplier) {}
operatorGaussianKernelFunc95 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 }
RadiusGaussianKernelFunc100 float Radius() const { return radius; }
101 const float radius;
102 const float sigma; // Gaussian standard deviation
103 };
104
105 struct BoxKernelFunc {
operatorBoxKernelFunc106 float operator()(float x) const {
107 x = std::abs(x);
108 return x < 0.5f ? 1. : x == 0.5f ? 0.5f : 0.0f;
109 }
RadiusBoxKernelFunc110 float Radius() const { return 1.f; }
111 };
112
113 struct TriangleKernelFunc {
114 // https://en.wikipedia.org/wiki/Triangle_function
operatorTriangleKernelFunc115 float operator()(float x) const {
116 x = std::abs(x);
117 return x < 1.0f ? 1.0f - x : 0.0f;
118 }
RadiusTriangleKernelFunc119 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):1153–1160, 1981.
operatorKeysCubicKernelFunc127 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 }
RadiusKeysCubicKernelFunc137 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):221–228, 1988.
operatorMitchellCubicKernelFunc145 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 }
RadiusMitchellCubicKernelFunc156 float Radius() const { return 2.f; }
157 };
158
CreateLanczos1Kernel()159 inline LanczosKernelFunc CreateLanczos1Kernel() {
160 return LanczosKernelFunc(1.0);
161 }
162
CreateLanczos3Kernel()163 inline LanczosKernelFunc CreateLanczos3Kernel() {
164 return LanczosKernelFunc(3.0);
165 }
166
CreateLanczos5Kernel()167 inline LanczosKernelFunc CreateLanczos5Kernel() {
168 return LanczosKernelFunc(5.0);
169 }
170
CreateGaussianKernel()171 inline GaussianKernelFunc CreateGaussianKernel() {
172 return GaussianKernelFunc(1.5);
173 }
174
CreateBoxKernel()175 inline BoxKernelFunc CreateBoxKernel() { return BoxKernelFunc(); }
176
CreateTriangleKernel()177 inline TriangleKernelFunc CreateTriangleKernel() {
178 return TriangleKernelFunc();
179 }
180
CreateKeysCubicKernel()181 inline KeysCubicKernelFunc CreateKeysCubicKernel() {
182 return KeysCubicKernelFunc();
183 }
184
CreateMitchellCubicKernel()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