|
10 | 10 |
|
11 | 11 | namespace caffe { |
12 | 12 |
|
| 13 | +static float bicubicCoeff(float x_) |
| 14 | +{ |
| 15 | + float x = fabs(x_); |
| 16 | + if (x <= 1.0f) return x * x * (1.5f * x - 2.5f) + 1.0f; |
| 17 | + else if (x < 2.0f) return x * (x * (-0.5f * x + 2.5f) - 4.0f) + 2.0f; |
| 18 | + else return 0.0f; |
| 19 | +} |
| 20 | + |
| 21 | +static float boxCoeff(float x) |
| 22 | +{ |
| 23 | + if (-0.5 <= x && x<0.5) return 1.0; |
| 24 | + return 0; |
| 25 | +} |
| 26 | + |
| 27 | +static float triangleCoeff(float x) |
| 28 | +{ |
| 29 | + if (-1<=x && x<0) return x+1; |
| 30 | + if (0<=x && x<=1) return 1-x; |
| 31 | + return 0; |
| 32 | +} |
| 33 | + |
| 34 | +#define FILTER_BICUBIC 0 |
| 35 | +#define FILTER_BOX 1 |
| 36 | +#define FILTER_TRIANGLE 2 |
| 37 | + |
| 38 | +template <typename Dtype> |
| 39 | +void InterpolationKernel( |
| 40 | + const int nthreads, |
| 41 | + const int in_channelsize, |
| 42 | + const int out_channelsize, |
| 43 | + const Dtype* in_ptr, |
| 44 | + const int in_width, |
| 45 | + const int in_height, |
| 46 | + const float fx, |
| 47 | + const float fy, |
| 48 | + Dtype* out_ptr, |
| 49 | + const int out_width, |
| 50 | + const int out_height, |
| 51 | + int filter_type, |
| 52 | + int kernel_width, |
| 53 | + const bool antialias) |
| 54 | +{ |
| 55 | + for (int index = 0; index < nthreads; ++index) |
| 56 | + { |
| 57 | + int c = index / out_channelsize; |
| 58 | + int x_out = (index % out_channelsize) % out_width; |
| 59 | + int y_out = (index % out_channelsize) / out_width; |
| 60 | + |
| 61 | + float x_in = x_out * fx + fy / 2.0f - 0.5f; |
| 62 | + float y_in = y_out * fy + fx / 2.0f - 0.5f; |
| 63 | + |
| 64 | + int x_in_round = round(x_in); |
| 65 | + int y_in_round = round(y_in); |
| 66 | + |
| 67 | + Dtype sum = 0; |
| 68 | + Dtype wsum = 0; |
| 69 | + |
| 70 | + float ax = 1.0f / (antialias ? fx : 1.0f); |
| 71 | + float ay = 1.0f / (antialias ? fy : 1.0f); |
| 72 | + int rx = (fx < 1.0f) ? 2 : ceil(float(kernel_width) / ax); |
| 73 | + int ry = (fy < 1.0f) ? 2 : ceil(float(kernel_width) / ay); |
| 74 | + |
| 75 | + for (int y = y_in_round - ry; y <= y_in_round + ry; y++) |
| 76 | + for (int x = x_in_round - rx; x <= x_in_round + rx; x++) |
| 77 | + { |
| 78 | + if (y < 0 || x < 0) continue; |
| 79 | + if (y >= in_height || x >= in_width) continue; |
| 80 | + |
| 81 | + float dx = x_in - x; |
| 82 | + float dy = y_in - y; |
| 83 | + |
| 84 | + float w; |
| 85 | + if (filter_type == FILTER_BICUBIC) w = ax * bicubicCoeff(ax * dx) * ay * bicubicCoeff(ay * dy); |
| 86 | + else if (filter_type == FILTER_BOX) w = ax * boxCoeff(ax * dx) * ay * boxCoeff(ay * dy); |
| 87 | + else w = ax * triangleCoeff(ax * dx) * ay * triangleCoeff(ay * dy); |
| 88 | + sum += w * in_ptr[c * in_channelsize + y * in_width + x]; |
| 89 | + wsum += w; |
| 90 | + } |
| 91 | + |
| 92 | + out_ptr[index] = (!wsum) ? 0 : (sum / wsum); |
| 93 | + } |
| 94 | +} |
| 95 | + |
| 96 | +template <typename Dtype> |
| 97 | +void NearestNeighborKernel( |
| 98 | + const int nthreads, |
| 99 | + const int in_channelsize, |
| 100 | + const int out_channelsize, |
| 101 | + const Dtype* in_ptr, |
| 102 | + const int in_width, |
| 103 | + const int in_height, |
| 104 | + const float fx, |
| 105 | + const float fy, |
| 106 | + Dtype* out_ptr, |
| 107 | + const int out_width, |
| 108 | + const int out_height) |
| 109 | +{ |
| 110 | + for (int index = 0; index < nthreads; ++index) |
| 111 | + { |
| 112 | + int c = index / out_channelsize; |
| 113 | + int x_out = (index % out_channelsize) % out_width; |
| 114 | + int y_out = (index % out_channelsize) / out_width; |
| 115 | + |
| 116 | + float x_in = x_out * fx + fy / 2.0f - 0.5f; |
| 117 | + float y_in = y_out * fy + fx / 2.0f - 0.5f; |
| 118 | + |
| 119 | + int x_in_round = round(x_in); |
| 120 | + int y_in_round = round(y_in); |
| 121 | + |
| 122 | + out_ptr[index] = in_ptr[c * in_channelsize + y_in_round * in_width + x_in_round]; |
| 123 | + } |
| 124 | +} |
| 125 | + |
13 | 126 | template <typename Dtype> |
14 | 127 | void ResampleLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, |
15 | 128 | const vector<Blob<Dtype>*>& top) { |
@@ -56,9 +169,82 @@ void ResampleLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom, |
56 | 169 |
|
57 | 170 | template <typename Dtype> |
58 | 171 | void ResampleLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom, |
59 | | - const vector<Blob<Dtype>*>& top) |
| 172 | + const vector<Blob<Dtype>*>& top) |
60 | 173 | { |
61 | | - NOT_IMPLEMENTED; |
| 174 | + |
| 175 | + Dtype* top_data = top[0]->mutable_cpu_data(); // dest |
| 176 | + int topwidth = top[0]->width(); |
| 177 | + int topheight = top[0]->height(); |
| 178 | + int topchannels = top[0]->channels(); |
| 179 | +// int topcount = top[0]->count(); |
| 180 | + |
| 181 | + Dtype* bottom_data = bottom[0]->mutable_cpu_data(); // source |
| 182 | + int bottomnum = (bottom)[0]->num(); |
| 183 | + int bottomchannels = (bottom)[0]->channels(); |
| 184 | + int bottomwidth = (bottom)[0]->width(); |
| 185 | + int bottomheight = (bottom)[0]->height(); |
| 186 | +// int bottomcount = (bottom)[0]->count(); |
| 187 | + |
| 188 | + CHECK_EQ(topchannels, bottomchannels) << "ResampleLayer top channel count must match bottom channel count"; |
| 189 | + |
| 190 | + float fx = float(bottomwidth) / float(topwidth); |
| 191 | + float fy = float(bottomheight) / float(topheight); |
| 192 | + |
| 193 | + //int botsize = bottomwidth*bottomheight*bottomchannels*bottomnum; |
| 194 | + int topsize = topwidth * topheight * topchannels*bottomnum; |
| 195 | + int topchannelsize = topwidth*topheight; |
| 196 | + int botchannelsize = bottomwidth*bottomheight; |
| 197 | + |
| 198 | + if (this->layer_param().resample_param().type() == ResampleParameter_ResampleType_NEAREST) |
| 199 | + { |
| 200 | + NearestNeighborKernel<Dtype>( |
| 201 | + topsize, |
| 202 | + botchannelsize, |
| 203 | + topchannelsize, |
| 204 | + (Dtype*) bottom_data, |
| 205 | + bottomwidth, |
| 206 | + bottomheight, |
| 207 | + fx, |
| 208 | + fy, |
| 209 | + (Dtype*) top_data, |
| 210 | + topwidth, |
| 211 | + topheight |
| 212 | + ); |
| 213 | + } |
| 214 | + else if (this->layer_param().resample_param().type() == ResampleParameter_ResampleType_CUBIC || this->layer_param().resample_param().type() == ResampleParameter_ResampleType_LINEAR) |
| 215 | + { |
| 216 | + int filter_type; |
| 217 | + if (this->layer_param().resample_param().type() == ResampleParameter_ResampleType_CUBIC) |
| 218 | + filter_type = FILTER_BICUBIC; |
| 219 | + else if (this->layer_param().resample_param().type() == ResampleParameter_ResampleType_LINEAR) |
| 220 | + filter_type = FILTER_TRIANGLE; |
| 221 | + |
| 222 | + bool isDownsample = (fx > 1) || (fy > 1); |
| 223 | + bool antialias = isDownsample && this->layer_param_.resample_param().antialias(); |
| 224 | + |
| 225 | + int kernel_width; |
| 226 | + if (filter_type == FILTER_BICUBIC) kernel_width = 4; |
| 227 | + else if (filter_type == FILTER_BOX) kernel_width = 1; |
| 228 | + else kernel_width = 2; |
| 229 | + |
| 230 | + InterpolationKernel<Dtype>( |
| 231 | + topsize, |
| 232 | + botchannelsize, |
| 233 | + topchannelsize, |
| 234 | + (Dtype*) bottom_data, |
| 235 | + bottomwidth, |
| 236 | + bottomheight, |
| 237 | + fx, |
| 238 | + fy, |
| 239 | + (Dtype*) top_data, |
| 240 | + topwidth, |
| 241 | + topheight, |
| 242 | + filter_type, |
| 243 | + kernel_width, |
| 244 | + antialias); |
| 245 | + } |
| 246 | + else |
| 247 | + LOG(FATAL) << "unsupported downsampling type"; |
62 | 248 | } |
63 | 249 |
|
64 | 250 | template <typename Dtype> |
|
0 commit comments