Implementation:Tencent Ncnn Mat Pixel Resize
| Knowledge Sources | |
|---|---|
| Domains | Computer Vision, Image Processing |
| Last Updated | 2026-02-09 19:00 GMT |
Overview
Implements bilinear interpolation-based image resizing for raw pixel buffers, supporting 1-4 channel images with SIMD-optimized paths for ARM NEON and x86 SSE2 architectures.
Description
The implementation uses a two-pass approach for bilinear resize. Helper functions vresize_two and vresize_one perform vertical interpolation by blending two source rows using pre-computed weights in fixed-point 16-bit arithmetic.
The main resize_bilinear_c1/c2/c3/c4 functions (with both implicit and explicit stride overloads) compute horizontal and vertical interpolation coefficients, then process the image row by row: first performing horizontal resampling into intermediate short-precision row buffers, then vertically blending pairs of row buffers into the output. The implementation processes two output rows at a time when possible (via vresize_two) to improve cache efficiency, falling back to single-row processing for the last row if needed.
SIMD optimization is extensive: ARM NEON processes 8-16 pixels per iteration using vqdmulhq_s16/vsraq_n_s16 for fixed-point multiply-accumulate and vqrshrun_n_s16 for saturating narrowing; SSE2 uses _mm_mulhi_epi16/_mm_add_epi16 for equivalent operations. Scalar fallbacks handle remaining pixels using 16-bit fixed-point arithmetic.
A resize_bilinear_yuv420sp variant handles YUV420SP formatted data by resizing the Y plane and UV plane separately. The entire file is guarded by the NCNN_PIXEL compile-time flag.
Usage
Use these functions for the most common preprocessing operation in neural network inference pipelines: resizing input images to match model-expected dimensions. These are the backend functions called by Mat::from_pixels_resize() and Mat::to_pixels_resize().
Code Reference
Source Location
- Repository: Tencent_Ncnn
- File: src/mat_pixel_resize.cpp
Signature
// Bilinear resize (implicit stride)
void resize_bilinear_c1(const unsigned char* src, int srcw, int srch,
unsigned char* dst, int w, int h);
void resize_bilinear_c2(const unsigned char* src, int srcw, int srch,
unsigned char* dst, int w, int h);
void resize_bilinear_c3(const unsigned char* src, int srcw, int srch,
unsigned char* dst, int w, int h);
void resize_bilinear_c4(const unsigned char* src, int srcw, int srch,
unsigned char* dst, int w, int h);
// Bilinear resize (explicit stride)
void resize_bilinear_c1(const unsigned char* src, int srcw, int srch, int srcstride,
unsigned char* dst, int w, int h, int stride);
void resize_bilinear_c2(const unsigned char* src, int srcw, int srch, int srcstride,
unsigned char* dst, int w, int h, int stride);
void resize_bilinear_c3(const unsigned char* src, int srcw, int srch, int srcstride,
unsigned char* dst, int w, int h, int stride);
void resize_bilinear_c4(const unsigned char* src, int srcw, int srch, int srcstride,
unsigned char* dst, int w, int h, int stride);
// YUV420SP variant
void resize_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch,
unsigned char* dst, int w, int h);
Import
#include "mat.h"
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| src | const unsigned char* | Yes | Source image pixel buffer |
| srcw | int | Yes | Source image width in pixels |
| srch | int | Yes | Source image height in pixels |
| srcstride | int | No | Source row stride in bytes (defaults to srcw * channels) |
| dst | unsigned char* | Yes | Destination image pixel buffer (pre-allocated) |
| w | int | Yes | Destination (target) width in pixels |
| h | int | Yes | Destination (target) height in pixels |
| stride | int | No | Destination row stride in bytes (defaults to w * channels) |
Outputs
| Name | Type | Description |
|---|---|---|
| dst | unsigned char* | Destination buffer filled with the resized image |
Usage Examples
Resizing a 3-Channel Image for Model Input
#include "mat.h"
// Resize a 640x480 RGB image to 224x224
unsigned char resized[224 * 224 * 3];
ncnn::resize_bilinear_c3(src_pixels, 640, 480, resized, 224, 224);
Resizing with Explicit Stride
#include "mat.h"
// Source has padding (stride != width * channels)
int src_stride = 1920; // e.g., 640 * 3 = 1920 or padded
int dst_stride = 672; // e.g., 224 * 3 = 672 or padded
ncnn::resize_bilinear_c3(src_pixels, 640, 480, src_stride,
dst_pixels, 224, 224, dst_stride);