@@ -1060,6 +1060,62 @@ inline tensor resize2d_bilinear(const tensor& in_vol, const shape2& target_size)
1060
1060
return out_vol;
1061
1061
}
1062
1062
1063
+ // just a clamping function, since I don't know if project has one
1064
+ inline std::size_t clamp (const std::size_t x, const std::size_t min, const std::size_t max) {
1065
+ return fplus::min (fplus::max (x, min), max);
1066
+ }
1067
+ // cubic spline interpolation
1068
+ inline float_type cerp (const float_type* p, const float_type t) {
1069
+ return p[1 ] + 0 .5f * t * (p[2 ] - p[0 ] + t * (2 .0f * p[0 ] - 5 .0f * p[1 ] + 4 .0f * p[2 ] - p[3 ] + t * (3 .0f * (p[1 ] - p[2 ]) + p[3 ] - p[0 ])));
1070
+ }
1071
+ // bicubic interpolation
1072
+ inline float_type bicerp (const float_type* p, float_type x, float_type y) {
1073
+ float_type tmp[4 ];
1074
+ tmp[0 ] = cerp (p, x);
1075
+ tmp[1 ] = cerp (p + 4 , x);
1076
+ tmp[2 ] = cerp (p + 8 , x);
1077
+ tmp[3 ] = cerp (p + 12 , x);
1078
+ return cerp (tmp, y);
1079
+ }
1080
+ inline float_type interpolate_2d_value_bicubicly (const tensor& t, float_type y, float_type x, std::size_t z) {
1081
+ // Clamping to max size is done in the gathering step
1082
+ y = fplus::max (0 , y);
1083
+ x = fplus::max (0 , x);
1084
+ // Corner coordinates as integers
1085
+ std::size_t y0 = static_cast <std::size_t >(y);
1086
+ std::size_t x0 = static_cast <std::size_t >(x);
1087
+ // Relative position for interpolation
1088
+ float_type vals[16 ];
1089
+ // Gather values in area of 4x4 pixels, might want to switch the loop ordering, since idk what is the storage order
1090
+ for (std::size_t i = 0 ; i < 4 ; i++) {
1091
+ std::size_t pos_y = clamp (y0 + i - 1 , 0 , t.height () - 1 );
1092
+ for (std::size_t j = 0 ; j < 4 ; j++) {
1093
+ std::size_t pos_x = clamp (x0 + j - 1 , 0 , t.width () - 1 );
1094
+ vals[i * 4 + j] = t.get_ignore_rank (tensor_pos (pos_y, pos_x, z));
1095
+ }
1096
+ }
1097
+ float_type x_t = x - static_cast <float_type>(x0);
1098
+ float_type y_t = y - static_cast <float_type>(y0);
1099
+ return static_cast <float_type>(bicerp (vals, x_t , y_t ));
1100
+ }
1101
+
1102
+ inline tensor resize2d_bicubic (const tensor& in_vol, const shape2& target_size) {
1103
+ tensor out_vol (tensor_shape (target_size.height_ , target_size.width_ , in_vol.shape ().depth_ ), 0 );
1104
+ const float_type scale_y = static_cast <float_type>(target_size.height_ ) / static_cast <float_type>(in_vol.shape ().height_ );
1105
+ const float_type scale_x = static_cast <float_type>(target_size.width_ ) / static_cast <float_type>(in_vol.shape ().width_ );
1106
+ for (std::size_t y = 0 ; y < out_vol.shape ().height_ ; ++y) {
1107
+ const auto y_in = (static_cast <float_type>(y) + 0 .5f ) / scale_y - 0 .5f ;
1108
+ for (std::size_t x = 0 ; x < out_vol.shape ().width_ ; ++x) {
1109
+ const auto x_in = (static_cast <float_type>(x) + 0 .5f ) / scale_x - 0 .5f ;
1110
+ for (std::size_t z = 0 ; z < in_vol.shape ().depth_ ; ++z) {
1111
+ float_type val = interpolate_2d_value_bicubicly (in_vol, y_in, x_in, z);
1112
+ out_vol.set_ignore_rank (tensor_pos (y, x, z), val);
1113
+ }
1114
+ }
1115
+ }
1116
+ return out_vol;
1117
+ }
1118
+
1063
1119
inline float_type interpolate_2d_value_area (const tensor& t,
1064
1120
float_type top, float_type bottom, float_type left, float_type right,
1065
1121
std::size_t z)
0 commit comments