From dfffb29bb51d43562880f376e7ff483a7add32cb Mon Sep 17 00:00:00 2001 From: nihuini Date: Fri, 29 Mar 2019 11:29:15 +0800 Subject: [PATCH] resize bicubic --- src/layer/arm/interp_arm.cpp | 4 +- src/layer/interp.cpp | 315 ++++++++++++++++++++++++++++++++++- src/layer/interp.h | 2 +- src/mat.cpp | 20 +++ src/mat.h | 1 + src/mat_pixel_resize.cpp | 16 +- 6 files changed, 344 insertions(+), 14 deletions(-) diff --git a/src/layer/arm/interp_arm.cpp b/src/layer/arm/interp_arm.cpp index 0651366d9..ec57e334e 100644 --- a/src/layer/arm/interp_arm.cpp +++ b/src/layer/arm/interp_arm.cpp @@ -87,8 +87,8 @@ static void resize_bilinear_image(const Mat& src, Mat& dst) } // loop body - Mat rowsbuf0(w + 1); - Mat rowsbuf1(w + 1); + Mat rowsbuf0(w); + Mat rowsbuf1(w); float* rows0 = rowsbuf0; float* rows1 = rowsbuf1; diff --git a/src/layer/interp.cpp b/src/layer/interp.cpp index ad91b295f..0294dcda8 100644 --- a/src/layer/interp.cpp +++ b/src/layer/interp.cpp @@ -110,8 +110,8 @@ static void resize_bilinear_image(const Mat& src, Mat& dst) } // loop body - Mat rowsbuf0(w + 1); - Mat rowsbuf1(w + 1); + Mat rowsbuf0(w); + Mat rowsbuf1(w); float* rows0 = rowsbuf0; float* rows1 = rowsbuf1; @@ -192,6 +192,302 @@ static void resize_bilinear_image(const Mat& src, Mat& dst) delete[] buf; } +static inline void interpolate_cubic(float fx, float* coeffs) +{ + const float A = -0.75f; + + float fx0 = fx + 1; + float fx1 = fx; + float fx2 = 1 - fx; + // float fx3 = 2 - fx; + + coeffs[0] = A * fx0*fx0*fx0 - 5*A * fx0*fx0 + 8*A * fx0 - 4*A; + coeffs[1] = (A+2) * fx1*fx1*fx1 - (A+3) * fx1*fx1 + 1; + coeffs[2] = (A+2) * fx2*fx2*fx2 - (A+3) * fx2*fx2 + 1; + coeffs[3] = 1.f - coeffs[0] - coeffs[1] - coeffs[2]; +} + +static void resize_bicubic_image(const Mat& src, Mat& dst) +{ + int w = dst.w; + int h = dst.w; + + double scale_x = (double)src.w / w; + double scale_y = (double)src.h / h; + + int* buf = new int[w + h + w*4 + h*4]; + + int* xofs = buf;//new int[w]; + int* yofs = buf + w;//new int[h]; + + float* alpha = (float*)(buf + w + h);//new float[w * 4]; + float* beta = (float*)(buf + w + h + w*4);//new float[h * 4]; + + float fx; + float fy; + int sx; + int sy; + + for (int dx = 0; dx < w; dx++) + { + fx = (float)((dx + 0.5) * scale_x - 0.5); + sx = floor(fx); + fx -= sx; + + interpolate_cubic(fx, alpha + dx*4); + + if (sx <= -1) + { + sx = 1; + alpha[dx*4 +0] = alpha[dx*4 +0] + alpha[dx*4 +1] + alpha[dx*4 +2]; + alpha[dx*4 +1] = alpha[dx*4 +3]; + alpha[dx*4 +2] = 0.f; + alpha[dx*4 +3] = 0.f; + } + if (sx == 0) + { + sx = 1; + alpha[dx*4 +0] = alpha[dx*4 +0] + alpha[dx*4 +1]; + alpha[dx*4 +1] = alpha[dx*4 +2]; + alpha[dx*4 +2] = alpha[dx*4 +3]; + alpha[dx*4 +3] = 0.f; + } + if (sx == src.w - 2) + { + sx = src.w - 3; + alpha[dx*4 +3] = alpha[dx*4 +2] + alpha[dx*4 +3]; + alpha[dx*4 +2] = alpha[dx*4 +1]; + alpha[dx*4 +1] = alpha[dx*4 +0]; + alpha[dx*4 +0] = 0.f; + } + if (sx >= src.w - 1) + { + sx = src.w - 3; + alpha[dx*4 +3] = 1.f - alpha[dx*4 +0]; + alpha[dx*4 +2] = alpha[dx*4 +0]; + alpha[dx*4 +1] = 0.f; + alpha[dx*4 +0] = 0.f; + } + + xofs[dx] = sx; + } + + for (int dy = 0; dy < h; dy++) + { + fy = (float)((dy + 0.5) * scale_y - 0.5); + sy = floor(fy); + fy -= sy; + + interpolate_cubic(fy, beta + dy*4); + + if (sy <= -1) + { + sy = 1; + beta[dy*4 +0] = beta[dy*4 +0] + beta[dy*4 +1] + beta[dy*4 +2]; + beta[dy*4 +1] = beta[dy*4 +3]; + beta[dy*4 +2] = 0.f; + beta[dy*4 +3] = 0.f; + } + if (sy == 0) + { + sy = 1; + beta[dy*4 +0] = beta[dy*4 +0] + beta[dy*4 +1]; + beta[dy*4 +1] = beta[dy*4 +2]; + beta[dy*4 +2] = beta[dy*4 +3]; + beta[dy*4 +3] = 0.f; + } + if (sy == src.h - 2) + { + sy = src.h - 3; + beta[dy*4 +3] = beta[dy*4 +2] + beta[dy*4 +3]; + beta[dy*4 +2] = beta[dy*4 +1]; + beta[dy*4 +1] = beta[dy*4 +0]; + beta[dy*4 +0] = 0.f; + } + if (sy >= src.h - 1) + { + sy = src.h - 3; + beta[dy*4 +3] = 1.f - beta[dy*4 +0]; + beta[dy*4 +2] = beta[dy*4 +0]; + beta[dy*4 +1] = 0.f; + beta[dy*4 +0] = 0.f; + } + + yofs[dy] = sy; + } + + // loop body + Mat rowsbuf0(w); + Mat rowsbuf1(w); + Mat rowsbuf2(w); + Mat rowsbuf3(w); + float* rows0 = rowsbuf0; + float* rows1 = rowsbuf1; + float* rows2 = rowsbuf2; + float* rows3 = rowsbuf3; + + int prev_sy1 = -3; + + for (int dy = 0; dy < h; dy++ ) + { + int sy = yofs[dy]; + + if (sy == prev_sy1) + { + // reuse all rows + } + else if (sy == prev_sy1 + 1) + { + // hresize one row + float* rows0_old = rows0; + rows0 = rows1; + rows1 = rows2; + rows2 = rows3; + rows3 = rows0_old; + const float* S3 = src.row(sy+2); + + const float* alphap = alpha; + float* rows3p = rows3; + for (int dx = 0; dx < w; dx++) + { + int sx = xofs[dx]; + const float* S3p = S3 + sx; + + float a0 = alphap[0]; + float a1 = alphap[1]; + float a2 = alphap[2]; + float a3 = alphap[3]; + rows3p[dx] = S3p[-1]*a0 + S3p[0]*a1 + S3p[1]*a2 + S3p[2]*a3; + + alphap += 4; + } + } + else if (sy == prev_sy1 + 2) + { + // hresize two rows + float* rows0_old = rows0; + float* rows1_old = rows1; + rows0 = rows2; + rows1 = rows3; + rows2 = rows0_old; + rows3 = rows1_old; + const float* S2 = src.row(sy+1); + const float* S3 = src.row(sy+2); + + const float* alphap = alpha; + float* rows2p = rows2; + float* rows3p = rows3; + for (int dx = 0; dx < w; dx++) + { + int sx = xofs[dx]; + const float* S2p = S2 + sx; + const float* S3p = S3 + sx; + + float a0 = alphap[0]; + float a1 = alphap[1]; + float a2 = alphap[2]; + float a3 = alphap[3]; + rows2p[dx] = S2p[-1]*a0 + S2p[0]*a1 + S2p[1]*a2 + S2p[2]*a3; + rows3p[dx] = S3p[-1]*a0 + S3p[0]*a1 + S3p[1]*a2 + S3p[2]*a3; + + alphap += 4; + } + } + else if (sy == prev_sy1 + 3) + { + // hresize three rows + float* rows0_old = rows0; + float* rows1_old = rows1; + float* rows2_old = rows2; + rows0 = rows3; + rows1 = rows0_old; + rows2 = rows1_old; + rows3 = rows2_old; + const float* S1 = src.row(sy); + const float* S2 = src.row(sy+1); + const float* S3 = src.row(sy+2); + + const float* alphap = alpha; + float* rows1p = rows1; + float* rows2p = rows2; + float* rows3p = rows3; + for (int dx = 0; dx < w; dx++) + { + int sx = xofs[dx]; + const float* S1p = S1 + sx; + const float* S2p = S2 + sx; + const float* S3p = S3 + sx; + + float a0 = alphap[0]; + float a1 = alphap[1]; + float a2 = alphap[2]; + float a3 = alphap[3]; + rows1p[dx] = S1p[-1]*a0 + S1p[0]*a1 + S1p[1]*a2 + S1p[2]*a3; + rows2p[dx] = S2p[-1]*a0 + S2p[0]*a1 + S2p[1]*a2 + S2p[2]*a3; + rows3p[dx] = S3p[-1]*a0 + S3p[0]*a1 + S3p[1]*a2 + S3p[2]*a3; + + alphap += 4; + } + } + else + { + // hresize four rows + const float* S0 = src.row(sy-1); + const float* S1 = src.row(sy); + const float* S2 = src.row(sy+1); + const float* S3 = src.row(sy+2); + + const float* alphap = alpha; + float* rows0p = rows0; + float* rows1p = rows1; + float* rows2p = rows2; + float* rows3p = rows3; + for (int dx = 0; dx < w; dx++) + { + int sx = xofs[dx]; + const float* S0p = S0 + sx; + const float* S1p = S1 + sx; + const float* S2p = S2 + sx; + const float* S3p = S3 + sx; + + float a0 = alphap[0]; + float a1 = alphap[1]; + float a2 = alphap[2]; + float a3 = alphap[3]; + rows0p[dx] = S0p[-1]*a0 + S0p[0]*a1 + S0p[1]*a2 + S0p[2]*a3; + rows1p[dx] = S1p[-1]*a0 + S1p[0]*a1 + S1p[1]*a2 + S1p[2]*a3; + rows2p[dx] = S2p[-1]*a0 + S2p[0]*a1 + S2p[1]*a2 + S2p[2]*a3; + rows3p[dx] = S3p[-1]*a0 + S3p[0]*a1 + S3p[1]*a2 + S3p[2]*a3; + + alphap += 4; + } + } + + prev_sy1 = sy; + + // vresize + float b0 = beta[0]; + float b1 = beta[1]; + float b2 = beta[2]; + float b3 = beta[3]; + + float* rows0p = rows0; + float* rows1p = rows1; + float* rows2p = rows2; + float* rows3p = rows3; + float* Dp = dst.row(dy); + for (int dx = 0; dx < w; dx++) + { +// D[x] = rows0[x]*b0 + rows1[x]*b1 + rows2[x]*b2 + rows3[x]*b3; + *Dp++ = *rows0p++ * b0 + *rows1p++ * b1 + *rows2p++ * b2 + *rows3p++ * b3; + } + + beta += 4; + } + + delete[] buf; +} + int Interp::forward(const Mat &bottom_blob, Mat &top_blob, const Option& opt) const { int h = bottom_blob.h; @@ -233,7 +529,7 @@ int Interp::forward(const Mat &bottom_blob, Mat &top_blob, const Option& opt) co return 0; } - if (resize_type == 1)//nearest + if (resize_type == 1)// nearest { #pragma omp parallel for num_threads(opt.num_threads) for (int q = 0; q < c; ++q) @@ -266,6 +562,19 @@ int Interp::forward(const Mat &bottom_blob, Mat &top_blob, const Option& opt) co return 0; } + else if (resize_type == 3)// bicubic + { + #pragma omp parallel for num_threads(opt.num_threads) + for (int q = 0; q < c; ++q) + { + const Mat src = bottom_blob.channel(q); + Mat dst = top_blob.channel(q); + + resize_bicubic_image(src, dst); + } + + return 0; + } else { fprintf(stderr, "unsupported resize type %d %d %d\n", resize_type, oh, ow); diff --git a/src/layer/interp.h b/src/layer/interp.h index 5a422f5e6..c325b1a82 100644 --- a/src/layer/interp.h +++ b/src/layer/interp.h @@ -37,7 +37,7 @@ public: public: // param - int resize_type;//1:near 2: bilinear + int resize_type;//1=nearest 2=bilinear 3=bicubic float width_scale; float height_scale; int output_width; diff --git a/src/mat.cpp b/src/mat.cpp index a05d82208..84b645870 100644 --- a/src/mat.cpp +++ b/src/mat.cpp @@ -286,6 +286,26 @@ void resize_bilinear(const Mat& src, Mat& dst, int w, int h, Allocator* allocato delete interp; } +void resize_bicubic(const Mat& src, Mat& dst, int w, int h, Allocator* allocator, int num_threads) +{ + ncnn::Layer* interp = ncnn::create_layer(ncnn::LayerType::Interp); + + ncnn::ParamDict pd; + pd.set(0, 3); + pd.set(3, h); + pd.set(4, w); + + interp->load_param(pd); + + ncnn::Option opt = ncnn::get_default_option(); + opt.num_threads = num_threads; + opt.blob_allocator = allocator; + + interp->forward(src, dst, opt); + + delete interp; +} + void convert_packing(const Mat& src, Mat& dst, int _packing, Allocator* allocator, int num_threads) { ncnn::Layer* packing = ncnn::create_layer(ncnn::LayerType::Packing); diff --git a/src/mat.h b/src/mat.h index fae02c786..51595c06c 100644 --- a/src/mat.h +++ b/src/mat.h @@ -368,6 +368,7 @@ enum void copy_make_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, int type, float v, Allocator* allocator = 0, int num_threads = 1); void copy_cut_border(const Mat& src, Mat& dst, int top, int bottom, int left, int right, Allocator* allocator = 0, int num_threads = 1); void resize_bilinear(const Mat& src, Mat& dst, int w, int h, Allocator* allocator = 0, int num_threads = 1); +void resize_bicubic(const Mat& src, Mat& dst, int w, int h, Allocator* allocator = 0, int num_threads = 1); void convert_packing(const Mat& src, Mat& dst, int packing, Allocator* allocator = 0, int num_threads = 1); void cast_float32_to_float16(const Mat& src, Mat& dst, Allocator* allocator = 0, int num_threads = 1); void cast_float16_to_float32(const Mat& src, Mat& dst, Allocator* allocator = 0, int num_threads = 1); diff --git a/src/mat_pixel_resize.cpp b/src/mat_pixel_resize.cpp index 007e60335..e937ebfde 100644 --- a/src/mat_pixel_resize.cpp +++ b/src/mat_pixel_resize.cpp @@ -103,8 +103,8 @@ void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, unsigned c #undef SATURATE_CAST_SHORT // loop body - Mat rowsbuf0((w >> 1) + 1); - Mat rowsbuf1((w >> 1) + 1); + Mat rowsbuf0(w, (size_t)2u); + Mat rowsbuf1(w, (size_t)2u); short* rows0 = (short*)rowsbuf0.data; short* rows1 = (short*)rowsbuf1.data; @@ -358,8 +358,8 @@ void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, unsigned c #undef SATURATE_CAST_SHORT // loop body - Mat rowsbuf0((w*2 >> 1) + 2); - Mat rowsbuf1((w*2 >> 1) + 2); + Mat rowsbuf0(w*2, (size_t)2u); + Mat rowsbuf1(w*2, (size_t)2u); short* rows0 = (short*)rowsbuf0.data; short* rows1 = (short*)rowsbuf1.data; @@ -651,8 +651,8 @@ void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, unsigned c #undef SATURATE_CAST_SHORT // loop body - Mat rowsbuf0((w*3 >> 1) + 3); - Mat rowsbuf1((w*3 >> 1) + 3); + Mat rowsbuf0(w*3, (size_t)2u); + Mat rowsbuf1(w*3, (size_t)2u); short* rows0 = (short*)rowsbuf0.data; short* rows1 = (short*)rowsbuf1.data; @@ -949,8 +949,8 @@ void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, unsigned c #undef SATURATE_CAST_SHORT // loop body - Mat rowsbuf0((w*4 >> 1) + 4); - Mat rowsbuf1((w*4 >> 1) + 4); + Mat rowsbuf0(w*4, (size_t)2u); + Mat rowsbuf1(w*4, (size_t)2u); short* rows0 = (short*)rowsbuf0.data; short* rows1 = (short*)rowsbuf1.data;