Samples from the image at the passed batch at pixel location sample_f with a kernel scaled by scale.
| 91 | // Samples from the image at the passed batch at pixel location sample_f with a |
| 92 | // kernel scaled by scale. |
| 93 | void Sample(const DynamicKernel& kernel, const bool antialias, |
| 94 | TTypes<float, 4>::Tensor images, const int batch, |
| 95 | const Vector2f& scale, const Vector2f& sample_f, float* dest) { |
| 96 | const Vector2f kernel_scale(antialias ? std::max(scale.x(), 1.0f) : 1.0, |
| 97 | antialias ? std::max(scale.y(), 1.0f) : 1.0); |
| 98 | |
| 99 | const int64 in_height = images.dimension(1); |
| 100 | const int64 in_width = images.dimension(2); |
| 101 | const int channels = images.dimension(3); |
| 102 | const int64 y_span_start = Clamp( |
| 103 | static_cast<int64>(0), in_height - 1, |
| 104 | static_cast<int64>( |
| 105 | std::ceil(sample_f.y() - kernel.Radius() * kernel_scale.y() - 0.5f))); |
| 106 | const int64 y_span_end = |
| 107 | Clamp(static_cast<int64>(0), in_height - 1, |
| 108 | static_cast<int64>(std::floor( |
| 109 | sample_f.y() + kernel.Radius() * kernel_scale.y() - 0.5f))) + |
| 110 | 1; |
| 111 | const int64 x_span_start = Clamp( |
| 112 | static_cast<int64>(0), in_width - 1, |
| 113 | static_cast<int64>( |
| 114 | std::ceil(sample_f.x() - kernel.Radius() * kernel_scale.x() - 0.5f))); |
| 115 | |
| 116 | const int64 x_span_end = |
| 117 | Clamp(static_cast<int64>(0), in_width - 1, |
| 118 | static_cast<int64>(std::floor( |
| 119 | sample_f.x() + kernel.Radius() * kernel_scale.x() - 0.5f))) + |
| 120 | 1; |
| 121 | |
| 122 | std::fill(dest, dest + channels, 0.0f); |
| 123 | if (sample_f.x() < 0.0f || sample_f.y() < 0.0f || sample_f.x() > in_width || |
| 124 | sample_f.y() > in_height) { |
| 125 | return; |
| 126 | } |
| 127 | const Vector2f one_over_kernel_scale(1.0f / kernel_scale.x(), |
| 128 | 1.0f / kernel_scale.y()); |
| 129 | float total_weight = 0.0f; |
| 130 | for (int64 y = y_span_start; y < y_span_end; ++y) { |
| 131 | float y_kernel_pos = static_cast<float>(y) + 0.5f - sample_f.y(); |
| 132 | float y_weight = kernel.Value(y_kernel_pos * one_over_kernel_scale.y()); |
| 133 | for (int64 x = x_span_start; x < x_span_end; ++x) { |
| 134 | float x_kernel_pos = static_cast<float>(x) + 0.5f - sample_f.x(); |
| 135 | float x_weight = kernel.Value(x_kernel_pos * one_over_kernel_scale.x()); |
| 136 | float kernel_weight = y_weight * x_weight; |
| 137 | total_weight += kernel_weight; |
| 138 | for (int c = 0; c < channels; ++c) { |
| 139 | dest[c] += static_cast<float>(images(batch, y, x, c)) * kernel_weight; |
| 140 | } |
| 141 | } |
| 142 | } |
| 143 | if (std::abs(total_weight) >= 1000.0f * std::numeric_limits<float>::min()) { |
| 144 | CHECK_NE(total_weight, 0.0f) << y_span_start << "," << y_span_end << " " |
| 145 | << x_span_start << "," << x_span_end; |
| 146 | for (int c = 0; c < channels; ++c) { |
| 147 | dest[c] /= total_weight; |
| 148 | } |
| 149 | } |
| 150 | } |