Implementation:Tencent Ncnn Letterbox Resize And Pad
| Knowledge Sources | |
|---|---|
| Domains | Computer_Vision, Object_Detection |
| Last Updated | 2026-02-09 00:00 GMT |
Overview
Pattern implementation for aspect-ratio-preserving image resize with border padding for YOLO detection models, as demonstrated in ncnn detection examples.
Description
This is a Pattern Doc documenting the letterbox preprocessing pattern used across ncnn YOLO examples. The implementation combines ncnn::Mat::from_pixels_resize for the initial resize with ncnn::copy_make_border for adding padding. The pattern calculates appropriate scale factors and padding offsets, which are tracked for post-processing coordinate adjustment.
The ncnn examples (yolov8.cpp, yolo11.cpp) implement this pattern inline in the detection function. The target size is typically 640 for YOLO models, with padding aligned to stride 32 and filled with value 114.
Usage
Implement this pattern for all YOLO-family object detection preprocessing. Adapt the target size and normalization values to match the specific model.
Code Reference
Source Location
- Repository: ncnn
- File: examples/yolov8.cpp
- Lines: L298-338 (letterbox preprocessing pattern)
- Also: src/mat_pixel.cpp:L2524-2578 (from_pixels_resize), src/mat.h:L299 (substract_mean_normalize)
Signature
// Pattern: Letterbox preprocessing for YOLO detection
// Combines ncnn APIs — not a single library function
// Step 1: Calculate scale and padding
int target_size = 640;
int w = img_w;
int h = img_h;
float scale = 1.f;
if (w > h) {
scale = (float)target_size / w;
w = target_size;
h = h * scale;
} else {
scale = (float)target_size / h;
h = target_size;
w = w * scale;
}
// Step 2: Resize preserving aspect ratio
ncnn::Mat in = ncnn::Mat::from_pixels_resize(
pixels, ncnn::Mat::PIXEL_BGR2RGB, img_w, img_h, w, h);
// Step 3: Pad to target_size aligned to stride
int wpad = (w + 31) / 32 * 32 - w;
int hpad = (h + 31) / 32 * 32 - h;
ncnn::Mat in_pad;
ncnn::copy_make_border(in, in_pad, hpad / 2, hpad - hpad / 2,
wpad / 2, wpad - wpad / 2,
ncnn::BORDER_CONSTANT, 114.f);
// Step 4: Normalize
const float norm_vals[3] = {1 / 255.f, 1 / 255.f, 1 / 255.f};
in_pad.substract_mean_normalize(0, norm_vals);
Import
#include "mat.h"
#include "net.h"
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| pixels | const unsigned char* | Yes | Raw BGR pixel buffer from cv::imread |
| img_w, img_h | int | Yes | Original image dimensions |
| target_size | int | Yes | Model input size (typically 640 for YOLO) |
Outputs
| Name | Type | Description |
|---|---|---|
| in_pad | ncnn::Mat | Letterboxed, normalized tensor ready for inference |
| scale | float | Scale factor for post-processing coordinate mapping |
| wpad, hpad | int | Padding offsets for post-processing coordinate adjustment |
Usage Examples
YOLOv8 Letterbox Preprocessing
cv::Mat bgr = cv::imread("image.jpg");
int target_size = 640;
int img_w = bgr.cols;
int img_h = bgr.rows;
// Calculate scale
float scale = std::min((float)target_size / img_w,
(float)target_size / img_h);
int w = img_w * scale;
int h = img_h * scale;
// Resize preserving aspect ratio
ncnn::Mat in = ncnn::Mat::from_pixels_resize(
bgr.data, ncnn::Mat::PIXEL_BGR2RGB, img_w, img_h, w, h);
// Pad to stride-aligned size
int wpad = (w + 31) / 32 * 32 - w;
int hpad = (h + 31) / 32 * 32 - h;
ncnn::Mat in_pad;
ncnn::copy_make_border(in, in_pad,
hpad / 2, hpad - hpad / 2,
wpad / 2, wpad - wpad / 2,
ncnn::BORDER_CONSTANT, 114.f);
// Normalize to [0, 1]
const float norm_vals[3] = {1/255.f, 1/255.f, 1/255.f};
in_pad.substract_mean_normalize(0, norm_vals);
// in_pad is ready for extractor.input()
// Save scale and padding for post-processing