AI2D Application Development Guide#
Overview#
AI2D is a hardware-accelerated image preprocessing module used on the board before inference. It reduces CPU overhead and improves end-to-end runtime performance. AI2D provides five hardware preprocessing capabilities:
CropShiftResizePadAffine
In visual tasks such as object detection, Resize and Pad are often combined to implement a standard letterbox preprocessing flow.
AI2D is mainly used during the deployment stage on the board to speed up preprocessing and improve inference throughput. For the C++ runtime interface details, refer to:
The sample source code is located at:
src/rtsmart/examples/ai/usage_ai2d
Build it in that directory:
./build_app.sh
The generated executables are placed in k230_bin. Copy the build outputs to the board before running the samples.
When using AI2D, note the following:
Note
AffineandResizeare mutually exclusive and cannot be enabled at the same time.
Shiftonly supportsRaw16input format.
Padfill values are configured per channel, so the number of fill values must match the image channel count.Even if you use only one AI2D function, the parameter structures for the other functions still need to be present; just set the corresponding enable flag to
false.When multiple functions are configured together, the execution order is fixed:
Crop -> Shift -> Resize / Affine -> PadMake sure the configuration of each stage stays consistent in terms of shape and data format.
Preprocessing Methods#
Resize Method#
Resize is one of the most commonly used image preprocessing operations. It changes the image size before inference and is widely used in detection and classification tasks.
Source location:
src/rtsmart/examples/ai/usage_ai2d/test_resize
Typical flow:
Read input data.
Initialize the AI2D input tensor.
Initialize the AI2D output tensor according to the target shape.
Configure
ai2d_resize_param_t.Construct
ai2d_builderand callbuild_schedule().Run the configured preprocessing path through
invoke().Read the output tensor data.
The sample resizes an input image to 640 x 320.
Sample code:
int main(int argc, char *argv[])
{
std::cout << "case " << argv[0] << " build " << __DATE__ << " " << __TIME__ << std::endl;
if (argc < 3)
{
std::cerr << "Usage: " << argv[0] << "<image> <debug_mode>" << std::endl;
return -1;
}
int debug_mode = atoi(argv[2]);
// Read image and convert to CHW + RGB format
cv::Mat ori_img = cv::imread(argv[1]);
int ori_w = ori_img.cols;
int ori_h = ori_img.rows;
std::vector<uint8_t> chw_vec;
std::vector<cv::Mat> bgrChannels(3);
cv::split(ori_img, bgrChannels);
for (auto i = 2; i > -1; i--)
{
std::vector<uint8_t> data = std::vector<uint8_t>(bgrChannels[i].reshape(1, 1));
chw_vec.insert(chw_vec.end(), data.begin(), data.end());
}
// Create AI2D input tensor, copy CHW_RGB data into it, and flush to DDR
dims_t ai2d_in_shape{1, 3, ori_h, ori_w};
runtime_tensor ai2d_in_tensor = host_runtime_tensor::create(typecode_t::dt_uint8, ai2d_in_shape, hrt::pool_shared).expect("cannot create input tensor");
auto input_buf = ai2d_in_tensor.impl()->to_host().unwrap()->buffer().as_host().unwrap().map(map_access_::map_write).unwrap().buffer();
memcpy(reinterpret_cast<char *>(input_buf.data()), chw_vec.data(), chw_vec.size());
hrt::sync(ai2d_in_tensor, sync_op_t::sync_write_back, true).expect("write back input failed");
// Resize target dimensions
int out_w = 640;
int out_h = 320;
int size = out_w * out_h;
// Create AI2D output tensor
dims_t ai2d_out_shape{1, 3, out_h, out_w};
runtime_tensor ai2d_out_tensor = host_runtime_tensor::create(typecode_t::dt_uint8, ai2d_out_shape, hrt::pool_shared).expect("cannot create input tensor");
// Configure AI2D parameters. AI2D supports 5 preprocessing methods: crop/shift/pad/resize/affine.
// Here resize is enabled.
ai2d_datatype_t ai2d_dtype{ai2d_format::NCHW_FMT, ai2d_format::NCHW_FMT, ai2d_in_tensor.datatype(), ai2d_out_tensor.datatype()};
ai2d_crop_param_t crop_param{false, 0, 0, 0, 0};
ai2d_shift_param_t shift_param{false, 0};
ai2d_pad_param_t pad_param{false, {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, ai2d_pad_mode::constant, {0, 0, 0}};
ai2d_resize_param_t resize_param{true, ai2d_interp_method::tf_bilinear, ai2d_interp_mode::half_pixel};
ai2d_affine_param_t affine_param{false, ai2d_interp_method::cv2_bilinear, 0, 0, 127, 1, {0.5, 0.1, 0.0, 0.1, 0.5, 0.0}};
// Build AI2D scheduler
ai2d_builder builder(ai2d_in_shape, ai2d_out_shape, ai2d_dtype, crop_param, shift_param, pad_param, resize_param, affine_param);
builder.build_schedule();
// Run AI2D: preprocess from ai2d_in_tensor to ai2d_out_tensor
builder.invoke(ai2d_in_tensor, ai2d_out_tensor).expect("error occurred in ai2d running");
// Retrieve result and save as image
auto output_buf = ai2d_out_tensor.impl()->to_host().unwrap()->buffer().as_host().unwrap().map(map_access_::map_write).unwrap().buffer();
cv::Mat image_r = cv::Mat(out_h, out_w, CV_8UC1, output_buf.data());
cv::Mat image_g = cv::Mat(out_h, out_w, CV_8UC1, output_buf.data() + size);
cv::Mat image_b = cv::Mat(out_h, out_w, CV_8UC1, output_buf.data() + 2 * size);
std::vector<cv::Mat> color_vec(3);
color_vec.clear();
color_vec.push_back(image_b);
color_vec.push_back(image_g);
color_vec.push_back(image_r);
cv::Mat color_img;
cv::merge(color_vec, color_img);
cv::imwrite("test_resize.jpg", color_img);
return 0;
}
Run it on the board:
./test_resize.elf test.jpg 2
Reference result:
Crop Method#
Crop extracts a region of interest (ROI) from the original image according to the specified coordinates and size.
Source location:
src/rtsmart/examples/ai/usage_ai2d/test_crop
Typical flow:
Read input data.
Initialize the AI2D input tensor.
Initialize the AI2D output tensor according to the cropped shape.
Configure
ai2d_crop_param_t.Construct
ai2d_builderand callbuild_schedule().Run the preprocessing path through
invoke().Read the output tensor data.
The reference sample crops a 400 x 400 region starting from [10, 10].
Sample code:
int main(int argc, char *argv[])
{
std::cout << "case " << argv[0] << " build " << __DATE__ << " " << __TIME__ << std::endl;
if (argc < 3)
{
std::cerr << "Usage: " << argv[0] << "<image> <debug_mode>" << std::endl;
return -1;
}
int debug_mode = atoi(argv[2]);
// Read image and convert to CHW + RGB format
cv::Mat ori_img = cv::imread(argv[1]);
int ori_w = ori_img.cols;
int ori_h = ori_img.rows;
std::vector<uint8_t> chw_vec;
std::vector<cv::Mat> bgrChannels(3);
cv::split(ori_img, bgrChannels);
for (auto i = 2; i > -1; i--)
{
std::vector<uint8_t> data = std::vector<uint8_t>(bgrChannels[i].reshape(1, 1));
chw_vec.insert(chw_vec.end(), data.begin(), data.end());
}
// Create AI2D input tensor, copy CHW_RGB data into it, and flush to DDR
dims_t ai2d_in_shape{1, 3, ori_h, ori_w};
runtime_tensor ai2d_in_tensor = host_runtime_tensor::create(typecode_t::dt_uint8, ai2d_in_shape, hrt::pool_shared).expect("cannot create input tensor");
auto input_buf = ai2d_in_tensor.impl()->to_host().unwrap()->buffer().as_host().unwrap().map(map_access_::map_write).unwrap().buffer();
memcpy(reinterpret_cast<char *>(input_buf.data()), chw_vec.data(), chw_vec.size());
hrt::sync(ai2d_in_tensor, sync_op_t::sync_write_back, true).expect("write back input failed");
// Crop parameters
int crop_x = 10;
int crop_y = 10;
int crop_w = 400;
int crop_h = 400;
// Create AI2D output tensor
dims_t ai2d_out_shape{1, 3, crop_h, crop_w};
runtime_tensor ai2d_out_tensor = host_runtime_tensor::create(typecode_t::dt_uint8, ai2d_out_shape, hrt::pool_shared).expect("cannot create input tensor");
// Configure AI2D parameters. Here crop is enabled.
ai2d_datatype_t ai2d_dtype{ai2d_format::NCHW_FMT, ai2d_format::NCHW_FMT, ai2d_in_tensor.datatype(), ai2d_out_tensor.datatype()};
ai2d_crop_param_t crop_param{true, crop_x, crop_y, crop_w, crop_h};
ai2d_shift_param_t shift_param{false, 0};
ai2d_pad_param_t pad_param{false, {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, ai2d_pad_mode::constant, {114, 114, 114}};
ai2d_resize_param_t resize_param{false, ai2d_interp_method::tf_bilinear, ai2d_interp_mode::half_pixel};
ai2d_affine_param_t affine_param{false, ai2d_interp_method::cv2_bilinear, 0, 0, 127, 1, {0.5, 0.1, 0.0, 0.1, 0.5, 0.0}};
// Build AI2D scheduler
ai2d_builder builder(ai2d_in_shape, ai2d_out_shape, ai2d_dtype, crop_param, shift_param, pad_param, resize_param, affine_param);
builder.build_schedule();
// Run AI2D: preprocess from ai2d_in_tensor to ai2d_out_tensor
builder.invoke(ai2d_in_tensor, ai2d_out_tensor).expect("error occurred in ai2d running");
// Retrieve result and save as image
auto output_buf = ai2d_out_tensor.impl()->to_host().unwrap()->buffer().as_host().unwrap().map(map_access_::map_write).unwrap().buffer();
cv::Mat image_r = cv::Mat(crop_h, crop_w, CV_8UC1, output_buf.data());
cv::Mat image_g = cv::Mat(crop_h, crop_w, CV_8UC1, output_buf.data() + crop_h * crop_w);
cv::Mat image_b = cv::Mat(crop_h, crop_w, CV_8UC1, output_buf.data() + 2 * crop_h * crop_w);
std::vector<cv::Mat> color_vec(3);
color_vec.clear();
color_vec.push_back(image_b);
color_vec.push_back(image_g);
color_vec.push_back(image_r);
cv::Mat color_img;
cv::merge(color_vec, color_img);
cv::imwrite("test_crop.jpg", color_img);
return 0;
}
Run it on the board:
./test_crop.elf test.jpg 2
Reference result:
Pad Method#
Pad is an image-border fill operation used during preprocessing. It changes the final image size by adding pixels to the top, bottom, left, and right edges. The fill values can be customized.
Source location:
src/rtsmart/examples/ai/usage_ai2d/test_pad
Typical flow:
Read input data.
Initialize the AI2D input tensor.
Initialize the AI2D output tensor according to the padded shape.
Configure
ai2d_pad_param_t.Construct
ai2d_builderand callbuild_schedule().Run the preprocessing path through
invoke().Read the output tensor data.
The sample pads the image by:
top:
100bottom:
100left:
200right:
200
and uses pad_val = {114, 114, 114}.
Sample code:
int main(int argc, char *argv[])
{
std::cout << "case " << argv[0] << " build " << __DATE__ << " " << __TIME__ << std::endl;
if (argc < 3)
{
std::cerr << "Usage: " << argv[0] << "<image> <debug_mode>" << std::endl;
return -1;
}
int debug_mode = atoi(argv[2]);
// Read image and convert to CHW + RGB format
cv::Mat ori_img = cv::imread(argv[1]);
int ori_w = ori_img.cols;
int ori_h = ori_img.rows;
std::vector<uint8_t> chw_vec;
std::vector<cv::Mat> bgrChannels(3);
cv::split(ori_img, bgrChannels);
for (auto i = 2; i > -1; i--)
{
std::vector<uint8_t> data = std::vector<uint8_t>(bgrChannels[i].reshape(1, 1));
chw_vec.insert(chw_vec.end(), data.begin(), data.end());
}
// Create AI2D input tensor, copy CHW_RGB data into it, and flush to DDR
dims_t ai2d_in_shape{1, 3, ori_h, ori_w};
runtime_tensor ai2d_in_tensor = host_runtime_tensor::create(typecode_t::dt_uint8, ai2d_in_shape, hrt::pool_shared).expect("cannot create input tensor");
auto input_buf = ai2d_in_tensor.impl()->to_host().unwrap()->buffer().as_host().unwrap().map(map_access_::map_write).unwrap().buffer();
memcpy(reinterpret_cast<char *>(input_buf.data()), chw_vec.data(), chw_vec.size());
hrt::sync(ai2d_in_tensor, sync_op_t::sync_write_back, true).expect("write back input failed");
// Padding parameters
int pad_top = 100;
int pad_bottom = 100;
int pad_left = 200;
int pad_right = 200;
std::vector<int> pad_val = {114, 114, 114};
int out_w = ori_w + pad_left + pad_right;
int out_h = ori_h + pad_top + pad_bottom;
int size = out_w * out_h;
// Create AI2D output tensor
dims_t ai2d_out_shape{1, 3, out_h, out_w};
runtime_tensor ai2d_out_tensor = host_runtime_tensor::create(typecode_t::dt_uint8, ai2d_out_shape, hrt::pool_shared).expect("cannot create input tensor");
// Configure AI2D parameters. Here pad is enabled.
ai2d_datatype_t ai2d_dtype{ai2d_format::NCHW_FMT, ai2d_format::NCHW_FMT, ai2d_in_tensor.datatype(), ai2d_out_tensor.datatype()};
ai2d_crop_param_t crop_param{false, 0, 0, 0, 0};
ai2d_shift_param_t shift_param{false, 0};
ai2d_pad_param_t pad_param{true, {{0, 0}, {0, 0}, {pad_top, pad_bottom}, {pad_left, pad_right}}, ai2d_pad_mode::constant, pad_val};
ai2d_resize_param_t resize_param{false, ai2d_interp_method::tf_bilinear, ai2d_interp_mode::half_pixel};
ai2d_affine_param_t affine_param{false, ai2d_interp_method::cv2_bilinear, 0, 0, 127, 1, {0.5, 0.1, 0.0, 0.1, 0.5, 0.0}};
// Build AI2D scheduler
ai2d_builder builder(ai2d_in_shape, ai2d_out_shape, ai2d_dtype, crop_param, shift_param, pad_param, resize_param, affine_param);
builder.build_schedule();
// Run AI2D: preprocess from ai2d_in_tensor to ai2d_out_tensor
builder.invoke(ai2d_in_tensor, ai2d_out_tensor).expect("error occurred in ai2d running");
// Retrieve result and save as image
auto output_buf = ai2d_out_tensor.impl()->to_host().unwrap()->buffer().as_host().unwrap().map(map_access_::map_write).unwrap().buffer();
cv::Mat image_r = cv::Mat(out_h, out_w, CV_8UC1, output_buf.data());
cv::Mat image_g = cv::Mat(out_h, out_w, CV_8UC1, output_buf.data() + size);
cv::Mat image_b = cv::Mat(out_h, out_w, CV_8UC1, output_buf.data() + 2 * size);
std::vector<cv::Mat> color_vec(3);
color_vec.clear();
color_vec.push_back(image_b);
color_vec.push_back(image_g);
color_vec.push_back(image_r);
cv::Mat color_img;
cv::merge(color_vec, color_img);
cv::imwrite("test_pad.jpg", color_img);
return 0;
}
Run it on the board:
./test_pad.elf test.jpg 2
Reference result:
Affine Method#
Affine is a geometric transform used during image preprocessing. It supports operations such as rotation, translation, and scaling, while preserving straight lines and parallelism.
Source location:
src/rtsmart/examples/ai/usage_ai2d/test_affine
Typical flow:
Read input data.
Initialize the AI2D input tensor.
Initialize the AI2D output tensor according to the transformed shape.
Configure
ai2d_affine_param_t.Construct
ai2d_builderand callbuild_schedule().Run the preprocessing path through
invoke().Read the output tensor data.
The reference sample uses an affine matrix that:
scales the image by
0.5translates it by
200pixels in bothxandy
Sample code:
int main(int argc, char *argv[])
{
std::cout << "case " << argv[0] << " build " << __DATE__ << " " << __TIME__ << std::endl;
if (argc < 3)
{
std::cerr << "Usage: " << argv[0] << "<image> <debug_mode>" << std::endl;
return -1;
}
int debug_mode = atoi(argv[2]);
// Read image and convert to CHW + RGB format
cv::Mat ori_img = cv::imread(argv[1]);
int ori_w = ori_img.cols;
int ori_h = ori_img.rows;
std::vector<uint8_t> chw_vec;
std::vector<cv::Mat> bgrChannels(3);
cv::split(ori_img, bgrChannels);
for (auto i = 2; i > -1; i--)
{
std::vector<uint8_t> data = std::vector<uint8_t>(bgrChannels[i].reshape(1, 1));
chw_vec.insert(chw_vec.end(), data.begin(), data.end());
}
// Create AI2D input tensor, copy CHW_RGB data into it, and flush to DDR
dims_t ai2d_in_shape{1, 3, ori_h, ori_w};
runtime_tensor ai2d_in_tensor = host_runtime_tensor::create(typecode_t::dt_uint8, ai2d_in_shape, hrt::pool_shared).expect("cannot create input tensor");
auto input_buf = ai2d_in_tensor.impl()->to_host().unwrap()->buffer().as_host().unwrap().map(map_access_::map_write).unwrap().buffer();
memcpy(reinterpret_cast<char *>(input_buf.data()), chw_vec.data(), chw_vec.size());
hrt::sync(ai2d_in_tensor, sync_op_t::sync_write_back, true).expect("write back input failed");
// Affine transform matrix: scale 0.5x, translate 200px in X and Y
std::vector<float> affine_matrix = {0.5, 0.0, 200.0,
0.0, 0.5, 200.0};
int out_w = (int)(0.5 * ori_w);
int out_h = (int)(0.5 * ori_h);
int size = out_w * out_h;
// Create AI2D output tensor
dims_t ai2d_out_shape{1, 3, out_h, out_w};
runtime_tensor ai2d_out_tensor = host_runtime_tensor::create(typecode_t::dt_uint8, ai2d_out_shape, hrt::pool_shared).expect("cannot create input tensor");
// Configure AI2D parameters. Here affine is enabled.
ai2d_datatype_t ai2d_dtype{ai2d_format::NCHW_FMT, ai2d_format::NCHW_FMT, ai2d_in_tensor.datatype(), ai2d_out_tensor.datatype()};
ai2d_crop_param_t crop_param{false, 0, 0, 0, 0};
ai2d_shift_param_t shift_param{false, 0};
ai2d_pad_param_t pad_param{false, {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, ai2d_pad_mode::constant, {0, 0, 0}};
ai2d_resize_param_t resize_param{false, ai2d_interp_method::tf_bilinear, ai2d_interp_mode::half_pixel};
ai2d_affine_param_t affine_param{true, ai2d_interp_method::cv2_bilinear, 0, 0, 127, 1, affine_matrix};
// Build AI2D scheduler
ai2d_builder builder(ai2d_in_shape, ai2d_out_shape, ai2d_dtype, crop_param, shift_param, pad_param, resize_param, affine_param);
builder.build_schedule();
// Run AI2D: preprocess from ai2d_in_tensor to ai2d_out_tensor
builder.invoke(ai2d_in_tensor, ai2d_out_tensor).expect("error occurred in ai2d running");
// Retrieve result and save as image
auto output_buf = ai2d_out_tensor.impl()->to_host().unwrap()->buffer().as_host().unwrap().map(map_access_::map_write).unwrap().buffer();
cv::Mat image_r = cv::Mat(out_h, out_w, CV_8UC1, output_buf.data());
cv::Mat image_g = cv::Mat(out_h, out_w, CV_8UC1, output_buf.data() + size);
cv::Mat image_b = cv::Mat(out_h, out_w, CV_8UC1, output_buf.data() + 2 * size);
std::vector<cv::Mat> color_vec(3);
color_vec.clear();
color_vec.push_back(image_b);
color_vec.push_back(image_g);
color_vec.push_back(image_r);
cv::Mat color_img;
cv::merge(color_vec, color_img);
cv::imwrite("test_affine.jpg", color_img);
return 0;
}
Run it on the board:
./test_affine.elf test.jpg 2
Reference result:
Shift Method#
Shift performs right-shift preprocessing on the input data. Each one-bit right shift divides the original value by 2. The input format must be RAW16.
Source location:
src/rtsmart/examples/ai/usage_ai2d/test_shift
Typical flow:
Create or read the input data.
Initialize the AI2D input tensor.
Initialize the AI2D output tensor.
Configure
ai2d_shift_param_t.Construct
ai2d_builderand callbuild_schedule().Run the preprocessing path through
invoke().Read the output tensor data.
In the reference sample, a RAW16 image filled with 240 is created, then shifted right by one bit so all values become 120.
Sample code:
int main(int argc, char *argv[])
{
std::cout << "case " << argv[0] << " build " << __DATE__ << " " << __TIME__ << std::endl;
if (argc < 2)
{
std::cerr << "Usage: " << argv[0] << "<debug_mode:0,1,2>" << std::endl;
return -1;
}
int debug_mode = atoi(argv[1]);
// Create a 16-bit raw image initialized to 240
cv::Mat ori_img(320, 320, CV_16UC3, cv::Scalar(240, 240, 240));
cv::imwrite("ori_img.jpg", ori_img);
// HWC, BGR
int ori_w = ori_img.cols;
int ori_h = ori_img.rows;
// Create AI2D input tensor
dims_t ai2d_in_shape{1, ori_h, ori_w, 3};
runtime_tensor ai2d_in_tensor = host_runtime_tensor::create(typecode_t::dt_uint16, ai2d_in_shape, hrt::pool_shared).expect("cannot create input tensor");
auto input_buf = ai2d_in_tensor.impl()->to_host().unwrap()->buffer().as_host().unwrap().map(map_access_::map_write).unwrap().buffer();
memcpy(reinterpret_cast<uint16_t *>(input_buf.data()), ori_img.data, ori_h * ori_w * 3 * sizeof(uint16_t));
hrt::sync(ai2d_in_tensor, sync_op_t::sync_write_back, true).expect("write back input failed");
int out_w = ori_w;
int out_h = ori_h;
// Create AI2D output tensor
dims_t ai2d_out_shape{1, out_h, out_w, 3};
runtime_tensor ai2d_out_tensor = host_runtime_tensor::create(typecode_t::dt_uint16, ai2d_out_shape, hrt::pool_shared).expect("cannot create input tensor");
// Configure AI2D parameters. Here shift is enabled: right-shift by 1 bit halves all values.
ai2d_datatype_t ai2d_dtype{ai2d_format::RAW16, ai2d_format::RAW16, ai2d_in_tensor.datatype(), ai2d_out_tensor.datatype()};
ai2d_crop_param_t crop_param{false, 0, 0, 0, 0};
ai2d_shift_param_t shift_param{true, 1};
ai2d_pad_param_t pad_param{false, {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, ai2d_pad_mode::constant, {0, 0, 0}};
ai2d_resize_param_t resize_param{false, ai2d_interp_method::tf_bilinear, ai2d_interp_mode::half_pixel};
ai2d_affine_param_t affine_param{false, ai2d_interp_method::cv2_bilinear, 0, 0, 127, 1, {0.5, 0.1, 0.0, 0.1, 0.5, 0.0}};
// Build AI2D scheduler
ai2d_builder builder(ai2d_in_shape, ai2d_out_shape, ai2d_dtype, crop_param, shift_param, pad_param, resize_param, affine_param);
builder.build_schedule();
// Run AI2D: preprocess from ai2d_in_tensor to ai2d_out_tensor
builder.invoke(ai2d_in_tensor, ai2d_out_tensor).expect("error occurred in ai2d running");
// Retrieve result and save as image
auto output_buf = ai2d_out_tensor.impl()->to_host().unwrap()->buffer().as_host().unwrap().map(map_access_::map_write).unwrap().buffer();
cv::Mat image_r = cv::Mat(out_h, out_w, CV_16UC3, output_buf.data());
cv::imwrite("test_shift.jpg", image_r);
return 0;
}
Run it on the board:
./test_shift.elf 2
Reference result:
Common AI2D Builder Pattern#
All AI2D samples use the same core pattern:
Read or prepare the input data.
Convert image data to the required layout, typically
CHW + RGB.Create the AI2D input tensor and write the source data to it.
Create the AI2D output tensor based on the target shape.
Configure:
ai2d_datatype_tai2d_crop_param_tai2d_shift_param_tai2d_pad_param_tai2d_resize_param_tai2d_affine_param_t
Construct
ai2d_builder.Call
build_schedule().Call
invoke().Read back the output tensor and inspect or save the result.
This same builder-based pattern is reused in most K230 deployment projects that use AI2D before KPU inference.
