Software/Arduino Core/Neural Networks

Aspect Modes and Coordinates

Mapping the camera frame into a square model input, and the coordinate spaces used by post-processors and the host.

intermediate2 min read

The camera produces a rectangular frame and most models accept a square input. cfg.nn.aspect selects how the frame is fitted to the input.

Modes

ModeBehaviourTypical use
ASPECT_STRETCHThe whole frame is scaled non-uniformly into the input. Full field of view; distortion along the long axisModels insensitive to shape. The default
ASPECT_CROP_CENTERThe largest centred rectangle with the input's aspect ratio is scaled uniformly. No distortion; the sides are excluded from the modelFaces, poses, hands
ASPECT_CROP_OFFSETThe rectangle given by cfg.nn.crop_*, in camera pixelsRegion of interest

For an 800x480 frame and a 256x256 input, centre crop selects the 480x480 square at x = 160. For 1024x768 it selects 768x768 at x = 128. The display and the stream show the full frame in every mode.

cpp
cfg.nn.aspect = ASPECT_CROP_CENTER;

An offset crop of the top left quarter of an 800x480 frame:

cpp
cfg.nn.aspect = ASPECT_CROP_OFFSET;
cfg.nn.crop_x = 0;   cfg.nn.crop_y = 0;
cfg.nn.crop_w = 400; cfg.nn.crop_h = 240;

Under offset crop the rectangle is clamped to lie within the frame and to be at least the model input size, because the hardware only downsizes. A clamp prints one warning naming the adjustment.

Result mapping

A model reports positions in NN-normalised coordinates: 0 to 1 across its input, which under a crop covers only part of the frame. The bundled post-processors and metadata builders convert these to camera-normalised coordinates, 0 to 1 across the full frame, before drawing or publishing. Boxes, masks and keypoints therefore align with the image on the panel and in Neuro Studio under every mode.

Helper functions

Custom post-processors use the same helpers, provided by Arduino.h:

cpp
float cam_x = nn_norm_to_cam_norm_x(det.x_norm);   // for host metadata
float cam_y = nn_norm_to_cam_norm_y(det.y_norm);

int lcd_x = nn_norm_to_lcd_x(det.x_norm);          // panel pixel, for the overlay
int lcd_y = nn_norm_to_lcd_y(det.y_norm);

Both are identities under WVGA with stretch. Under VGA the panel helper adds the 80 pixel letterbox offset. Under a crop both scale and offset. They read the live crop and remain correct after runRoi().

The underlying values are also exposed:

cpp
extern uint16_t g_camera_full_w, g_camera_full_h;   // full frame
extern uint16_t g_nn_crop_x, g_nn_crop_y;           // model window, camera pixels
extern uint16_t g_nn_crop_w, g_nn_crop_h;
extern int16_t  g_lcd_camera_x, g_lcd_camera_y;     // camera region on the panel
extern uint16_t g_lcd_camera_w, g_lcd_camera_h;

Coordinate spaces

SpaceRangeMeaning
NN-normalised0 to 1Within the crop fed to the current model. All post-processors report in this space
Camera-normalised0 to 1Within the full camera frame. Used by Neuro Studio and by regions passed to runRoi()

The region builders used by cascades accept NN-normalised input and convert to camera-normalised using the crop live at the time of the call. They are called immediately after the pass that produced the coordinates.

Aspect of normalised units

The sensor is 4:3, so a rectangle with equal width and height in per-axis normalised units is not square. The core's region functions convert to isotropic pixel space, operate there, and convert back. Region arithmetic written in normalised units without this conversion produces a crop stretched by one third, and a landmark model given such a crop returns incorrect output.

Downscaler ratio

The hardware downscaler manages a ratio of about 8x. When the frame to input ratio exceeds this, the pipe decimates first, dropping pixels rather than averaging them. XGA to 256 is a 4x ratio and gives the best detection quality. A centre crop reduces the ratio at high resolutions.