AI2D 应用指南#

概述#

AI2D 提供了使用硬件处理的5种预处理方法,包括 Crop/Shift/Resize/Pad/Affine 。 比如其中的 PadResize 可以实现目标检测任务中常用的 letterbox 操作。AI2D 运行时主要在编写开发板部署代码时使用,提供的C++版本的API见文档:AI2D运行时API手册。下文给出的示例源码位于 src/rtsmart/examples/usage_ai2d 目录下,执行 build_app.sh 即可进行编译,编译生成物在 k230_bin 目录下,将生成物拷贝到开发板上即可运行。请注意 AI2D 的使用注意事项。

注意:

1、Affine和Resize功能是互斥的,不能同时开启; 2、Shift功能的输入格式只能是Raw16; 3、Pad value是按通道配置的,对应的list元素个数要与channel数相等; 4、当前版本中,当只需要AI2D的一个功能时,其他参数也需要配置,flag置为false即可,其他字段不用配置; 5、当配置了多个功能时,执行顺序是Crop->Shift->Resize/Affine->Pad, 配置参数时注意要匹配。

预处理方法#

Resize 方法#

Resize 方法是一种在图片预处理中广泛使用的操作,它主要用于改变图像的尺寸大小。无论是放大还是缩小图像,都可以通过这个方法来实现。源码位于 src/rtsmart/examples/usage_ai2d/test_resize 目录下。实现Resize 的流程如下:

graph TD; ReadData("读取数据
(from pictures/camera)") -->SetInput("初始化AI2D输入tensor")-->SetOutput("根据预处理后的shape
初始化AI2D输出tensor")-->SetParam("配置Resize参数
ai2d_resize_param_t")-->InitBuilder("构造ai2d_builder实例
执行build_schedule")-->Run("调用invoke接口运行配置的预处理方法")-->GetOutput("从配置的AI2D输出tensor处获取输出数据");

这里给出使用 AI2D 实现 Resize 过程的示例代码,实现将读入的图片resize640*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]);

    // 读入图片,并将数据处理成CHW和RGB格式
    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());
    }

    // 创建AI2D输入tensor,并将CHW_RGB数据拷贝到tensor中,并回写到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参数
    int out_w=640;
    int out_h=320;
    int size=out_w*out_h;

    // 创建AI2D输出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");

    // 设置AI2D参数,AI2D支持5种预处理方法,crop/shift/pad/resize/affine。这里开启resize
    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}};

    // 构造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();
    // 执行ai2d,实现从ai2d_in_tensor->ai2d_out_tensor的预处理过程
    builder.invoke(ai2d_in_tensor,ai2d_out_tensor).expect("error occurred in ai2d running");

    //获取处理结果,并将结果存成图片
    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;
}

编译后在开发板上运行:

./test_resize.elf test.jpg 2

执行后原图和预处理后图像的对比图如下:

resize_res

Crop 方法#

Crop 方法是一种用于从原始图像中提取(裁剪)出感兴趣区域(ROI,Region of Interest)的操作。它可以根据指定的坐标和尺寸,从图像中选取一部分作为新的图像。源码位于 src/rtsmart/examples/usage_ai2d/test_crop 。实现 Crop 的流程如下:

graph TD; ReadData("读取数据
(from pictures/camera)") -->SetInput("初始化AI2D输入tensor")-->SetOutput("根据预处理后的shape
初始化AI2D输出tensor")-->SetParam("配置Crop参数
ai2d_crop_param_t")-->InitBuilder("构造ai2d_builder实例
执行build_schedule")-->Run("调用invoke接口运行配置的预处理方法")-->GetOutput("从配置的AI2D输出tensor处获取输出数据");

这里给出使用 AI2D 实现 Crop 过程的示例代码,实现将读入的图片在[10,10]位置裁剪[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]);

    // 读入图片,并将数据处理成CHW和RGB格式
    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());
    }

    // 创建AI2D输入tensor,并将CHW_RGB数据拷贝到tensor中,并回写到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参数
    int crop_x=10;
    int crop_y=10;
    int crop_w=400;
    int crop_h=400;

    // 创建AI2D输出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");

    // 设置AI2D参数,AI2D支持5种预处理方法,crop/shift/pad/resize/affine。这里开启crop
    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}};

    // 构造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();
    // 执行ai2d,实现从ai2d_in_tensor->ai2d_out_tensor的预处理过程
    builder.invoke(ai2d_in_tensor,ai2d_out_tensor).expect("error occurred in ai2d running");

    //获取处理结果,并将结果存成图片
    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;
}

编译后在开发板上运行:

./test_crop.elf test.jpg 2

执行后原图和预处理后图像的对比图如下:

crop_res

Pad 方法#

Pad(填充)方法是一种在图片预处理阶段,对图像边缘进行填充操作的技术。它通过在图像的四周(上下左右)添加像素值,来改变图像的尺寸大小。这些添加的像素值可以自定义。源码位于 src/rtsmart/examples/usage_ai2d/test_pad 。实现 Pad 的流程如下:

graph TD; ReadData("读取数据
(from pictures/camera)") -->SetInput("初始化AI2D输入tensor")-->SetOutput("根据预处理后的shape
初始化AI2D输出tensor")-->SetParam("配置Pad参数
ai2d_pad_param_t")-->InitBuilder("构造ai2d_builder实例
执行build_schedule")-->Run("调用invoke接口运行配置的预处理方法")-->GetOutput("从配置的AI2D输出tensor处获取输出数据");

这里给出使用 AI2D 实现 Pad 过程的示例代码,实现将读入的图片在上下左右分别填充100、100、200、200像素的图像。

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]);

    // 读入图片,并将数据处理成CHW和RGB格式
    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());
    }

    // 创建AI2D输入tensor,并将CHW_RGB数据拷贝到tensor中,并回写到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参数
    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);

    // 创建AI2D输出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");

    // 设置AI2D参数,AI2D支持5种预处理方法,crop/shift/pad/resize/affine。这里开启pad
    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}};

    // 构造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();
    // 执行ai2d,实现从ai2d_in_tensor->ai2d_out_tensor的预处理过程
    builder.invoke(ai2d_in_tensor,ai2d_out_tensor).expect("error occurred in ai2d running");

    //获取处理结果,并将结果存成图片
    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;
}

编译后在开发板上运行:

./test_pad.elf test.jpg 2

执行后原图和预处理后图像的对比图如下:

pad_res

Affine 方法#

Affine(仿射变换)方法是一种在图像预处理中用于对图像进行几何变换的技术。它可以实现图像的旋转、平移、缩放等多种几何变换操作,并且能够保持图像的 “平直性”(即直线在变换后仍然是直线)和 “平行性”(即平行的线在变换后仍然平行)。实现 Affine 的流程如下:

graph TD; ReadData("读取数据
(from pictures/camera)") -->SetInput("初始化AI2D输入tensor")-->SetOutput("根据预处理后的shape
初始化AI2D输出tensor")-->SetParam("配置Affine参数
ai2d_affine_param_t")-->InitBuilder("构造ai2d_builder实例
执行build_schedule")-->Run("调用invoke接口运行配置的预处理方法")-->GetOutput("从配置的AI2D输出tensor处获取输出数据");

这里给出使用 AI2D 实现 Affine 过程的示例代码,实现将读入的图片缩放0.5倍,并分别在x,y方向平移200像素的图像。

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]);

    // 读入图片,并将数据处理成CHW和RGB格式
    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());
    }

    // 创建AI2D输入tensor,并将CHW_RGB数据拷贝到tensor中,并回写到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参数,创建仿射变换矩阵,缩放0.5倍,X/Y方向各平移200px
    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;

    // 创建AI2D输出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");

    // 设置AI2D参数,AI2D支持5种预处理方法,crop/shift/pad/resize/affine。这里开启affine
    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};

    // 构造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();
    // 执行ai2d,实现从ai2d_in_tensor->ai2d_out_tensor的预处理过程
    builder.invoke(ai2d_in_tensor,ai2d_out_tensor).expect("error occurred in ai2d running");

    //获取处理结果,并将结果存成图片
    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;
}

编译后在开发板上运行:

./test_affine.elf test.jpg 2

执行后原图和预处理后图像的对比图如下:

affine_res

Shift 方法#

Shift 方法是数据预处理中比特位右移的方法,每右移一位原数据变为原来的1/2。需要注意的是 Shift 的输入数据格式必须为 RAW16 。 实现 Affine 的流程如下:

graph TD; ReadData("读取数据
(from pictures/camera)") -->SetInput("初始化AI2D输入tensor")-->SetOutput("根据预处理后的shape
初始化AI2D输出tensor")-->SetParam("配置Shift参数
ai2d_shift_param_t")-->InitBuilder("构造ai2d_builder实例
执行build_schedule")-->Run("调用invoke接口运行配置的预处理方法")-->GetOutput("从配置的AI2D输出tensor处获取输出数据");

这里给出使用 AI2D 实现 Shift 过程的示例代码,这里创建了一个全为240的数据,通过 Shift 右移一位,将所有的数据变成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]);

    // 创建一张位深为16的原始数据,初始化为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;
    
    // 创建AI2D输入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;
    // 创建AI2D输出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");

    // 设置AI2D参数,AI2D支持5种预处理方法,crop/shift/pad/resize/affine。这里开启shift,右移1位,数据变为原来的1/2
    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}};

    // 构造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();
    // 执行ai2d,实现从ai2d_in_tensor->ai2d_out_tensor的预处理过程
    builder.invoke(ai2d_in_tensor,ai2d_out_tensor).expect("error occurred in ai2d running");

    //获取处理结果,并将结果存成图片
    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;
}

编译后在开发板上运行:

./test_shift.elf 2

执行后原图和预处理后图像的对比图如下:

shift_res