本文参照《NPU开发环境部署参考指南》,介绍了在Ubuntu系统下借助Docker镜像构建PC端模型转换环境的流程,通过容器化方案有效规避了环境依赖冲突。针对awnpu_model_zoo中未收录的模型,建议参考examples目录下的相近案例,自行适配前后处理代码并修正配置文件。若量化导出失败,需尝试裁剪模型结构或调整量化策略。文中所涉yolov26_seg模型已在实际硬件平台完成推理验证。

环境配置
关于参考部署yolox的文章
【端侧部署yolo系列】yolox部署至全志开发板T736
https://blog.csdn.net/troyteng/article/details/155444386?spm=1011.2124.3001.6209

下载 镜像文件和AWNPU_Model_Zoo,创建自己的容器。

模型准备
原始模型下载链接请参见yolo26s-seg.pt。

导出onnx模型
# 下载官方源码

git clone https://github.com/ultralytics/yolov5  # clone
cd yolov5
pip install -r requirements.txt  # install

#进入docker 

sudo docker exec -it {your_docker_name} /bin/bash  #在/bin前面有空格
# 裁剪onnx: 裁剪的部分转换为前处理pre.cpp和后处理post.cpp, 留下output1部分,一共10个输出,如果裁剪reshape_0部分

onnx.utils.extract_model('./yolo26s.onnx', '../yolo26s_6.onnx', ['images'], ['/model.23/Reshape_output_0', '/model.23/Reshape_1_output_0', '/model.23/Reshape_2_output_0', '/model.23/Reshape_3_output_0', '/model.23/Reshape_4_output_0', '/model.23/Reshape_5_output_0']) 
# 如果裁剪Conv_output_0部分:./yolo26s-seg.onnx为裁剪前,../yolo26s-seg_10.onnx为裁剪后命名

onnx.utils.extract_model('./yolo26s-seg.onnx', '../yolo26s-seg_10.onnx', ['images'],['/model.23/one2one_cv2.0/one2one_cv2.0.2/Conv_output_0', '/model.23/one2one_cv3.0/one2one_cv3.0.2/Conv_output_0', '/model.23/one2one_cv4.0/one2one_cv4.0.2/Conv_output_0','/model.23/one2one_cv2.1/one2one_cv2.1.2/Conv_output_0', '/model.23/one2one_cv3.1/one2one_cv3.1.2/Conv_output_0', '/model.23/one2one_cv4.1/one2one_cv4.1.2/Conv_output_0','/model.23/one2one_cv2.2/one2one_cv2.2.2/Conv_output_0', '/model.23/one2one_cv3.2/one2one_cv3.2.2/Conv_output_0', '/model.23/one2one_cv4.2/one2one_cv4.2.2/Conv_output_0', 'output1'])

裁剪之后运行:

python3 onnx_extract.py

固化onnx模型的尺寸,先裁剪后固化:

固化尺寸如果有以下问题:

The operator schemas and or other functionality may change before next ONNX release and in this case ONNX Runtime will not guarantee backward compatibility. Curret for domain ai.onnx is till opset 15.   #问题:onnx版本不对。

在conda环境解决:转换到有环境的虚拟环境下,conda activate yolocd到yolo26_seg/convert_model(和原来一样)的目录:

python3 -m onnxsim yolo26_sim.onnx yolo26s_sim.onnx --overwrite-input-shape 1,3,640,640

裁剪模型裁剪的部分:在python目录下运行

yolo26s-seg网络的后处理部分8bit量化会产生较大的精度损失,通过onnx_extract.py对模型剪枝,修改输出结构,其中ouput0节点为3个输出head后处理解析后的节点;同时将后处理结构移至外部使用cpu进行相应的处理,最终模型输出差异如下,左边是官方模型,右边是修改后的模型

模型配置方面可直接沿用YOLOX的既有部署范式,由于YOLO系列架构在归一化参数、输入预处理逻辑、色彩通道顺序以及量化校准所需的数据集构成上均保持高度统一,因此相关设定无需额外调整。在前后处理环节,yolov26_seg实例分割模型仅相较于常规检测头多出一路用于生成掩码原型的输出张量,其形状通常为[1,32,160,160];针对目标分类与边界框回归的解码流程,开发者完全可复用yolov26s的标准后处理代码。

关于掩码分支的具体操作可简要归纳为:首先提取第五维度中包含的32维掩码特征系数,随后将该系数矩阵与前述原型输出执行矩阵乘法运算,接着施加Sigmoid激活函数以获取二值化概率映射,再将生成的掩码缩放至原始输入图像分辨率并依据检测框坐标进行边界裁剪。

此外,工程目录下的model_config.h头文件建议直接拷贝自官方提供的其他YOLO系列范例(如yolov5、yolov8、yolo11或yolo26)。

前处理代码:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
 
#include "model_config.h"
 
/* model_inputmeta.yml file param modify, eg:
    preproc_node_params:
      add_preproc_node: true
      preproc_type: IMAGE_RGB
*/
 
void get_input_data(const char* image_file, unsigned char* input_data, int letterbox_rows, int letterbox_cols)
{
    cv::Mat sample = cv::imread(image_file, 1);
    if (sample.empty()) {
        fprintf(stderr, "cv::imread %s failed\n", image_file);
        return;
    }
 
    cv::Mat img;
    cv::cvtColor(sample, img, cv::COLOR_BGR2RGB);
 
    /* letterbox process to support different letterbox size */
    float scale_letterbox;
    if ((letterbox_rows * 1.0 / img.rows) < (letterbox_cols * 1.0 / img.cols))
    {
        scale_letterbox = letterbox_rows * 1.0 / img.rows;
    }
    else
    {
        scale_letterbox = letterbox_cols * 1.0 / img.cols;
    }
    int resize_cols = int(scale_letterbox * img.cols);
    int resize_rows = int(scale_letterbox * img.rows);
 
    cv::resize(img, img, cv::Size(resize_cols, resize_rows));
 
    // create a mat with input_data ptr
    cv::Mat img_new(letterbox_rows, letterbox_cols, CV_8UC3, input_data);
 
    int top   = (letterbox_rows - resize_rows) / 2;
    int bot   = (letterbox_rows - resize_rows + 1) / 2;
    int left  = (letterbox_cols - resize_cols) / 2;
    int right = (letterbox_cols - resize_cols + 1) / 2;
 
    // Letterbox filling
    cv::copyMakeBorder(img, img_new, top, bot, left, right, cv::BORDER_CONSTANT, cv::Scalar(114, 114, 114));
}
 
int yolov5_seg_preprocess(const char* imagepath, void* buff_ptr, unsigned int buff_size)
{
    int img_c = 3;
 
    // set default letterbox size
    int letterbox_rows = LETTERBOX_ROWS;
    int letterbox_cols = LETTERBOX_COLS;
    int img_size = letterbox_rows * letterbox_cols * img_c;
 
    unsigned int data_size = img_size * sizeof(uint8_t);
 
    if (data_size > buff_size) {
        printf("data size > buff size, please check code. \n");
        return -1;
    }
 
    get_input_data(imagepath, (unsigned char*)buff_ptr, letterbox_rows, letterbox_cols);
 
    return 0;
}

后处理yolo26_seg_post.cpp

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>
#include <stdio.h>
#include <vector>
#include <cmath>

#include "model_config.h"


using namespace std;


struct Object
{
    cv::Rect_<float> rect;
    int         label;
    float       prob;
    int         gindex;
    cv::Mat     mask;
    std::vector<float> mask_feat;
};


static inline float intersection_area(const Object& a, const Object& b)
{
    cv::Rect_<float> inter = a.rect & b.rect;
    return inter.area();
}

static void qsort_descent_inplace(std::vector<Object>& objects, int left, int right)
{
    int i = left;
    int j = right;
    float p = objects[(left + right) / 2].prob;

    while (i <= j)
    {
        while (objects[i].prob > p)
            i++;

        while (objects[j].prob < p)
            j--;

        if (i <= j)
        {
            std::swap(objects[i], objects[j]);
            i++;
            j--;
        }
    }

#pragma omp parallel sections
    {
#pragma omp section
        {
            if (left < j) qsort_descent_inplace(objects, left, j);
        }
#pragma omp section
        {
            if (i < right) qsort_descent_inplace(objects, i, right);
        }
    }
}

static void qsort_descent_inplace(std::vector<Object>& objects)
{
    if (objects.empty())
        return;
    qsort_descent_inplace(objects, 0, objects.size() - 1);
}

static void nms_sorted_bboxes(const std::vector<Object>& objects, std::vector<int>& picked, float nms_threshold, bool agnostic = false)
{
    picked.clear();
    const int n = objects.size();
    std::vector<float> areas(n);
    for (int i = 0; i < n; i++)
    {
        areas[i] = objects[i].rect.area();
    }

    for (int i = 0; i < n; i++)
    {
        const Object& a = objects[i];
        int keep = 1;
        for (int j = 0; j < (int)picked.size(); j++)
        {
            const Object& b = objects[picked[j]];
            float inter_area = intersection_area(a, b);
            float union_area = areas[i] + areas[picked[j]] - inter_area;
            if (inter_area / union_area > nms_threshold)
                keep = 0;
        }
        if (keep)
            picked.push_back(i);
    }
}

static inline float sigmoid(float x)
{
    return 1.0f / (1.0f + expf(-x));
}

static float softmax(const float* src, float* dst, int length)
{
    float alpha = -FLT_MAX;
    for (int c = 0; c < length; c++)
    {
        float score = src[c];
        if (score > alpha)
            alpha = score;
    }

    float denominator = 0;
    float dis_sum = 0;
    for (int i = 0; i < length; ++i)
    {
        dst[i] = expf(src[i] - alpha);
        denominator += dst[i];
    }
    for (int i = 0; i < length; ++i)
    {
        dst[i] /= denominator;
        dis_sum += i * dst[i];
    }
    return dis_sum;
}

static void generate_proposals_6(int stride, const float* feat_grid, const float* feat_score, const float* feat_mask, float prob_threshold,
                                std::vector<Object>& objects, int letterbox_cols, int letterbox_rows)
{
    const int num_grid_x = letterbox_cols / stride;
    const int num_grid_y = letterbox_rows / stride;
    const int num_grid_size = num_grid_x * num_grid_y;

    const int num_class = CLASS_NUM;
    const int mask_channel = MASK_PROTOS_C;

    cv::Mat out_grid  = cv::Mat(4, num_grid_size, CV_32FC1, (float*)feat_grid);
    cv::Mat out_score = cv::Mat(num_class, num_grid_size, CV_32FC1, (float*)feat_score);
    cv::Mat out_mask  = cv::Mat(mask_channel, num_grid_size, CV_32FC1, (float*)feat_mask);

    cv::transpose(out_grid, out_grid);
    cv::transpose(out_score, out_score);
    cv::transpose(out_mask, out_mask);

    float *feat_mask_ptr = (float*)out_mask.data;

    for (int y = 0; y < num_grid_y; y++)
    {
        for (int x = 0; x < num_grid_x; x++)
        {
            int num_grid_idx = y * num_grid_x + x;

            int label = -1;
            float score = -FLT_MAX;
            {
                const float *pred_score = (float*)out_score.data + num_grid_idx * num_class;
                for (int k = 0; k < num_class; k++)
                {
                    float s = sigmoid(*(pred_score + k));
                    if (s > score)
                    {
                        label = k;
                        score = s;
                    }
                }
            }

            if (score >= prob_threshold)
            {
                const float *pred_grid = (float*)out_grid.data + num_grid_idx * 4;

                float x0 = (x + 0.5f - pred_grid[0]) * stride;
                float y0 = (y + 0.5f - pred_grid[1]) * stride;
                float x1 = (x + 0.5f + pred_grid[2]) * stride;
                float y1 = (y + 0.5f + pred_grid[3]) * stride;

                float width = x1 - x0;
                float height = y1 - y0;

                if (width <= 0 || height <= 0)
                {
                    feat_mask_ptr += mask_channel;
                    continue;
                }

                Object obj;
                obj.rect.x = x0;
                obj.rect.y = y0;
                obj.rect.width = width;
                obj.rect.height = height;
                obj.label = label;
                obj.prob = score;
                obj.gindex = num_grid_idx;

                obj.mask_feat.resize(mask_channel);
                memcpy(obj.mask_feat.data(), feat_mask_ptr, sizeof(float) * mask_channel);

                objects.push_back(obj);
            }
            feat_mask_ptr += mask_channel;
        }
    }
}

int detect_yolo26_seg_10_post(const cv::Mat& bgr, std::vector<Object>& objects, float **output)
{
    std::chrono::steady_clock::time_point Tbegin, Tend;
    Tbegin = std::chrono::steady_clock::now();

    const float *p8_data_0_ptr = output[0];
    const float *p8_data_1_ptr = output[3];
    const float *p8_data_2_ptr = output[6];
    const float *p16_data_0_ptr = output[1];
    const float *p16_data_1_ptr = output[4];
    const float *p16_data_2_ptr = output[7];
    const float *p32_data_0_ptr = output[2];
    const float *p32_data_1_ptr = output[5];
    const float *p32_data_2_ptr = output[8];
    const float *protos_ptr = output[9];

    int img_w = bgr.cols;
    int img_h = bgr.rows;

    int letterbox_rows = LETTERBOX_ROWS;
    int letterbox_cols = LETTERBOX_COLS;

    const float prob_threshold = SCORE_THRESHOLD;
    const float nms_threshold  = NMS_THRESHOLD;
    const float mask_threshold = MASK_THRESHOLD;

    std::vector<Object> proposals;

    generate_proposals_6(8,  p8_data_0_ptr, p8_data_1_ptr, p8_data_2_ptr, 
                         prob_threshold, proposals, letterbox_cols, letterbox_rows);
    generate_proposals_6(16, p16_data_0_ptr, p16_data_1_ptr, p16_data_2_ptr, 
                         prob_threshold, proposals, letterbox_cols, letterbox_rows);
    generate_proposals_6(32, p32_data_0_ptr, p32_data_1_ptr, p32_data_2_ptr, 
                         prob_threshold, proposals, letterbox_cols, letterbox_rows);

    qsort_descent_inplace(proposals);
    std::vector<int> picked;
    nms_sorted_bboxes(proposals, picked, nms_threshold);

    float scale_letterbox = 1.0f;
    if ((letterbox_rows * 1.0 / bgr.rows) < (letterbox_cols * 1.0 / bgr.cols))
        scale_letterbox = letterbox_rows * 1.0 / bgr.rows;
    else
        scale_letterbox = letterbox_cols * 1.0 / bgr.cols;
    
    int resize_cols = int(round(scale_letterbox * bgr.cols));
    int resize_rows = int(round(scale_letterbox * bgr.rows));

    int hpad = (letterbox_rows - resize_rows);
    int wpad = (letterbox_cols - resize_cols);
    int top_pad = hpad / 2;
    int left_pad = wpad / 2;

    float ratio_y = (float)bgr.rows / resize_rows;
    float ratio_x = (float)bgr.cols / resize_cols;

    int mask_proto_dim = MASK_PROTOS_C;
    int mask_stride  = MASK_PROTOS_STRIDE;
    int mask_proto_h = int(letterbox_rows / mask_stride);
    int mask_proto_w = int(letterbox_cols / mask_stride);

    int count = picked.size();
    if (count == 0)
        return 0;

    objects.resize(count);

    for (int i = 0; i < count; i++)
    {
        objects[i] = proposals[picked[i]];

        float x0_orig = (objects[i].rect.x - left_pad) * ratio_x;
        float y0_orig = (objects[i].rect.y - top_pad) * ratio_y;
        float x1_orig = (objects[i].rect.x + objects[i].rect.width - left_pad) * ratio_x;
        float y1_orig = (objects[i].rect.y + objects[i].rect.height - top_pad) * ratio_y;

        x0_orig = std::max(std::min(x0_orig, (float)(img_w - 1)), 0.f);
        y0_orig = std::max(std::min(y0_orig, (float)(img_h - 1)), 0.f);
        x1_orig = std::max(std::min(x1_orig, (float)(img_w - 1)), 0.f);
        y1_orig = std::max(std::min(y1_orig, (float)(img_h - 1)), 0.f);

        objects[i].rect.x = x0_orig;
        objects[i].rect.y = y0_orig;
        objects[i].rect.width = x1_orig - x0_orig;
        objects[i].rect.height = y1_orig - y0_orig;

        if (objects[i].rect.width <= 0)
            objects[i].rect.width = 1.0f;
        if (objects[i].rect.height <= 0)
            objects[i].rect.height = 1.0f;

        float letterbox_x0 = (x0_orig / ratio_x) + left_pad;
        float letterbox_y0 = (y0_orig / ratio_y) + top_pad;
        float letterbox_x1 = (x1_orig / ratio_x) + left_pad;
        float letterbox_y1 = (y1_orig / ratio_y) + top_pad;

        int hstart = std::max(0, (int)(letterbox_y0 / mask_stride));
        int hend = std::min(mask_proto_h, (int)(letterbox_y1 / mask_stride) + 1);
        int wstart = std::max(0, (int)(letterbox_x0 / mask_stride));
        int wend = std::min(mask_proto_w, (int)(letterbox_x1 / mask_stride) + 1);

        int mask_h = hend - hstart;
        int mask_w = wend - wstart;

        cv::Mat mask = cv::Mat(mask_h, mask_w, CV_32FC1);
        
        if (mask_w > 0 && mask_h > 0)
        {
            std::vector<cv::Range> roi_ranges;
            roi_ranges.push_back(cv::Range(0, 1));
            roi_ranges.push_back(cv::Range::all());
            roi_ranges.push_back(cv::Range(hstart, hend));
            roi_ranges.push_back(cv::Range(wstart, wend));

            cv::Mat mask_protos = cv::Mat(mask_proto_dim, mask_proto_h * mask_proto_w, CV_32FC1, (float*)protos_ptr);
            int protos_size[] = {1, mask_proto_dim, mask_proto_h, mask_proto_w};
            cv::Mat mask_protos_reshape = mask_protos.reshape(1, 4, protos_size);
            cv::Mat protos = mask_protos_reshape(roi_ranges).clone().reshape(0, {mask_proto_dim, mask_w * mask_h});
            cv::Mat mask_proposals = cv::Mat(1, mask_proto_dim, CV_32FC1, (float*)objects[i].mask_feat.data());
            cv::Mat masks_feature = (mask_proposals * protos);

            cv::exp(-masks_feature.reshape(1, {mask_h, mask_w}), mask);
            mask = 1.0 / (1.0 + mask);
        }

        int target_w = (int)objects[i].rect.width;
        int target_h = (int)objects[i].rect.height;
        
        if (target_w <= 0) target_w = 1;
        if (target_h <= 0) target_h = 1;

        if (mask.rows > 0 && mask.cols > 0)
        {
            cv::resize(mask, mask, cv::Size(target_w, target_h));
            objects[i].mask = mask > mask_threshold;
        }
        else
        {
            objects[i].mask = cv::Mat::zeros(cv::Size(target_w, target_h), CV_8UC1);
        }
    }

    struct
    {
        bool operator()(const Object& a, const Object& b) const
        {
            return a.rect.area() > b.rect.area();
        }
    } objects_area_greater;
    std::sort(objects.begin(), objects.end(), objects_area_greater);

    Tend = std::chrono::steady_clock::now();
    float f = std::chrono::duration_cast<std::chrono::milliseconds>(Tend - Tbegin).count();

    std::cout << "post process time : " << f << " ms" << std::endl;
    fprintf(stderr, "detection num: %d\n", count);

    return 0;
}

static void draw_objects(const cv::Mat& bgr, const std::vector<Object>& objects, const char *imagepath)
{
    cv::Mat image = bgr.clone();
    cv::Mat mask  = bgr.clone();

    static const cv::Scalar colors[] = {
        cv::Scalar(233, 30, 99), cv::Scalar(156, 39, 176),
        cv::Scalar(103, 58, 183), cv::Scalar(63, 81, 181),
        cv::Scalar(3, 169, 244), cv::Scalar(0, 188, 212),
        cv::Scalar(255, 193, 7), cv::Scalar(255, 152, 0),
        cv::Scalar(255, 87, 34), cv::Scalar(96, 125, 139)
    };

    for (size_t i = 0; i < objects.size(); i++)
    {
        const Object& obj = objects[i];
        const cv::Scalar& color = colors[i % 10];

        if (obj.prob > 1.0) {
            fprintf(stderr, "%2d: %3.0f%%, [%4.0f, %4.0f, %4.0f, %4.0f], score is illegal\n", 
                    obj.label, obj.prob * 100, obj.rect.x, obj.rect.y,
                    obj.rect.x + obj.rect.width, obj.rect.y + obj.rect.height);
            continue;
        }

        fprintf(stderr, "%2d: %3.0f%%, [%4.0f, %4.0f, %4.0f, %4.0f], %s\n", 
                obj.label, obj.prob * 100, obj.rect.x, obj.rect.y,
                obj.rect.x + obj.rect.width, obj.rect.y + obj.rect.height, 
                g_classes_name[obj.label].c_str());

        int roi_x = (int)obj.rect.x;
        int roi_y = (int)obj.rect.y;
        int roi_w = (int)obj.rect.width;
        int roi_h = (int)obj.rect.height;
        
        if (roi_w <= 0) roi_w = 1;
        if (roi_h <= 0) roi_h = 1;
        
        cv::Rect roi(roi_x, roi_y, roi_w, roi_h);
        roi &= cv::Rect(0, 0, mask.cols, mask.rows);
        
        if (roi.width > 0 && roi.height > 0 && !objects[i].mask.empty())
        {
            cv::Mat mask_resized;
            cv::resize(objects[i].mask, mask_resized, cv::Size(roi.width, roi.height), 0, 0, cv::INTER_NEAREST);
            mask(roi).setTo(color, mask_resized);
        }

        cv::rectangle(image, obj.rect, color);

        char text[256];
        sprintf(text, "%s %.1f%%", g_classes_name[obj.label].c_str(), obj.prob * 100);

        int baseLine = 0;
        cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);

        int x = obj.rect.x;
        int y = obj.rect.y - label_size.height - baseLine;
        if (y < 0) y = 0;
        if (x + label_size.width > image.cols) x = image.cols - label_size.width;

        cv::rectangle(image, cv::Rect(cv::Point(x, y), cv::Size(label_size.width, label_size.height + baseLine)),
                      cv::Scalar(255, 255, 255), -1);
        cv::putText(image, text, cv::Point(x, y + label_size.height),
                    cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
    }

    image = 0.5 * mask + 0.5 * image;
    cv::imwrite("out_yolo26_seg.png", image);
}

int yolo26_seg_postprocess(const char *imagepath, float **output)
{
    cv::Mat m = cv::imread(imagepath, 1);
    if (m.empty()) {
        fprintf(stderr, "cv::imread %s failed\n", imagepath);
        return -1;
    }

    std::vector<Object> objects;
    detect_yolo26_seg_10_post(m, objects, output);
    draw_objects(m, objects, imagepath);

    printf("yolo26_seg_postprocess finished.\n");
    return 0;
}


模型转换
后续的一系列和其他模型一样,这里就直接给出转换的命令了,详细的说明可以参考yolox的部署,或者《NPU_模型部署_开发指南》

#导出模型

# using xxx_env.sh to create softlink 生成软连接,避免复用
./convert_model_env.sh

# 导入
# pegasus_import.sh <model_name>
./pegasus_import.sh yolo26s-seg_sim

# 量化
# pegasus_quantize.sh <model_name> <quantize_type> <calibration_set_size>
./pegasus_quantize.sh yolo26s-seg_sim pcq 12

# 仿真(可选)
# pegasus_inference.sh <model_name> <quantize_type>
./pegasus_inference.sh yolo26s-seg_sim pcq

# 导出nb模型
# pegasus_export_ovx_nbg.sh <model_name> <quantize_type> <platform>
./pegasus_export_ovx_nbg.sh yolo26s-seg_sim pcq t736

# 导出的模型文件存放在../model目录
# 例如 ../model/yolo26s-seg_sim_pcq_t736.nb

板端demo

含demo编译及运行说明。

解压opencv压缩包

# 进入目录
cd ../../../3rdparty/opencv/
# 解压,选择对应平台
# armhf, eg: V85x, R853
unzip opencv-3.4.16-gnueabihf-linux.zip
# linux aarch64, eg: T527/MR527/MR536/T536/A733/T736
unzip opencv-4.9.0-aarch64-linux-sunxi-glibc.zip
# android aarch64, eg: T527/A733/T736
unzip opencv-4.9.0-android.zip

准备交叉编译工具链

Linux

# 进入目录
cd ../../0-toolchains/
# 解压
# armhf, V85x, R853
unzip arm-openwrt-linux-muslgnueabi.zip
chmod 777 -R ./arm-openwrt-linux-muslgnueabi
# aarch64, MR527, T527, MR536, T536, A733, T736
tar xvf gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz
# aarch64 for debian11, T527, A733, T736
tar vxf gcc-arm-10.2-2020.11-x86_64-aarch64-none-linux-gnu.tar.xz

编译脚本会根据平台自动选择交叉编译工具链,若需使用其它路径的工具链,可在cmake_toolchain目录修改.cmake文件内容指定对应的交叉编译工具链路径。

编译、推理
这里以在Linux系统下进行编译推理,Android系统参考yolox的部署,这里直接给出命令行,根据自己的平台和系统进行修改就行了。

# 进入yolo26s_seg目录,进行编译

cd ../examples/yolo26s_seg/
./../build_linux.sh -t t736  #在yolo26s_seg的目录运行这段代码

生成文件夹:intall 下面是yolo11_seg_demo_linux_t527, yolo26_seg_demo_linux_t527下有两个文件 yolo26_seg_demo_t527和 model下的测试图片和yolo26s-sim_simple_uint8_t527.nb 文件推送yolo26_seg_demo_linux_t736文件至板端,方式有多种,这里使用adb

首先打开cmd输入:

adb shell

连接上板子之后:创建目录

mkdir -p mnt/UDISK  #外部存储

推送文件:

adb push Z:\docker_data\awnpu_model_zoo\examples\yolo26_seg\install\yolo26_seg_demo_linux_t736 /mnt/UDISK/yolo26_demo_linux_t736  #将 yolo26_seg_demo_linux_t736 放到刚刚创建的存储

cd 到 yolo26_demo_linux_t736目录下运行

# cd到目录

cd  /mnt/UDISK/yolo26_demo_linux_t736/yolo26_seg_demo_linux_t736

#推理
./yolo26_seg_demo_t736 -nb model/yolo26_sim_pcq_t736.nb -i model/dog.jpg

输出结果

post process time : 22 ms
detection num: 3
 1:  85%, [ 127,  133,  568,  417], bicycle
16:  86%, [ 129,  220,  313,  542], dog
 7:  65%, [ 464,   73,  685,  170], truck
yolo26_seg_postprocess finished.
destory npu finished.
~NpuUint.


————————————————
版权声明:本文为CSDN博主的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐