Browse Source

resize bicubic

tags/20190611
nihuini 7 years ago
parent
commit
dfffb29bb5
6 changed files with 344 additions and 14 deletions
  1. +2
    -2
      src/layer/arm/interp_arm.cpp
  2. +312
    -3
      src/layer/interp.cpp
  3. +1
    -1
      src/layer/interp.h
  4. +20
    -0
      src/mat.cpp
  5. +1
    -0
      src/mat.h
  6. +8
    -8
      src/mat_pixel_resize.cpp

+ 2
- 2
src/layer/arm/interp_arm.cpp View File

@@ -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;



+ 312
- 3
src/layer/interp.cpp View File

@@ -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);


+ 1
- 1
src/layer/interp.h View File

@@ -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;


+ 20
- 0
src/mat.cpp View File

@@ -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);


+ 1
- 0
src/mat.h View File

@@ -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);


+ 8
- 8
src/mat_pixel_resize.cpp View File

@@ -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;



Loading…
Cancel
Save