有关算能SE7盒子适配yolov5的相关问题


1.转模型问题

官方文档
算能的SE7盒子芯片支持bm1684x,所以我转模型时选择了前后处理放到模型里的方式。

转模型的步骤安装文档一步一步来即可,但是有几点需要注意

  1. –output_names 的值是按照自己的onnx模型的结构确定的。其实就是自己onnx的三个输出的名字。
    在这里插入图片描述
    2.生成后的 yolov5s.mlir 文件最后被插入了一个 top.YoloDetection, 如下:在这里插入图片描述
    一定要修改class_num 的值为自己训练的模型的分类数,一定要修改锚框为自己训练时使用的锚框。其他的值可以默认。
    3.batch_size的问题当选择batch=1时[1,3,640 640],不会出什么怪问题,但当batch=4时[4,3,640,640],模型的输出结构就会发生变化。
    当batch=4时,模型输出的结果是先把这4张图的检测出来的结果依次输出,其次再输出无关值,如图
    在这里插入图片描述
    我打印了输出内存中的前100个数,因为步长为7,所以7个一组代表一个框,以0-6为例:0得值为第几张图,1的值为分类数 ,2的值为置信度,3-6的值为框的信息。从图中可以看出,输出结果是先把4张图的框的信息先输出了。

2.环境问题

算能的SE7盒子是自带运行环境的,主要就是libsophon 、 sophon-ffmpeg、 sophon-opencv这三个库,但是不能编译,想要编译需要自己搭建。SE7盒子自带容器,可以从官方拉取镜像也可以基础镜像自己安装,这里不再赘述。

3.前后处理

前处理:

float img_w = img.cols;

  float img_h = img.rows;
  float input_h = model_size_[3];
  float input_w = model_size_[2];
  float img_scale = img_w < img_h ? (input_h / img_h) : (input_w / img_w);
  int new_w = std::floor(img_w * img_scale);
  int new_h = std::floor(img_h * img_scale);
//  std::cout << img_w << " " << img_h << " " << input_w<< " " << input_h <<" "<< new_w<<" "<<new_h<<"\n"; // 1920 1080 0.333333 640360

  cv::Mat resize_img;
  cv::resize(img, resize_img, cv::Size(new_w, new_h), cv::INTER_LINEAR);


  resize_img.convertTo(resize_img, CV_32FC3);

  cv::Mat net_input_data_rgba(input_h, input_w, CV_32FC3, cv::Scalar(114.0f, 114.0f, 114.0f));

  resize_img.copyTo(net_input_data_rgba( //  自动进行 type 的转化
      cv::Range((static_cast<float>(input_h) - new_h) / 2, (static_cast<float>(input_h) - new_h) / 2 + new_h),
      cv::Range((static_cast<float>(input_w) - new_w) / 2, (static_cast<float>(input_w) - new_w) / 2 + new_w)));

  //net_input_data_rgba /= 255.0;
  net_input_data_rgba.convertTo(net_input_data_rgba,CV_8UC3);

  cv::cvtColor(net_input_data_rgba, net_input_data_rgba, cv::COLOR_BGR2RGB);

  std::vector<cv::Mat> sample_split;

  cv::split(net_input_data_rgba, sample_split);
  int offset = 0;
  int channel_offset = input_h * input_w;

  // 加锁
  // std::lock_guard<std::mutex> lock(mtx);

   std::vector<uchar> v(channel_offset*3);
  for (auto part : sample_split)
  {

     memcpy(v.data() + offset, part.data, channel_offset);

    offset += channel_offset;
  }
           
      
  memcpy(pre+channel_offset*3*i, v.data(), channel_offset*3);

后处理:

const float *net_output = output;

  //int MAX_NUM_BOX = 200;
  //int step = 7;
  auto range_0_1 = [](float num) { return std::max(.0f, std::min(1.0f, num)); };
  // std::vector<float> result_nms(step * MAX_NUM_BOX, 0);
  // memcpy(result_nms.data(), net_output, step * MAX_NUM_BOX * sizeof(float));
  // cnstream::CNDataFramePtr frame = package->collection.Get<cnstream::CNDataFramePtr>(cnstream::kCNDataFrameTag);
  const int img_w = img.cols;
  const int img_h = img.rows;
  const float model_input_w = model_size_[2];
  const float model_input_h = model_size_[3];

  float scaling_factors = std::min(1.0 * model_input_w / img_w, 1.0 * model_input_h / img_h);

  int scaled_w = scaling_factors * img_w;
  int scaled_h = scaling_factors * img_h;

   int box_step = 7;
for (int box_idx = 0; box_idx < 200; ++box_idx) {
   if(net_output[box_idx * box_step+2]==0)
     continue;

   float right = net_output[box_idx * box_step + 5];
   float bottom = net_output[box_idx * box_step + 6];
   float left = net_output[box_idx * box_step + 3]-right/2;
   float top = net_output[box_idx * box_step + 4]-bottom/2;
   right=right+left;
   bottom=top+bottom;

   // rectify
   left = (left - (model_input_w - scaled_w) / 2) / scaled_w;
   right = (right - (model_input_w - scaled_w) / 2) / scaled_w;
   top = (top - (model_input_h - scaled_h) / 2) / scaled_h;
   bottom = (bottom - (model_input_h - scaled_h) / 2) / scaled_h;
   left = range_0_1(left);
   right = range_0_1(right);
   top = range_0_1(top);
   bottom = range_0_1(bottom);

    auto obj = std::make_shared<CNInferObject>();
    int id_ = static_cast<int>(net_output[ box_idx * box_step + 1]);
    obj->id = std::to_string(id_);
    obj->score = net_output[ box_idx * box_step + 2];

        if(threshold.size()>id_)
    {
      if (obj->score<threshold[id_])
        continue;
    }
    else
    {
      if(obj->score<*std::min_element(std::begin(threshold), std::end(threshold)))
        continue;
    }

    int re_lo_fa = 0;
    obj->bbox.x = left;
    obj->bbox.y = top;
    obj->bbox.w = std::min(1.0f - obj->bbox.x, right - left);
    obj->bbox.h = std::min(1.0f - obj->bbox.y, bottom - top);
    //转绝对坐标
    obj->bbox.x = max(obj->bbox.x * img.cols,1.0f);
    obj->bbox.y = max(obj->bbox.y * img.rows,1.0f);
    obj->bbox.w = max(obj->bbox.w * img.cols,1.0f);
    obj->bbox.h = max(obj->bbox.h * img.rows,1.0f);
    obj->id_fa_lo = re_lo_fa;
    std::string name = model_name_;
    obj->model_name = name;

前后处理大家主要看逻辑,这是我代码中的一小部分,跑不起来的。

最后画出图来:在这里插入图片描述

总结

这就是我适配SE7yolov5的一些心得,希望能给你带来帮助。一键三连哦~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值