首页 > 其他分享 >边缘设备使用记录--阿加犀AIBox 6490(realsense+yolox部署)

边缘设备使用记录--阿加犀AIBox 6490(realsense+yolox部署)

时间:2024-07-24 15:53:37浏览次数:18  
标签:std 6490 img cast -- AIBox color objects cv

边缘设备使用记录--阿加犀AIBox 6490:realsense+yolox部署

前言

由于6490这个板子是有type-c接口的,所以这里准备用Realsense+YOLOx来先简单做一个实时的目标检测的东西出来,这里也用到上一篇文章所提到的Aidlite SDK,通过这个SDK在板子上可以很方便的部署YOLOx模型

具体的代码我放在realtime_detection中了,目前测试下来来看,我把相机的采集频率设置为15Hz,平均每帧推理的耗费时间在20ms左右,理论上可以实现实时的需求。

在这里插入图片描述

Realsense SDK + ROS

这里的具体的安装要参考realsense-ros切记要把SDK的版本和你ROS启动程序的版本对应上,比如我这里用的是ROS1版本的节点,对应的SDK就应该是v2.50.0

  • 这里有个问题,就是我安装好之后启动节点图像是没什么问题的,但是再启动IMU的话就会一直报错。。后来我去另一个电脑下也试了一下,好像IMU模块坏了。。但是reaslsense-viewer打开视图又是能看到的,所以不清楚现在具体是什么问题,不过因为不影响图像的使用,所以这里就先没管

然后这里的ROS还是推荐用鱼香ROS,一键安装,这里还遇到了OpenCV版本冲突的原因,因为板子里自己带个4.9.0,不过我这里因为不会用到4.9.0,所以最后就直接把4.9.0覆盖掉了,后边就不会再有警告了

YOLOx部署

关于这个SDK的一些接口上篇文章写过了,所以这里主要讲一下YOLO部署实际遇到的一些问题

预处理

这里的resize就是之前说的那个思路,挑选scale比较小的一边,然后resize到规定的大小

scale_ = std::min((float)resolution_ / img.cols, (float)resolution_ / img.rows);
ROS_INFO_STREAM("scale: " << scale_);
cv::Size scale_size = cv::Size(img.cols * scale_, img.rows * scale_);
cv::resize(dst_img, dst_img, scale_size, 0, 0, cv::INTER_CUBIC);

然后这里要记得先检查下图像的RGB顺序和通道,不然最后提取是会出错的!我一开始就是这里搞错了,所以提取出来的结果一直很抽象。。

dst_img.convertTo(input_data, CV_32FC3);

后处理

后处理的部分我是参考了autoware,大体的一个思路可以参考我之前的文章autoware.universe源码略读(3.4)–perception:tensorrt_yolox,总体流程就是先提取框框,然后根据置信度排序,然后再做一下nms的步骤就好了,思路还是挺简单的

void YoloX::postProcess(
      float * prob, ObjectArray & objects, float scale, cv::Size & img_size) const
{
    ObjectArray proposals;

    std::vector<int> strides = {8, 16, 32};
    std::vector<GridAndStride> grid_strides;
    generateGridsAndStride(resolution_, resolution_, strides, grid_strides);
    generateYoloxProposals(grid_strides, prob, score_threshold_, proposals);

    qsortDescentInplace(proposals);

    std::vector<int> picked;
    nmsSortedBboxes(proposals, picked, nms_threshold_);

    int count = static_cast<int>(picked.size());
    objects.resize(count);
    for (int i = 0; i < count; i++) {
        objects[i] = proposals[picked[i]];

        // adjust offset to original unpadded
        float x0 = (objects[i].x_offset) / scale;
        float y0 = (objects[i].y_offset) / scale;
        float x1 = (objects[i].x_offset + objects[i].width) / scale;
        float y1 = (objects[i].y_offset + objects[i].height) / scale;

        // clip
        x0 = std::clamp(x0, 0.f, static_cast<float>(img_size.width - 1));
        y0 = std::clamp(y0, 0.f, static_cast<float>(img_size.height - 1));
        x1 = std::clamp(x1, 0.f, static_cast<float>(img_size.width - 1));
        y1 = std::clamp(y1, 0.f, static_cast<float>(img_size.height - 1));

        objects[i].x_offset = x0;
        objects[i].y_offset = y0;
        objects[i].width = x1 - x0;
        objects[i].height = y1 - y0;
    }
}

可视化

因为前面得到的其实是检测到的物体对应到的框,所以这里可以再加一点可视化的东西,把物体种类和概率显示在旁边,当然这里其实还是在cv::rectangle,不过这里是把小框放在大框的角落上

cv::Mat Visualization::drawObjects(const cv::Mat &in, const ObjectArray &objects)
{
    if (objects.empty())
    {
        ROS_WARN_STREAM("Cannot detect any object!");
    }

    cv::Mat output_img = in;

    for (const auto & object : objects) {
        // color
        float* color_f = _COLORS[object.type];
        std::vector<int> color = { static_cast<int>(color_f[0] * 255), static_cast<int>(color_f[1] * 255), static_cast<int>(color_f[2] * 255) };

        // text
        std::string text = label_map_[object.type] + ":" + std::to_string(object.score * 100) + "%";
        cv::Scalar txt_color = ((color_f[0] + color_f[1] + color_f[2]) > 0.5) ? cv::Scalar(0, 0, 0) : cv::Scalar(255, 255, 255);
        int font = cv::FONT_HERSHEY_SIMPLEX;
        int baseline = 0;
        cv::Size txt_size = cv::getTextSize(text, font, 0.4, 1, &baseline);
        
        const auto left = object.x_offset;
        const auto top = object.y_offset;
        const auto right = std::clamp(left + object.width, 0, output_img.cols);
        const auto bottom = std::clamp(top + object.height, 0, output_img.rows);
        cv::rectangle(
        output_img, cv::Point(left, top), cv::Point(right, bottom), cv::Scalar(0, 0, 255), 3, 8, 0);

        // text bg
        std::vector<int> txt_bk_color = { static_cast<int>(color_f[0] * 255 * 0.7), static_cast<int>(color_f[1] * 255 * 0.7), static_cast<int>(color_f[2] * 255 * 0.7) };
        cv::rectangle(
            output_img,
            cv::Point(left, top + 1),
            cv::Point(left + txt_size.width + 1, top + int(1.5 * txt_size.height)),
            cv::Scalar(txt_bk_color[0], txt_bk_color[1], txt_bk_color[2]),
            -1
        );

        cv::putText(output_img, text, cv::Point(left, top + txt_size.height), font, 0.4, txt_color, 1);
    }

    return output_img;
}

最后实现的效果大概是这样
在这里插入图片描述

ROS节点

ROS节点的话这里还是选择以图像的形式把检测结果发布出去了,所以用ROS带的image_transport就好,现在的逻辑每太处理好等待消息,以及等有人订阅的时候再启动节点这些细节,后边争取再完善一下吧

image_transport::ImageTransport it(n);
pub_img = it.advertise("/detection_res", 10);
// process里
sensor_msgs::ImagePtr msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", output_img).toImageMsg();
pub_img.publish(msg);

总结

到此为止,就实现了一个简单的实时检测的库,其实代码本身不是很难,主要是里面的一些设计细节要考虑得周全一些,以及遇到问题的时还是要耐心来调试

标签:std,6490,img,cast,--,AIBox,color,objects,cv
From: https://blog.csdn.net/weixin_45432823/article/details/140662655

相关文章

  • PyTorch可以用来干嘛?
    PyTorch是一个广泛使用的开源机器学习库,由FacebookAIResearch(FAIR)开发。它主要用于计算机视觉和自然语言处理等深度学习领域,但也可以应用于许多其他类型的机器学习任务。PyTorch提供了丰富的功能和灵活的设计,使得构建和训练神经网络变得相对简单。以下是PyTorch的一些主要......
  • NAS机友必知: 一个命令轻松搞定DockerHub被墙问题!
    最近因“不可控”之理由, DockerHub算是被全面封杀了,以前还只是污染了Web网站,现在连直接使用dockerpull都不能正常拉镜像了。如下,拉镜像一直卡在pulling阶段,重试数次后就会直接失败:这对于玩NAS的朋友来说是不可接受的(对于开发者来说简直是灾难,端午节没法过了),没了 Docker,NAS的可......
  • 02-Scala基础
    2.1.类型系统2.2.控制结构与函数2.2.1.条件表达式if/else语句可以返回一个值,但不用写return关键字objectCH_0201_ConditionalExpression{defmain(args:Array[String]):Unit={//if/else语句可以返回一个值,但不用写return关键字valx=10valv......
  • Solution - Atcoder Xmas2019E Sum of f(n)
    考虑\(F(n)=\sum\limits_{i=1}^nf_i=\sum\limits_{i=1}^n\sum\limits_{p\in\mathbb{P},k\ge1}[p^k|i]=\sum\limits_{p\in\mathbb{P},k\ge1}\lfloor\frac{n}{p^k}\rfloor\)。对于这个\(\lfloor\frac{n}{x}\rfloor\),一个比较经典的想法就是考虑对其......
  • nvm管理npm安装
    要在Ubuntu上安装最新版本的npm和Node.js,建议使用NodeVersionManager(nvm)。nvm可以帮助你管理和切换不同版本的Node.js和npm。以下是详细步骤:1.安装nvm首先,下载并安装nvm:curl-o-https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh|bash......
  • 题解:2024牛客多校第三场 B
    BCrashTestheader时间限制:C/C++2秒,其他语言4秒空间限制:C/C++1048576K,其他语言2097152K64bitIOFormat:%lld题目描述Afterfiveyears,themosthigh-profileeventinmotorracing,Formula1,returnstoChina.TheChineseGrandPrixwasrecentlyheldatthe......
  • iOS开发_IQKeyboardManager的启用/禁用
    在某个界面完全禁用IQKeyboard-(void)viewWillAppear:(BOOL)animated{ [superviewWillAppear:animated]; //页面appear禁用 [IQKeyboardManagersharedManager].enable=NO;}-(void)viewWillDisappear:(BOOL)animated{ [superviewWillDisappear:animated];......
  • 比较Python中的字符串统一特殊字符
    也许我可以使用更好的英语,但我想要的是忽略单词中的重音(和类似的),所以:renè、rené、rene'和rene应该是相同的,所以应该mañana和manana或even-distribuited和evendistribuited,可能还有sho......
  • 智慧油气合集 | 图扑数字孪生实现全生命周期管理
    石油和天然气在当今社会中扮演着不可替代的角色,虽然面临着环保和资源可持续性的挑战,但在现阶段仍然是全球能源体系中的核心组成部分。石油和天然气行业一直是技术创新的驱动者,带动了勘探、开采、处理和运输等方面的技术进步。效果展示图扑软件运用自主研发HTforWeb产品,打造......
  • 达梦dmp导出导入命令包含特殊字符例子(以密码包含#为例)
    1WINDOWS导出导入1.1导出达梦客户端目录\dexp.exeuserid=TEST/\"TEST#12345678\"@10.10.100.100:5237DIRECTORY=D:\1FILE=dm_exp_test_10.dmpCOMPRESS=YLOG=dm_exp_test_10.log1.2导入--TABLE_EXISTS_ACTION=TRUNCATE对dimp不生效,如果需要truncate表数据后导入,自行......