基于YOLO11实例分割与奥比中光相机的快递包裹抓取点检测

[复制链接]
发表于 2025-10-2 20:50:31 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本博客泉源于CSDN呆板鱼,未同意任何人转载。
更多内容,接待点击本专栏,检察更多内容。

目次
0 弁言
1 奥比中光相机测试
1.1 SDK相机初体验
1.2 将SDK的Example改成所必要步伐
2 YOLO11S-SEG的onnxruntime推理
3 结语


0 弁言


项目接纳六轴呆板臂搭配末了真空吸盘,从无序包裹中抓取想要的包裹。AI算法必要提供各包裹的抓取点的3D坐标与3D姿态。由于快递包裹含有多个面,且大多为倾斜状态,为了顺遂抓取,我们的算法必要如下几个步调:
①从彩色图的包裹堆内里辨认、分割出每个单独的包裹,得到2D掩码Mask1;
②从对齐的深度图中提取每个包裹Mask1对应的深度掩码Mask2;
③根据相机参数,盘算Mask2对应的三维点云DisMask;
④将DisMask中的非常点云值剔除后做平面分割,只要含点云数目最多的谁人平面;
⑤求平面的质心作为抓取点,求平面的法向量与x、y、z轴的角度为末了抓取姿态。
终极得到6个值返回给下位机做呆板臂的控制。
本次是在windows上举行开发,我用到的软件与SDK有:cmak-3.28.1,vs2019,opencv-4.6.1,open3d-0.18.0,orbbecsdk1.10.18、cuda-11.6、cudnn-8.5.0、onnxruntime-gpu-1.14.0(本来仍然用tensorrt的究竟快,但是我之前已经出过yolov8-seg的tensorrt推理博客了,而yolov11-seg的可以直接用,再写一遍没啥意思,以是改成onnxruntime-gpu举行推理,实测比tensorrt差不到很多,还可以省掉onnx转tensorrt模子的步调,巴适的板。我的PC显卡是3060,yolo11s-seg的推理速率是11ms,而onnxruntime的速率是24ms左右)。
模子用的ultralytics最新版练习的yolo11s-seg,练习好之后转好的onnx模子与练习数据可以在【这里】下载,练习方法网上随处都有,不是此博客的重点。
1 奥比中光相机测试

1.1 SDK相机初体验

从前做这种对精度要求不那么高项目用的都是intel的realsense系列,但代价越来越贵了,加上奥博中光每天网上吹牛批,以是某鱼买了一款二手的GeminiPro相机,是奥比中光与轮趣科技一同研发的。
起首设置奥比中光相机的驱动与SDK,必须要装驱动才气利用,下载所在:所在1。由于我接纳的win11,以是下载的win_x64这个版本。

解压后的目次为D:/Project/OrbbecSDK/(这是我放置的目次),也可以换其他路径存放。有个driver的文件夹,内里的exe无脑安装即可。

安装完成后,打开CMAKE_GUI与VS2019,CMAKE我接纳的版本是3.28.1。起首打开CMakeLists.txt将OpenCV_DIR的路径改成自己的实际路径,关于opencv的安装编译网上有很多,这里就不赘述了。

https://github.com/orbbec/OrbbecSDK/releases然后打开cmakegui按照下列步调设置并天生vs的工程文件,天生好之后打开,末了ALL_BUILD。

 

ALL_BUILD右键天生之后会在bin目次下天生很多exe文件,插上相机、运行color_viewer有画面就代表已经可以精确利用SDK了,下面我们对其举行改写,得到我们想要的步伐。

1.2 将SDK的Example改成所必要步伐

在我的案例中,对于SDK必要有以下几个功能:
①设定参数与初始化相机;②获取彩色图与深度图;③对彩色图与深度图举行对齐;④传入检测得到的box与mask盘算3d点云;⑤点云处理惩罚得到三维抓取点与三维姿态。
起首创建一个camera.h,界说必要的函数,代码如下:
  1. #ifndef CAMERAUTIL_H
  2. #define CAMERAUTIL_H
  3. #include "libobsensor/ObSensor.hpp"
  4. #include "libobsensor/hpp/Pipeline.hpp"
  5. #include <Eigen/Dense>
  6. #include <open3d/Open3D.h>
  7. #include "opencv2/opencv.hpp"
  8. #include <fstream>
  9. #include <iostream>
  10. #include <cmath>
  11. #include <vector>
  12. class Orbbec {
  13. public:
  14.         bool Init(void);//初始化相机
  15.         bool GetRgbAndDepth(cv::Mat& src, cv::Mat& dep);//获取当前帧,并进行深度图与彩色图的对齐
  16.         void GetDistance(int x, int y);//打印提取某个点的x、y、z坐标
  17.         void GetDistance(int box[4], cv::Mat& mask, cv::Mat& dis_mask);//提取某个box中mask对应的所有点的三维点云,并组成dis_mask
  18.         void ProcessPointcloud(cv::Mat& dis_mask, cv::Mat imgcrop, std::vector<float>& result, float *ylength, float *xlength);//对点云进行后处理得到抓取坐标与抓取姿态
  19.         void Postprocess(int box[4], cv::Mat& mask, cv::Mat srcimg, float result[10]);//对提取的dis_mask进行后处理,GetDistance与ProcessPointcloud
  20.         //都是后处理需要用到的函数
  21.         void close(void);
  22. private:
  23.         ob::Pipeline pipe;
  24.         OBCameraParam cameraParam;
  25.         cv::Mat depth;
  26.         float scale;
  27.         ob::Align* align=nullptr;
  28. };
  29. #endif
复制代码
然后新建一个camera.cpp,orbbec的函数举行实现,代码如下:
  1. #include "camera.h"
  2. bool Orbbec::Init(void) {
  3.     // Query the list of connected devices
  4.     // Create a Context.
  5.     ob::Context ctx;
  6.     auto devList = ctx.queryDeviceList();
  7.     // Get the number of connected devices
  8.     if (devList->deviceCount() == 0) {
  9.         std::cerr << "Device not found!" << std::endl;
  10.         return false;
  11.     }
  12.    
  13.     // Configure which streams to enable or disable for the Pipeline by creating a Config
  14.     std::shared_ptr<ob::Config> config = std::make_shared<ob::Config>();
  15.     // Get all stream profiles of the color camera, including stream resolution, frame rate, and frame format
  16.     auto colorProfiles = pipe.getStreamProfileList(OB_SENSOR_COLOR);
  17.     // Get the default color profile
  18.     //auto colorProfile = colorProfiles->getProfile(OB_PROFILE_DEFAULT);
  19.     std::shared_ptr<ob::VideoStreamProfile> colorProfile = nullptr;
  20.     colorProfile = colorProfiles->getVideoStreamProfile(640, 480, OB_FORMAT_RGB, 30);
  21.     config->enableStream(colorProfile);
  22.     // Get all stream profiles of the depth camera, including stream resolution, frame rate, and frame format
  23.     auto depthProfiles = pipe.getStreamProfileList(OB_SENSOR_DEPTH);
  24.     // Get the default depth profile
  25.      //auto depthProfile = depthProfiles->getProfile(OB_PROFILE_DEFAULT);
  26.     std::shared_ptr<ob::VideoStreamProfile> depthProfile = nullptr;
  27.     depthProfile = depthProfiles->getVideoStreamProfile(640, OB_HEIGHT_ANY, OB_FORMAT_Y11, 30);
  28.     config->enableStream(depthProfile);
  29.     // Configure the alignment mode as hardware D2C alignment
  30.     config->setAlignMode(ALIGN_D2C_HW_MODE);
  31.     align = new ob::Align(OB_STREAM_COLOR);
  32.     try {
  33.         pipe.start(config);
  34.         cameraParam = pipe.getCameraParam();
  35.     }
  36.     catch (ob::Error& e) {
  37.         std::cerr << "function:" << e.getName() << "\nargs:" << e.getArgs() << "\nmessage:" << e.getMessage() << "\ntype:" << e.getExceptionType() << std::endl;
  38.         return false;
  39.     }
  40.     return true;
  41. };
  42. bool Orbbec::GetRgbAndDepth(cv::Mat& src, cv::Mat& dep) {
  43.     auto frameset = pipe.waitForFrames(100);
  44.     if (frameset == nullptr || frameset->depthFrame() == nullptr || frameset->colorFrame() == nullptr) {
  45.         return false;
  46.     }
  47.     auto newFrame = align->process(frameset);
  48.     auto newFrameSet = newFrame->as<ob::FrameSet>();
  49.     auto colorFrame = newFrameSet->colorFrame();
  50.     auto depthFrame = newFrameSet->depthFrame();
  51.     uint32_t  width = colorFrame->width();
  52.     uint32_t  height = colorFrame->height();
  53.     cv::Mat rawMat(height, width, CV_8UC3, (uint16_t*)colorFrame->data(), cv::Mat::AUTO_STEP);
  54.     cv::cvtColor(rawMat, src, cv::COLOR_RGB2BGR);
  55.     width = depthFrame->width();
  56.     height = depthFrame->height();
  57.     scale = depthFrame->getValueScale();
  58.     uint16_t* data = (uint16_t*)depthFrame->data();
  59.     cv::Mat depimg(height, width, CV_16U, data, cv::Mat::AUTO_STEP);
  60.     depimg.copyTo(depth);
  61.     // 将深度图转换为8位图像,进行可视化
  62.     cv::Mat depth_image_8bit;
  63.     double minVal, maxVal;
  64.     cv::Point minLoc, maxLoc;
  65.     cv::minMaxLoc(depimg, &minVal, &maxVal, &minLoc, &maxLoc);
  66.     cv::convertScaleAbs(depimg, depth_image_8bit, 255.0 / maxVal);
  67.     cv::applyColorMap(depth_image_8bit, dep, cv::COLORMAP_JET);
  68.     //float centerDistance = data[width * height / 2 + width / 2] * scale;
  69.     return true;
  70. };
  71. void Orbbec::GetDistance(int x,int y) {
  72.     float Z = (float)depth.at<uint16_t>(y,x) * scale;
  73.     float X= (x - cameraParam.depthIntrinsic.cx) * Z / cameraParam.depthIntrinsic.fx;
  74.     float Y= (y - cameraParam.depthIntrinsic.cy) * Z / cameraParam.depthIntrinsic.fy;
  75.     printf("X,Y,Z:%f,%f.%f\n", X, Y, Z);
  76. }
  77. void Orbbec::GetDistance(int box[4], cv::Mat& mask, cv::Mat& dis_mask) {
  78.     for (int i = box[0]; i < box[2]; i++) {
  79.         for (int j = box[1]; j < box[3]; j++) {
  80.             if (mask.at<uchar>(j - box[1], i - box[0]) != 0){
  81.                 float upoint[3];
  82.                 upoint[2] = (float)depth.at<uint16_t>(j, i)* scale/1000.f;//转换成米
  83.                 upoint[0] = (i - cameraParam.depthIntrinsic.cx) * upoint[2] / cameraParam.depthIntrinsic.fx;
  84.                 upoint[1] = (j - cameraParam.depthIntrinsic.cy) * upoint[2] / cameraParam.depthIntrinsic.fy;
  85.                 dis_mask.at<cv::Vec3f>(j - box[1], i - box[0]) = cv::Vec3f(upoint[0], upoint[1], upoint[2]);
  86.                 if (upoint[2] == 0.0f)
  87.                 {
  88.                     mask.at<uchar>(j - box[1], i - box[0]) = 0; // 深度值为0的地方 mask也改成0
  89.                 }
  90.             }
  91.         }
  92.     }
  93. }
  94. void Orbbec::Postprocess(int box[4], cv::Mat& mask, cv::Mat srcimg,float result[10]) {
  95.     cv::Rect r = cv::Rect(box[0], box[1], box[2] - box[0], box[3] - box[1]);
  96.     cv::Mat imgcrop = srcimg(r).clone();
  97.     mask = mask(r).clone();
  98.     cv::Mat dis_mask = cv::Mat::zeros(r.height,r.width, CV_32FC3);
  99.     GetDistance(box, mask, dis_mask);
  100.     //cv::Mat dis_show;
  101.     //cv::convertScaleAbs(dis_mask, dis_show, 255.0 / 1000);
  102.     //cv::applyColorMap(dis_show, dis_show, cv::COLORMAP_JET);
  103.     //cv::imshow("dismask", dis_show);
  104.    
  105.     // 利用open3d进行点云的后处理
  106.     // segment plane分割平面,因为快递分割结果里面会含有侧面,因此先分割,取最大的那个面,然后提取这个面的中点作抓取点
  107.     // 以及该面的法向量
  108.     float ylength = 0, xlength = 0;
  109.     std::vector<float> Normals_and_Axis;
  110.     ProcessPointcloud(dis_mask, imgcrop, Normals_and_Axis, &ylength, &xlength);
  111.    
  112.     // 通过抓取点反算彩色图上的抓取点,用来观察是否抓对点
  113.     float CX = Normals_and_Axis[3] * cameraParam.depthIntrinsic.fx / Normals_and_Axis[5] + cameraParam.depthIntrinsic.cx;
  114.     float CY = Normals_and_Axis[4] * cameraParam.depthIntrinsic.fy / Normals_and_Axis[5] + cameraParam.depthIntrinsic.cy;
  115.     // 通过点云算出来的包裹长宽来反算彩色图中的2D最小包围框,用于观察是否抓准平面
  116.     float Width = 0, Height = 0;
  117.     if (Normals_and_Axis[5] > 0) {//只计算有合理深度值的
  118.         //根据xlength与ylength,反算框的wh,与XY形成抓取面的2d最小包围框
  119.         Width = xlength * cameraParam.depthIntrinsic.fx / Normals_and_Axis[5];
  120.         Height = ylength * cameraParam.depthIntrinsic.fy / Normals_and_Axis[5];
  121.     }
  122.     for (int i = 0; i < 6; i++) {
  123.         result[i] = Normals_and_Axis[i];
  124.     }
  125.     result[6] = CX;
  126.     result[7] = CY;
  127.     result[8] = Width;
  128.     result[9] = Height;
  129. }
  130. void Orbbec::ProcessPointcloud(cv::Mat& dis_mask, cv::Mat image, std::vector<float>& result, float* ylength, float* xlength)
  131. {
  132.         // //dis_mask to pointcloud
  133.         auto outputPC = std::make_shared<open3d::geometry::PointCloud>();
  134.         int num_points = dis_mask.cols * dis_mask.rows;
  135.         for (int i = 0; i < dis_mask.rows; i++)
  136.         {
  137.                 for (int j = 0; j < dis_mask.cols; j++)
  138.                 {
  139.                         Eigen::Vector3d pc = { dis_mask.at<cv::Vec3f>(i, j)[0], dis_mask.at<cv::Vec3f>(i, j)[1], dis_mask.at<cv::Vec3f>(i, j)[2] };
  140.                         Eigen::Vector3d clr = { (float)image.at<cv::Vec3b>(i,j)[2] / 255.0,
  141.                                                                    (float)image.at<cv::Vec3b>(i,j)[1] / 255.0,
  142.                                                                    (float)image.at<cv::Vec3b>(i,j)[0] / 255.0 };
  143.                         outputPC->points_.push_back(pc);
  144.                         outputPC->colors_.push_back(clr);
  145.                 }
  146.         }
  147.         //open3d::visualization::DrawGeometries({ outputPC}, "outputPC", 800, 450);
  148.         //异常值剔除,剔除z距离为0的无效点云
  149.         std::vector<size_t> indices;
  150.         for (size_t i = 0; i < outputPC->points_.size(); i++) {
  151.                 if (outputPC->points_[i][2] == 0.0) {
  152.                         indices.push_back(i);
  153.                 }
  154.         }
  155.         outputPC = outputPC->SelectByIndex(indices, true);
  156.         if (outputPC->points_.size() <= 3) {
  157.                 result = { 0,0,0,0,0,0,0 };
  158.                 printf("points size too small\n");
  159.                 return;
  160.         }
  161.     // 平面分割 取出来最大的平面
  162.         auto start = std::chrono::system_clock::now();
  163.         double tDis = 0.01; // 邻域距离
  164.         int minNum = 3;    // 最小点云数
  165.         int numIter = 200; // 迭代数  
  166.         std::tuple<Eigen::Vector4d, std::vector<size_t>> vRes = outputPC->SegmentPlane(tDis, minNum, numIter);
  167.         // 平面参数
  168.         // AX+BY+CZ+D=0  ==> Z=-(AX+BY+D)/C
  169.         Eigen::Vector4d para = std::get<0>(vRes);
  170.         //printf("Segment plane:%.3fX+%.3fY+%.3fZ+%.3f=0\n",para[0],para[1],para[2],para[3]);
  171.         // 内点索引
  172.         std::vector<size_t> selectedIndex = std::get<1>(vRes);
  173.         std::shared_ptr<open3d::geometry::PointCloud> inPC = outputPC->SelectByIndex(selectedIndex, false);
  174.         //open3d::visualization::DrawGeometries({ inPC}, "inPC", 800, 450);
  175.         // 点云质心作为距离坐标
  176.         Eigen::Vector3d Axis;
  177.         Axis = inPC->GetCenter();
  178.         // 计算法向量z夹角
  179.         Eigen::Vector3d A(para[0], para[1], para[2]), X(-1, 0, 0), Y(0, -1, 0), Z(0, 0, 1);
  180.         double angleX0, angleX, angleY, angleZ;
  181.         double PI = 3.1415926;
  182.         angleZ = std::acos(A.dot(Z) / (A.norm() * Z.norm())) * 180 / PI;
  183.         angleX0 = std::acos(A.dot(X) / (A.norm() * X.norm())) * 180 / PI;
  184.         angleY = std::acos(A.dot(Y) / (A.norm() * Y.norm())) * 180 / PI;
  185.         angleX = std::atan2(A[1], A[0]) * 180 / PI;
  186.         if (angleZ > 90) {
  187.                 angleZ = 180 - angleZ;
  188.                 X = { 1, 0, 0 };
  189.                 Y = { 0, 1, 0 };
  190.                 angleX0 = std::acos(A.dot(X) / (A.norm() * X.norm())) * 180 / PI;
  191.                 angleY = std::acos(A.dot(Y) / (A.norm() * Y.norm())) * 180 / PI;
  192.                 angleX = std::atan2(-A[1], A[0]) * 180 / PI;
  193.                
  194.         }
  195.         //printf("angle:%f,%f,%f,xplane:%f\n", angleX0, angleY, angleZ, angleX);
  196.         //angleX的角度是与法向量投影到xoy平面的并于x负方向的夹角,顺时针是0-180,逆时针是0-负180
  197.     //
  198.        
  199.         result.push_back(angleX0);
  200.         result.push_back(angleY);
  201.         result.push_back(angleZ);
  202.         result.push_back(Axis[0]);
  203.         result.push_back(Axis[1]);
  204.         result.push_back(Axis[2]);
  205.        
  206.         auto end = std::chrono::system_clock::now();
  207.         //std::cout << "open3d process time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
  208.         // // 绘制分割出来的平面模型
  209.         Eigen::Vector3d min_pt, max_pt;
  210.         min_pt = inPC->GetMinBound();
  211.         max_pt = inPC->GetMaxBound();
  212.         double Xmin = min_pt[0], Ymin = min_pt[1], Zmin = min_pt[2];
  213.         double Xmax = max_pt[0], Ymax = max_pt[1], Zmax = max_pt[2];
  214.         *ylength = (float)Ymax - (float)Ymin;
  215.         *xlength = (float)Xmax - (float)Xmin;
  216.         //展示结果
  217.         if (0) {
  218.                 // 外点   绿色
  219.                 std::shared_ptr<open3d::geometry::PointCloud> outPC = outputPC->SelectByIndex(selectedIndex, true);
  220.                 const Eigen::Vector3d colorOut = { 0,1,0 };
  221.                 outPC->PaintUniformColor(colorOut);
  222.                 // open3d::visualization::DrawGeometries({ outPC}, "outPC", 800, 450);
  223.                 auto Plane = std::make_shared<open3d::geometry::PointCloud>();
  224.                 int width = 20, height = 20;
  225.                 for (int i = 0; i < width; i++) {
  226.                         double x = Xmin + (Xmax - Xmin) / width * i;
  227.                         for (int j = 0; j < height; j++) {
  228.                                 double y = Ymin + (Ymax - Ymin) / height * j;
  229.                                 double z = -(para[0] * x + para[1] * y + para[3]) / para[2];
  230.                                 Eigen::Vector3d pc = { x, y, z };
  231.                                 Plane->points_.push_back(pc);
  232.                         }
  233.                 }
  234.                 const Eigen::Vector3d color = { 1,0,1 };
  235.                 Plane->PaintUniformColor(color);
  236.                 // 夹爪方向
  237.                 auto lineCloud = std::make_shared<open3d::geometry::PointCloud>();
  238.                 lineCloud->points_.resize(20);
  239.                 for (size_t i = 0; i < lineCloud->points_.size(); ++i)
  240.                 {
  241.                         lineCloud->points_[i] = Axis - i * 0.01 * A;
  242.                 }
  243.                 lineCloud->PaintUniformColor(color);
  244.                 // 抓取点
  245.                 auto mesh = open3d::geometry::TriangleMesh::CreateSphere(0.01);
  246.                 mesh->ComputeVertexNormals();
  247.                 mesh->PaintUniformColor(Eigen::Vector3d(0.1, 0.1, 0.1));
  248.                 mesh->Translate(Axis);
  249.                 //圆心坐标
  250.                 auto mesh1 = open3d::geometry::TriangleMesh::CreateCoordinateFrame(0.1);
  251.                 mesh1->ComputeVertexNormals();
  252.                 //旋转到相机方向 方便我们观看
  253.                 Eigen::Matrix4d transform;
  254.                 transform << 1.0, 0.0, 0.0, 0.0,
  255.                         0.0, -1.0, 0.0, 0.0,
  256.                         0.0, 0.0, -1.0, 0.0,
  257.                         0.0, 0.0, 0.0, 1.0;
  258.                 inPC->Transform(transform);
  259.                 outPC->Transform(transform);
  260.                 lineCloud->Transform(transform);
  261.                 Plane->Transform(transform);
  262.                 mesh->Transform(transform);
  263.                 mesh1->Transform(transform);
  264.                 // open3d::io::WritePointCloudToPCD("inPC.pcd", *inPC,false);
  265.                 // open3d::io::WritePointCloudToPCD("outPC.pcd", *outPC,false);
  266.                 // open3d::io::WritePointCloudToPCD("lineCloud.pcd", *lineCloud,false);
  267.                 // open3d::io::WritePointCloudToPCD("Plane.pcd", *Plane,false);
  268.                 open3d::visualization::DrawGeometries({ inPC,outPC,lineCloud,Plane,mesh,mesh1 }, "Result", 800, 450);
  269.         }
  270. }
  271. void Orbbec::close(void) {
  272.     pipe.stop();
  273. };
复制代码
再新建一个主函数,用来调用上面的函数,名字就叫main1_testcamera.cpp写,主体代码如下所示:
  1. #include "camera.h"
  2. // #include "opencv2/opencv.hpp"
  3. #include <fstream>
  4. #include <iostream>
  5. #include <cmath>
  6. #include <conio.h>
  7. using namespace std;
  8. int main(int argc, char** argv) try {
  9.     Orbbec camera;
  10.     camera.Init();
  11.     while (true)  {
  12.         cv::Mat src, dep;
  13.         if (!camera.GetRgbAndDepth(src, dep)) {
  14.             continue;
  15.         }
  16.         cv::Mat show=src.clone();
  17.         //cv::addWeighted(src,0.5,dep,0.8,0.5,show);
  18.         int box[4] = { 280,200,360,280};//检测框的xmin,ymin,xmax,ymax
  19.         cv::Mat mask = cv::Mat::ones(cv::Size(src.cols, src.rows), CV_8UC1);
  20.         float result[10] = {0};
  21.         camera.Postprocess(box, mask, src, result);
  22.         printf("ax,ay,az,x,y,z,:%f,%f,%f,%f,%f,%f\n", result[0], result[1], result[2], result[3], result[4], result[5]);
  23.         
  24.         cv::Point p1((int)(0.5 * box[0] + 0.5 * box[2]), (int)(0.5 * box[1] + 0.5 * box[3]));
  25.         cv::circle(show, p1, 3, cv::Scalar(0, 255, 255), 3);//center point
  26.         cv::Point p2((int)result[6], (int)result[7]);
  27.         cv::circle(show, p2, 3, cv::Scalar(0, 0, 255), 3);//pick point   
  28.         cv::Rect rdraw0 = cv::Rect((int)box[0], (int)box[1], (int)(box[2]-box[0]), (int)(box[3] - box[1]));
  29.         cv::rectangle(show, rdraw0, cv::Scalar(0, 255, 255), 2);//detect box
  30.         cv::Rect rdraw1 = cv::Rect((int)(result[6] - 0.5 * result[8]),(int)(result[7] - 0.5 * result[9]),
  31.             (int)result[8], (int)result[9]);
  32.         cv::rectangle(show, rdraw1, cv::Scalar(0, 0, 255), 2);//postprocess box
  33.         printf("-------------------------------------------------\n");
  34.         cv::imshow("show", show);
  35.         char c = cv::waitKey(1);
  36.         if (c == 27) {
  37.             cv::destroyAllWindows();
  38.             break;
  39.         }
  40.     }
  41.     camera.close();
  42.     return 0;
  43. }
  44. catch (ob::Error& e) {
  45.     std::cerr << "function:" << e.getName() << "\nargs:" << e.getArgs() << "\nmessage:" << e.getMessage() << "\ntype:" << e.getExceptionType() << std::endl;
  46.     exit(EXIT_FAILURE);
  47. }
复制代码
末了,新建一个CMakeLists.txt设置我们的环境,如下所示,必要根据现真相况修改OpenCV_DIR、OrbbecSDK_ROOT_DIR、Open3D_DIR,
  1. cmake_minimum_required(VERSION 3.10)
  2. project(orbbec)
  3. add_definitions(-std=c++11)
  4. add_definitions(-DAPI_EXPORTS)
  5. set(CMAKE_CXX_STANDARD 11)
  6. set(CMAKE_BUILD_TYPE Release)
  7. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
  8. include_directories(include/)
  9. link_directories(lib/) #添加特定的库文件搜索路径 相当于g++的 -L参数
  10. include_directories(${PROJECT_SOURCE_DIR}/src/)
  11. file(GLOB_RECURSE SRCS ${PROJECT_SOURCE_DIR}/src/*.cpp)
  12. #opencv
  13. Set(OpenCV_DIR D:/Project/opencv/build/)
  14. find_package(OpenCV)
  15. include_directories(${OpenCV_INCLUDE_DIRS})
  16. include_directories(${OpenCV_DIR}/include/)
  17. link_directories(${OpenCV_DIR}/x64/vc15/lib/)
  18. #orbbec
  19. set(OrbbecSDK_ROOT_DIR D:/Project/OrbbecSDK/SDK)
  20. set(OrbbecSDK_LIBRARY_DIRS ${OrbbecSDK_ROOT_DIR}/lib)
  21. set(OrbbecSDK_INCLUDE_DIR ${OrbbecSDK_ROOT_DIR}/include)
  22. include_directories(${OrbbecSDK_INCLUDE_DIR})
  23. link_directories(${OrbbecSDK_LIBRARY_DIRS})
  24. #open3d
  25. Set(Open3D_DIR D:/Project/open3d-0.18.0/CMake/)
  26. find_package( Open3D  REQUIRED)
  27. include_directories(${Open3D_INCLUDE_DIRS})
  28. link_directories(${Open3D_LIBRARY_DIRS})
  29. add_executable(test main1_test_camera.cpp ${SRCS})
  30. target_link_libraries(test OrbbecSDK ${OpenCV_LIBS})
  31. target_link_libraries(test ${Open3D_LIBRARIES})
  32. target_include_directories(test PUBLIC ${Open3D_INCLUDE_DIRS})
复制代码
末了,利用Cmake-gui与vs2019天生可实行文件即可,运行步伐时间将这3个dll文件放在test.exe的同级目次即可。

2 YOLO11S-SEG的onnxruntime推理

 直接上代码,起首创建Segment.h,用来界说推理用到的函数,如下
  1. #ifndef SEGMENT_H
  2. #define SEGMENT_H
  3. #include <fstream>
  4. #include <sstream>
  5. #include <iostream>
  6. #include <opencv2/imgproc.hpp>
  7. #include <opencv2/highgui.hpp>
  8. //#include <cuda_provider_factory.h>
  9. #include <onnxruntime_cxx_api.h>
  10. #include <chrono>
  11. using namespace std;
  12. using namespace Ort;
  13. struct BoxInfo
  14. {
  15.         float x;
  16.         float y;
  17.         float w;
  18.         float h;
  19.         float score;
  20.         int label;
  21.         float mask[32];
  22. };
  23. struct Net_config
  24. {
  25.         float confThreshold; // Confidence threshold
  26.         float nmsThreshold;  // Non-maximum suppression threshold
  27.         std::string modelpath;
  28.         std::string labelpath;
  29. };
  30. constexpr static int num_class = 1;//我们只有一类就是1,多类就要改这儿
  31. const static int kOutputSize = num_class + 4 + 32;
  32. class YOLOV8
  33. {
  34. public:
  35.         YOLOV8(Net_config config);//加载模型
  36.         void preprocess_img(cv::Mat& img, cv::Mat& dis, int input_w, int input_h);//将图像letterbox resize到640*640
  37.         void normalize_(cv::Mat img);//除以255,归一化,同时将rgbrgbrgb转成rrrgggbbb
  38.         void detect(cv::Mat& frame, std::vector<BoxInfo>& generate_boxes, std::vector<cv::Mat>& masks);//输入图像进行检测与后处理
  39.         //得到每个目标的检测框与每个目标的mask1
  40.         float iou(float lbox[4], float rbox[4]);//iou计算
  41.         void nms(vector<BoxInfo>& input_boxes);//nms
  42.         std::vector<cv::Mat> process_mask(const float* proto, int proto_size, std::vector<BoxInfo>& dets, cv::Mat img);//后处理得到mask
  43.         cv::Rect get_downscale_rect(float bbox[4], float scale);//将640*640输入的box尺寸下采样到160*160的特征图上
  44.         cv::Mat scale_mask(cv::Mat mask, cv::Mat img); // 将640 * 640输入得到的掩码还原到原图上, 很好理解,就跟processimg反着操作
  45.         cv::Rect get_rect(cv::Mat& img, float bbox[4]);// 将640 * 640输入得到的box还原到原图上, 很好理解,就跟processimg反着操作
  46.        
  47.        
  48. private:
  49.         int inpWidth;
  50.         int inpHeight;
  51.         int nout;
  52.         int num_proposal;
  53.         std::vector<string> class_names;
  54.         float confThreshold;
  55.         float nmsThreshold;
  56.         std::vector<float> input_image_;//ONNXRUMTIME接收的数据是一个vector
  57.        
  58.         Env env = Env(ORT_LOGGING_LEVEL_ERROR, "YOLOV8");
  59.         Ort::Session* ort_session = nullptr;
  60.         SessionOptions sessionOptions = SessionOptions();
  61.         std::vector<char*> input_names;
  62.         std::vector<char*> output_names;
  63.         std::vector<vector<int64_t>> input_node_dims; // >=1 outputs
  64.         std::vector<vector<int64_t>> output_node_dims; // >=1 outputs
  65.         const std::vector<uint32_t> colors = { 0xFF3838, 0xFF9D97, 0xFF701F, 0xFFB21D, 0xCFD231, 0x48F90A,
  66.                                                                                 0x92CC17, 0x3DDB86, 0x1A9334, 0x00D4BB, 0x2C99A8, 0x00C2FF,
  67.                                                                                 0x344593, 0x6473FF, 0x0018EC, 0x8438FF, 0x520085, 0xCB38FF,
  68.                                                                                 0xFF95C8, 0xFF37C7 };
  69. };
  70. #endif
复制代码
然后新建Segment.cpp开详细实现这些函数,代码如下:
  1. #include "Segment.h"
  2. YOLOV8::YOLOV8(Net_config config)
  3. {
  4.         confThreshold = config.confThreshold;
  5.         nmsThreshold = config.nmsThreshold;
  6.         string classesFile = config.labelpath;
  7.         string model_path = config.modelpath;
  8.         std::wstring widestr = std::wstring(model_path.begin(), model_path.end());
  9.         OrtStatus* status = OrtSessionOptionsAppendExecutionProvider_CUDA(sessionOptions, 0);
  10.         sessionOptions.SetGraphOptimizationLevel(ORT_ENABLE_BASIC);
  11.         ort_session = new Session(env, widestr.c_str(), sessionOptions);
  12.         size_t numInputNodes = ort_session->GetInputCount();
  13.         size_t numOutputNodes = ort_session->GetOutputCount();
  14.         AllocatorWithDefaultOptions allocator;
  15.         for (int i = 0; i < numInputNodes; i++)
  16.         {
  17.                 AllocatedStringPtr input_name_Ptr = ort_session->GetInputNameAllocated(i, allocator);
  18.                 input_names.push_back(input_name_Ptr.get());
  19.                 Ort::TypeInfo input_type_info = ort_session->GetInputTypeInfo(i);
  20.                 auto input_tensor_info = input_type_info.GetTensorTypeAndShapeInfo();
  21.                 auto input_dims = input_tensor_info.GetShape();
  22.                 input_node_dims.push_back(input_dims);
  23.         }
  24.         for (int i = 0; i < numOutputNodes; i++)
  25.         {
  26.                 AllocatedStringPtr output_name_Ptr = ort_session->GetOutputNameAllocated(i, allocator);
  27.                 output_names.push_back(output_name_Ptr.get());
  28.                 Ort::TypeInfo output_type_info = ort_session->GetOutputTypeInfo(i);
  29.                 auto output_tensor_info = output_type_info.GetTensorTypeAndShapeInfo();
  30.                 auto output_dims = output_tensor_info.GetShape();
  31.                 output_node_dims.push_back(output_dims);
  32.         }
  33.         inpHeight = input_node_dims[0][2];
  34.         inpWidth = input_node_dims[0][3];
  35.         nout = output_node_dims[0][1];
  36.         num_proposal = output_node_dims[0][2];
  37.         ifstream ifs(classesFile.c_str());
  38.         string line;
  39.         while (getline(ifs, line))  class_names.push_back(line);
  40.         printf("classsize is:%d\n", num_class);
  41.         assert(num_class = class_names.size());
  42. }
  43. cv::Rect YOLOV8::get_rect(cv::Mat& img, float bbox[4]) {
  44.         float l, r, t, b;
  45.         float r_w = inpWidth / (img.cols * 1.0);
  46.         float r_h = inpHeight / (img.rows * 1.0);//inpHeight inpWidth
  47.         if (r_h > r_w) {
  48.                 l = bbox[0] - bbox[2] / 2.f;
  49.                 r = bbox[0] + bbox[2] / 2.f;
  50.                 t = bbox[1] - bbox[3] / 2.f - (inpHeight - r_w * img.rows) / 2;
  51.                 b = bbox[1] + bbox[3] / 2.f - (inpHeight - r_w * img.rows) / 2;
  52.                 l = l / r_w;
  53.                 r = r / r_w;
  54.                 t = t / r_w;
  55.                 b = b / r_w;
  56.         }
  57.         else {
  58.                 l = bbox[0] - bbox[2] / 2.f - (inpWidth - r_h * img.cols) / 2;
  59.                 r = bbox[0] + bbox[2] / 2.f - (inpWidth - r_h * img.cols) / 2;
  60.                 t = bbox[1] - bbox[3] / 2.f;
  61.                 b = bbox[1] + bbox[3] / 2.f;
  62.                 l = l / r_h;
  63.                 r = r / r_h;
  64.                 t = t / r_h;
  65.                 b = b / r_h;
  66.         }
  67.         return cv::Rect(round(l), round(t), round(r - l), round(b - t));
  68. }
  69. cv::Rect YOLOV8::get_downscale_rect(float bbox[4], float scale) {
  70.         float left = bbox[0] - bbox[2] / 2;
  71.         float top = bbox[1] - bbox[3] / 2;
  72.         float right = bbox[0] + bbox[2] / 2;
  73.         float bottom = bbox[1] + bbox[3] / 2;
  74.         left /= scale;
  75.         top /= scale;
  76.         right /= scale;
  77.         bottom /= scale;
  78.         return cv::Rect(round(left), round(top), round(right - left), round(bottom - top));
  79. }
  80. cv::Mat YOLOV8::scale_mask(cv::Mat mask, cv::Mat img) {
  81.         int x, y, w, h;
  82.         float r_w = inpWidth / (img.cols * 1.0);
  83.         float r_h = inpHeight / (img.rows * 1.0);
  84.         if (r_h > r_w) {
  85.                 w = inpWidth;
  86.                 h = r_w * img.rows;
  87.                 x = 0;
  88.                 y = (inpHeight - h) / 2;
  89.         }
  90.         else {
  91.                 w = r_h * img.cols;
  92.                 h = inpHeight;
  93.                 x = (inpWidth - w) / 2;
  94.                 y = 0;
  95.         }
  96.         cv::Rect r(x, y, w, h);
  97.         cv::Mat res;
  98.         cv::resize(mask(r), res, img.size());
  99.         return res;
  100. }
  101. std::vector<cv::Mat> YOLOV8::process_mask(const float* proto, int proto_size, std::vector<BoxInfo>& dets, cv::Mat img) {
  102.         std::vector<cv::Mat> masks;
  103.         //proto 32x(H/4)x(W/4)
  104.         //auto start = std::chrono::system_clock::now();
  105.         for (size_t i = 0; i < dets.size(); i++) {
  106.                 cv::Mat mask_mat = cv::Mat::zeros(inpHeight / 4, inpWidth / 4, CV_8UC1);//160*160
  107.                 float bbox[4] = { dets[i].x, dets[i].y, dets[i].w, dets[i].h };
  108.                 auto r = get_downscale_rect(bbox, 4);//将640*640输入的box尺寸下采样到160*160的特征图上
  109.                 for (int x = r.x; x < r.x + r.width; x++) {
  110.                         for (int y = r.y; y < r.y + r.height; y++) {
  111.                                 float e = 0.0f;
  112.                                 for (int j = 0; j < 32; j++) {
  113.                                         //1x32 x 1*32*160*160 =1*160*160 可以理解成160*160特征图上的每一个像素有32个值,要与mask的32个值分别相乘再相加
  114.                                         //而1*32*160*160在内存中的存储方式是160*160 160*160 160*160 .... 因此每次乘法操作的时候都要跳过160*160个内存空间
  115.                                         e += dets[i].mask[j] * proto[j * proto_size / 32 + y * mask_mat.cols + x];
  116.                                 }
  117.                                 e = 1.0f / (1.0f + expf(-e));
  118.                                 if (e > 0.5) {
  119.                                         mask_mat.at<uchar>(y, x) = 1;
  120.                                 }
  121.                         }
  122.                 }
  123.                 //160*160的掩码resize到640*640上
  124.                 cv::resize(mask_mat, mask_mat, cv::Size(inpWidth, inpHeight), 0, 0, 1);
  125.                 //再将640*640的掩码还原到原图上,很好理解,就跟processimg反着操作
  126.                 cv::Mat img_mask = scale_mask(mask_mat, img);
  127.                 //将640*640的box还原到原图上,很好理解,就跟processimg反着操作
  128.                 r = get_rect(img, bbox);
  129.                 cv::Rect holeImgRect(0, 0, img.cols, img.rows);
  130.                 r = r & holeImgRect;
  131.                 dets[i].x = r.x;
  132.                 dets[i].y = r.y;
  133.                 dets[i].w = r.width;
  134.                 dets[i].h = r.height;
  135.                 masks.push_back(img_mask);
  136.         }
  137.         return masks;
  138. }
  139. void YOLOV8::normalize_(cv::Mat img)
  140. {
  141.         int row = img.rows;
  142.         int col = img.cols;
  143.         input_image_.resize(row * col * img.channels());
  144.         // bgrbgrbgr to rrrgggbbb
  145.         for (int c = 0; c < 3; c++)
  146.         {
  147.                 for (int i = 0; i < row; i++)
  148.                 {
  149.                         for (int j = 0; j < col; j++)
  150.                         {
  151.                                 float pix = img.ptr<uchar>(i)[j * 3 + 2 - c];
  152.                                 input_image_[c * row * col + i * col + j] = pix / 255.0;
  153.                         }
  154.                 }
  155.         }
  156. }
  157. float YOLOV8::iou(float lbox[4], float rbox[4]) {
  158.         float interBox[] = {
  159.           (std::max)(lbox[0] - lbox[2] / 2.f , rbox[0] - rbox[2] / 2.f), //left
  160.           (std::min)(lbox[0] + lbox[2] / 2.f , rbox[0] + rbox[2] / 2.f), //right
  161.           (std::max)(lbox[1] - lbox[3] / 2.f , rbox[1] - rbox[3] / 2.f), //top
  162.           (std::min)(lbox[1] + lbox[3] / 2.f , rbox[1] + rbox[3] / 2.f), //bottom
  163.         };
  164.         if (interBox[2] > interBox[3] || interBox[0] > interBox[1])
  165.                 return 0.0f;
  166.         float interBoxS = (interBox[1] - interBox[0]) * (interBox[3] - interBox[2]);
  167.         return interBoxS / (lbox[2] * lbox[3] + rbox[2] * rbox[3] - interBoxS);
  168. }
  169. void YOLOV8::nms(vector<BoxInfo>& input_boxes)
  170. {
  171.         sort(input_boxes.begin(), input_boxes.end(), [](BoxInfo a, BoxInfo b) { return a.score > b.score; });
  172.         vector<bool> isSuppressed(input_boxes.size(), false);
  173.         for (int i = 0; i < int(input_boxes.size()); ++i)
  174.         {
  175.                 if (isSuppressed[i]) { continue; }
  176.                 for (int j = i + 1; j < int(input_boxes.size()); ++j)
  177.                 {
  178.                         if (isSuppressed[j]) { continue; }
  179.                         float lbox[4] = { input_boxes.at(i).x,input_boxes.at(i).y,input_boxes.at(i).w,input_boxes.at(i).h };
  180.                         float rbox[4] = { input_boxes.at(j).x,input_boxes.at(j).y,input_boxes.at(j).w,input_boxes.at(j).h };
  181.                         float ovr = iou(lbox, rbox);
  182.                         if (ovr >= nmsThreshold)
  183.                         {
  184.                                 isSuppressed[j] = true;
  185.                         }
  186.                 }
  187.         }
  188.         int idx_t = 0;
  189.         input_boxes.erase(remove_if(input_boxes.begin(), input_boxes.end(), [&idx_t, &isSuppressed](const BoxInfo& f) { return isSuppressed[idx_t++]; }), input_boxes.end());
  190. }
  191. void YOLOV8::preprocess_img(cv::Mat& img, cv::Mat& dis, int input_w, int input_h) {
  192.         int w, h, x, y;
  193.         float r_w = input_w / (img.cols * 1.0);
  194.         float r_h = input_h / (img.rows * 1.0);
  195.         if (r_h > r_w) {//宽大于高
  196.                 w = input_w;
  197.                 h = r_w * img.rows;
  198.                 x = 0;
  199.                 y = (input_h - h) / 2;
  200.         }
  201.         else {
  202.                 w = r_h * img.cols;
  203.                 h = input_h;
  204.                 x = (input_w - w) / 2;
  205.                 y = 0;
  206.         }
  207.         cv::Mat re(h, w, CV_8UC3);
  208.         cv::resize(img, re, re.size(), 0, 0, cv::INTER_LINEAR);
  209.         cv::Mat out(input_h, input_w, CV_8UC3, cv::Scalar(128, 128, 128));
  210.         re.copyTo(out(cv::Rect(x, y, re.cols, re.rows)));
  211.         out.copyTo(dis);
  212. }
  213. void YOLOV8::detect(cv::Mat& frame, vector<BoxInfo>& generate_boxes,std::vector<cv::Mat>& masks)
  214. {
  215.         cv::Mat dstimg;
  216.         preprocess_img(frame, dstimg, inpWidth, inpHeight);
  217.         normalize_(dstimg);
  218.         array<int64_t, 4> input_shape_{ 1, 3,  inpHeight,  inpWidth };
  219.         auto allocator_info = MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
  220.         Value input_tensor_ = Value::CreateTensor<float>(allocator_info, input_image_.data(), input_image_.size(), input_shape_.data(), input_shape_.size());
  221.         // 开始推理
  222.         const std::array<const char*, 1> inputNames = { "images" };
  223.         const std::array<const char*, 2> outNames = { "output0","output1" };
  224.         vector<Value> ort_outputs = ort_session->Run(Ort::RunOptions{ nullptr }, inputNames.data(), &input_tensor_, 1, outNames.data(), outNames.size());
  225.         /////generate proposals
  226.         //vector<BoxInfo> generate_boxes;
  227.         int n = 0, k = 0;
  228.         const float* pdata = ort_outputs[0].GetTensorMutableData<float>();// 1 * 116 *8400
  229.         const float* pdata1 = ort_outputs[1].GetTensorMutableData<float>();//1*32*160*160 mask propsal
  230.         for (n = 0; n < num_proposal; n++)
  231.         {
  232.                 float out[kOutputSize];//4+class+32
  233.                 float mask[32];
  234.                 for (int j = 0; j < nout; j++) {
  235.                         out[j] = pdata[n + num_proposal * j];
  236.                 }
  237.                 memcpy(&mask, &out[4 + num_class], 32 * sizeof(float));
  238.                 int max_ind = 0;
  239.                 float max_class_socre = 0;
  240.                 // 计算最大的置信度得分
  241.                 for (k = 0; k < num_class; k++)
  242.                 {
  243.                         if (out[k + 4] > max_class_socre)
  244.                         {
  245.                                 max_class_socre = out[k + 4];
  246.                                 max_ind = k;
  247.                         }
  248.                 }
  249.                 if (max_class_socre > confThreshold)
  250.                 {
  251.                         float cx = out[0];
  252.                         float cy = out[1];
  253.                         float w = out[2];
  254.                         float h = out[3];
  255.                         BoxInfo det;
  256.                         det.x = cx;
  257.                         det.y = cy;
  258.                         det.w = w;
  259.                         det.h = h;
  260.                         det.score = max_class_socre;
  261.                         det.label = max_ind;
  262.                         for (int jj = 0; jj < 32; jj++) {
  263.                                 det.mask[jj] = mask[jj];
  264.                         }
  265.                         generate_boxes.push_back(det);
  266.                 }
  267.         }
  268.         nms(generate_boxes);
  269.         int kOutputSize2 = 32 * (inpHeight / 4) * (inpWidth / 4);
  270.         masks = process_mask(pdata1, kOutputSize2, generate_boxes, frame);
  271.         // draw at original frame
  272.         for (size_t i = 0; i < generate_boxes.size(); i++) {
  273.                 cv::Mat img_mask = masks[i];
  274.                 auto color = colors[(int)generate_boxes[i].label % colors.size()];
  275.                 auto bgr = cv::Scalar(color & 0xFF, color >> 8 & 0xFF, color >> 16 & 0xFF);
  276.                 cv::Rect r = cv::Rect((int)generate_boxes[i].x, (int)generate_boxes[i].y, (int)generate_boxes[i].w, (int)generate_boxes[i].h);
  277.                 cv::rectangle(frame, r, bgr, 2);
  278.                 // mask 画原图上
  279.                 for (int x = r.x; x < r.x + r.width; x++) {
  280.                         for (int y = r.y; y < r.y + r.height; y++) {
  281.                                 float val = img_mask.at<uchar>(y, x);
  282.                                 if (val == 0) continue;
  283.                                 frame.at<cv::Vec3b>(y, x)[0] = frame.at<cv::Vec3b>(y, x)[0] / 2 + bgr[0] / 2;
  284.                                 frame.at<cv::Vec3b>(y, x)[1] = frame.at<cv::Vec3b>(y, x)[1] / 2 + bgr[1] / 2;
  285.                                 frame.at<cv::Vec3b>(y, x)[2] = frame.at<cv::Vec3b>(y, x)[2] / 2 + bgr[2] / 2;
  286.                         }
  287.                 }
  288.                 char label[100];
  289.                 sprintf(label, "%s:%.2f", class_names[generate_boxes[i].label], generate_boxes[i].score);
  290.                 cv::putText(frame, label, cv::Point(r.x, r.y - 4), cv::FONT_HERSHEY_PLAIN, 1.2, cv::Scalar(128, 128, 255), 2);
  291.         }
  292. }
复制代码
然后再创建一个主步伐,叫main.cpp用来调用这些步伐,代码如下:
  1. #include <iostream>
  2. #include <chrono>
  3. #include <cmath>
  4. #include <assert.h>
  5. #include "Segment.h"
  6. #include "camera.h"
  7. #include <stdio.h>
  8. using namespace std;
  9. int main(int argc, char** argv) {
  10.     Net_config YOLOV8_nets = { 0.9, 0.5,
  11.             "D:/Project/inference/Orbbec_example/model/kuaidi.onnx" ,
  12.             "D:/Project/inference/Orbbec_example/model/kuaidi.names" };
  13.     YOLOV8 net(YOLOV8_nets);
  14.     Orbbec camera;
  15.     camera.Init();
  16.     while (1){
  17.         cv::Mat src, dep;
  18.         if (!camera.GetRgbAndDepth(src, dep)) {
  19.             continue;
  20.         }
  21.         cv::Mat show = src.clone();
  22.         // Run inference
  23.         auto start = std::chrono::system_clock::now();
  24.         std::vector<BoxInfo> res;
  25.         std::vector<cv::Mat> masks;
  26.         net.detect(src, res, masks);
  27.         auto end = std::chrono::system_clock::now();
  28.         std::cout << "inference time: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
  29.         if (res.size()==0){printf("no target detect\n");}
  30.         cv::imshow("reult", src);
  31.         char c = cv::waitKey(1);
  32.         for (int i = 0; i < res.size(); i++){
  33.             int box[4] = { (int)res[i].x, (int)res[i].y,(int)(res[i].x + res[i].w),(int)(res[i].y + res[i].h) };
  34.             cv::Mat mask = masks[i].clone();
  35.             float result[10] = { 0 };
  36.             camera.Postprocess(box, mask, src, result);
  37.             cv::Point p1((int)(0.5 * box[0] + 0.5 * box[2]), (int)(0.5 * box[1] + 0.5 * box[3]));
  38.             cv::circle(show, p1, 3, cv::Scalar(0, 255, 255), 3);//center point
  39.             cv::Point p2((int)result[6], (int)result[7]);
  40.             cv::circle(show, p2, 3, cv::Scalar(0, 0, 255), 3);//pick point   
  41.             cv::Rect rdraw0 = cv::Rect((int)box[0], (int)box[1], (int)(box[2] - box[0]), (int)(box[3] - box[1]));
  42.             cv::rectangle(show, rdraw0, cv::Scalar(0, 255, 255), 2);//detect box
  43.             cv::Rect rdraw1 = cv::Rect((int)(result[6] - 0.5 * result[8]), (int)(result[7] - 0.5 * result[9]),
  44.                 (int)result[8], (int)result[9]);
  45.             cv::rectangle(show, rdraw1, cv::Scalar(0, 0, 255), 2);//postprocess box
  46.         }
  47.         printf("-------------------------------------------------\n");
  48.         cv::imshow("show", show);
  49.         c = cv::waitKey(1);
  50.         if (c == 27) {
  51.             cv::destroyAllWindows();
  52.             break;
  53.         }
  54.    
  55.     }
  56.   
  57.   camera.close();
  58.   printf("exit prgram\n");
  59.   return 0;
  60. }
复制代码
改写以下CMakeLists.txt,使其可以同时利用1.2与这一章节,如下:
  1. cmake_minimum_required(VERSION 3.10)
  2. project(orbbec)
  3. add_definitions(-std=c++11)
  4. add_definitions(-DAPI_EXPORTS)
  5. set(CMAKE_CXX_STANDARD 11)
  6. set(CMAKE_BUILD_TYPE Release)
  7. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
  8. include_directories(include/)
  9. link_directories(lib/) #添加特定的库文件搜索路径 相当于g++的 -L参数
  10. include_directories(${PROJECT_SOURCE_DIR}/src/)
  11. file(GLOB_RECURSE SRCS ${PROJECT_SOURCE_DIR}/src/*.cpp)
  12. #opencv
  13. Set(OpenCV_DIR D:/Project/opencv/build/)
  14. find_package(OpenCV)
  15. include_directories(${OpenCV_INCLUDE_DIRS})
  16. include_directories(${OpenCV_DIR}/include/)
  17. link_directories(${OpenCV_DIR}/x64/vc15/lib/)
  18. #orbbec
  19. set(OrbbecSDK_ROOT_DIR D:/Project/OrbbecSDK/SDK)
  20. set(OrbbecSDK_LIBRARY_DIRS ${OrbbecSDK_ROOT_DIR}/lib)
  21. set(OrbbecSDK_INCLUDE_DIR ${OrbbecSDK_ROOT_DIR}/include)
  22. include_directories(${OrbbecSDK_INCLUDE_DIR})
  23. link_directories(${OrbbecSDK_LIBRARY_DIRS})
  24. #open3d
  25. Set(Open3D_DIR D:/Project/open3d-0.18.0/CMake/)
  26. find_package( Open3D  REQUIRED)
  27. include_directories(${Open3D_INCLUDE_DIRS})
  28. link_directories(${Open3D_LIBRARY_DIRS})
  29. #onnxruntinme
  30. Set(ONNXRUNTIME_ROOT_DIR D:/Project/onnxruntime-win-x64-gpu-1.14.0/)
  31. include_directories(${ONNXRUNTIME_ROOT_DIR}/include/)
  32. link_directories(${ONNXRUNTIME_ROOT_DIR}/lib/)
  33. add_executable(test main1_test_camera.cpp ${SRCS})
  34. target_link_libraries(test OrbbecSDK ${OpenCV_LIBS})
  35. target_link_libraries(test ${Open3D_LIBRARIES})
  36. target_include_directories(test PUBLIC ${Open3D_INCLUDE_DIRS})
  37. target_link_libraries(test onnxruntime)
  38. add_executable(main main.cpp ${SRCS})
  39. target_link_libraries(main OrbbecSDK ${OpenCV_LIBS})
  40. target_link_libraries(main ${Open3D_LIBRARIES})
  41. target_include_directories(main PUBLIC ${Open3D_INCLUDE_DIRS})
  42. target_link_libraries(main onnxruntime)
复制代码
 仍然基于cmake-gui与vs,天生对应的exe文件,运行exe的时间记得将下面几个dll拷贝到同一个目次下,否则会报错。



别的将camra.cpp中的ProcessPointcloud下面的改成1,就可以可视化抓取点与姿态。


3 结语

实测奥比中光的相机彩色图很暗,调了好久曝光参数啥的也没realsense的彩色图看起来真实。大概跟我买的相机型号有关。
末了说一下,这个博客的内容恰当有一点c++底子的食用,至少要会用cmake、vs嘛。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表