AI2D Application Development Guide#
Overview#
AI2D is a hardware-accelerated image preprocessing module used to complete data processing before inference on the development board, in order to reduce CPU overhead and improve overall performance. AI2D provides 5 hardware-accelerated image preprocessing capabilities, namely Crop / Shift / Resize / Pad / Affine.
In visual tasks such as object detection, a common letterbox preprocessing pipeline can be implemented by combining Resize and Pad.
AI2D is mainly used in the deployment stage on the development board to accelerate the preprocessing process and improve inference speed. Its C++ runtime interface is documented in: AI2D Runtime API Manual
The example source code in this document is located in the directory:
src/rtsmart/examples/ai/usage_ai2d
Run build_app.sh in this directory to complete the compilation; the generated executable is located in the k230_bin directory.
Copy the generated artifacts to the development board to run the example program.
When using AI2D, please be sure to pay attention to the following points.
Note:
AffineandResizeare mutually exclusive, they cannot be enabled at the same time;
Shiftonly supports theRaw16input format;
Padfill values are configured per channel, and the number of list elements must match the number of channels of the input image;In the current version, even if only a single AI2D function is used, the parameters for the other functions still need to be configured, but you only need to set the corresponding
flagtofalse; the other fields can be left blank;When multiple functions are configured simultaneously, the AI2D execution order is fixed as:
Crop → Shift → Resize / Affine → PadPlease ensure that the parameter configurations for each stage are consistent in terms of dimensions, format, etc.
Preprocessing Methods#
Resize Method#
The Resize method is a widely used operation in image preprocessing, primarily used to change the size of an image. Whether enlarging or reducing an image, this method can accomplish it. The source code is located in the src/rtsmart/examples/ai/usage_ai2d/test_resize directory. The process for implementing Resize is as follows:
(from pictures/camera)") -->SetInput("Initialize AI2D input tensor")-->SetOutput("Initialize AI2D output tensor
according to preprocessed shape")-->SetParam("Configure Resize parameters
ai2d_resize_param_t")-->InitBuilder("Construct ai2d_builder instance
execute build_schedule")-->Run("Call invoke interface to run
configured preprocessing method")-->GetOutput("Get output data from
configured AI2D output tensor");
Here is example code that uses AI2D to implement the Resize process, resizing the read image to a resolution of 640*320.
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 process data into CHW and 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 the tensor, and write back 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 parameters
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");
// Set AI2D parameters; AI2D supports 5 preprocessing methods: crop/shift/pad/resize/affine. Enable resize here
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}};
// Construct ai2d_builder
ai2d_builder builder(ai2d_in_shape, ai2d_out_shape, ai2d_dtype, crop_param, shift_param, pad_param, resize_param, affine_param);
builder.build_schedule();
// Execute ai2d to implement the preprocessing process from ai2d_in_tensor->ai2d_out_tensor
builder.invoke(ai2d_in_tensor,ai2d_out_tensor).expect("error occurred in ai2d running");
// Get processing result and save it as an 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;
}
After compilation, run on the development board:
./test_resize.elf test.jpg 2
The comparison between the original image and the preprocessed image after execution is as follows:
Crop Method#
The Crop method is an operation used to extract (crop) a region of interest (ROI) from an original image. It can select a portion of the image as a new image based on specified coordinates and dimensions. The source code is located in src/rtsmart/examples/ai/usage_ai2d/test_crop. The process for implementing Crop is as follows:
(from pictures/camera)") -->SetInput("Initialize AI2D input tensor")-->SetOutput("Initialize AI2D output tensor
according to preprocessed shape")-->SetParam("Configure Crop parameters
ai2d_crop_param_t")-->InitBuilder("Construct ai2d_builder instance
execute build_schedule")-->Run("Call invoke interface to run
configured preprocessing method")-->GetOutput("Get output data from
configured AI2D output tensor");
Here is example code that uses AI2D to implement the Crop process, cropping the read image at position [10,10] to a resolution of [400,400].
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 process data into CHW and 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 the tensor, and write back 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");
// Set AI2D parameters; AI2D supports 5 preprocessing methods: crop/shift/pad/resize/affine. Enable crop here
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}};
// Construct ai2d_builder
ai2d_builder builder(ai2d_in_shape, ai2d_out_shape, ai2d_dtype, crop_param, shift_param, pad_param, resize_param, affine_param);
builder.build_schedule();
// Execute ai2d to implement the preprocessing process from ai2d_in_tensor->ai2d_out_tensor
builder.invoke(ai2d_in_tensor,ai2d_out_tensor).expect("error occurred in ai2d running");
// Get processing result and save it as an 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;
}
After compilation, run on the development board:
./test_crop.elf test.jpg 2
The comparison between the original image and the preprocessed image after execution is as follows:
Pad Method#
The Pad (padding) method is a technique used in the image preprocessing stage to pad the edges of an image. It changes the size of the image by adding pixel values around the image (top, bottom, left, right). These added pixel values can be customized. The source code is located in src/rtsmart/examples/ai/usage_ai2d/test_pad. The process for implementing Pad is as follows:
(from pictures/camera)") -->SetInput("Initialize AI2D input tensor")-->SetOutput("Initialize AI2D output tensor
according to preprocessed shape")-->SetParam("Configure Pad parameters
ai2d_pad_param_t")-->InitBuilder("Construct ai2d_builder instance
execute build_schedule")-->Run("Call invoke interface to run
configured preprocessing method")-->GetOutput("Get output data from
configured AI2D output tensor");
Here is example code that uses AI2D to implement the Pad process, padding the read image with 100, 100, 200, 200 pixels at top, bottom, left, and right respectively.
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 process data into CHW and 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 the tensor, and write back 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=(ori_w+pad_left+pad_right)*(ori_h+pad_top+pad_bottom);
// 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");
// Set AI2D parameters; AI2D supports 5 preprocessing methods: crop/shift/pad/resize/affine. Enable pad here
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}};
// Construct ai2d_builder
ai2d_builder builder(ai2d_in_shape, ai2d_out_shape, ai2d_dtype, crop_param, shift_param, pad_param, resize_param, affine_param);
builder.build_schedule();
// Execute ai2d to implement the preprocessing process from ai2d_in_tensor->ai2d_out_tensor
builder.invoke(ai2d_in_tensor,ai2d_out_tensor).expect("error occurred in ai2d running");
// Get processing result and save it as an 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;
}
After compilation, run on the development board:
./test_pad.elf test.jpg 2
The comparison between the original image and the preprocessed image after execution is as follows:
Affine Method#
The Affine (affine transformation) method is a technique used in image preprocessing to perform geometric transformations on an image. It can implement various geometric transformation operations such as rotation, translation, and scaling of an image, while maintaining the image’s “straightness” (i.e., straight lines remain straight after transformation) and “parallelism” (i.e., parallel lines remain parallel after transformation). The source code is located in src/rtsmart/examples/ai/usage_ai2d/test_affine. The process for implementing Affine is as follows:
(from pictures/camera)") -->SetInput("Initialize AI2D input tensor")-->SetOutput("Initialize AI2D output tensor
according to preprocessed shape")-->SetParam("Configure Affine parameters
ai2d_affine_param_t")-->InitBuilder("Construct ai2d_builder instance
execute build_schedule")-->Run("Call invoke interface to run
configured preprocessing method")-->GetOutput("Get output data from
configured AI2D output tensor");
Here is example code that uses AI2D to implement the Affine process, scaling the read image by 0.5x and translating it by 200 pixels in both the x and y directions.
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 process data into CHW and 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 the tensor, and write back 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 parameters, create affine transformation matrix, scale by 0.5x, translate 200px in X/Y directions
std::vector<float> affine_matrix = {0.5,0.0,200.0,
0.0,0.5,200.0};
int out_w=0.5*ori_w;
int out_h=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");
// Set AI2D parameters; AI2D supports 5 preprocessing methods: crop/shift/pad/resize/affine. Enable affine here
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};
// Construct ai2d_builder
ai2d_builder builder(ai2d_in_shape, ai2d_out_shape, ai2d_dtype, crop_param, shift_param, pad_param, resize_param, affine_param);
builder.build_schedule();
// Execute ai2d to implement the preprocessing process from ai2d_in_tensor->ai2d_out_tensor
builder.invoke(ai2d_in_tensor,ai2d_out_tensor).expect("error occurred in ai2d running");
// Get processing result and save it as an 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;
}
After compilation, run on the development board:
./test_affine.elf test.jpg 2
The comparison between the original image and the preprocessed image after execution is as follows:
Shift Method#
The Shift method is a bitwise right-shift method in data preprocessing; each right shift by one bit makes the original data become 1/2 of its original value. Please note that the input data format for Shift must be RAW16. The source code is located in src/rtsmart/examples/ai/usage_ai2d/test_shift. The process for implementing Affine is as follows:
(from pictures/camera)") -->SetInput("Initialize AI2D input tensor")-->SetOutput("Initialize AI2D output tensor
according to preprocessed shape")-->SetParam("Configure Shift parameters
ai2d_shift_param_t")-->InitBuilder("Construct ai2d_builder instance
execute build_schedule")-->Run("Call invoke interface to run
configured preprocessing method")-->GetOutput("Get output data from
configured AI2D output tensor");
Here is example code that uses AI2D to implement the Shift process; here, data filled entirely with 240 is created, and through a right shift of one bit using Shift, all the data becomes 120.
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 original data with bit depth of 16, 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");
// Set AI2D parameters; AI2D supports 5 preprocessing methods: crop/shift/pad/resize/affine. Enable shift here, right shift by 1 bit, data becomes 1/2 of original
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}};
// Construct ai2d_builder
ai2d_builder builder(ai2d_in_shape, ai2d_out_shape, ai2d_dtype, crop_param, shift_param, pad_param, resize_param, affine_param);
builder.build_schedule();
// Execute ai2d to implement the preprocessing process from ai2d_in_tensor->ai2d_out_tensor
builder.invoke(ai2d_in_tensor,ai2d_out_tensor).expect("error occurred in ai2d running");
// Get processing result and save it as an 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;
}
After compilation, run on the development board:
./test_shift.elf 2
The comparison between the original image and the preprocessed image after execution is as follows:
