当前位置:   article > 正文

【QT开发(8)】QT 中使用tensorrt_qt tensorrt

qt tensorrt

在之前的文章《【TensorRT(2)】研究美团tech的yolov6的TensorRT部署》说明了tensorRT 的使用流程。今天尝试将其并入QT 项目中。

项目地址

库地址:https://gitee.com/hiyanyx/qt5.14-cpp_dds_-project/tree/dds_-tensorRT-yolov6/

参考资料:

1、代码参考:https://gitee.com/xiaoyuerCV/tensorrt-yolov6/,已经下载到了目录 ./reference/YOLOv6-Trt8

2、pytorch 权重下载:美团yolov6,已经下载到了目录 ./reference/YOLOv6-main-meituan/deployONNX

原理:下载 pytorch 的权重,yolov6s.pt,转换成 onnx。然后,把onnx 复制到 ./reference/YOLOv6-Trt8。然后trt 里面的c代码会自动把onnx 序列化为 yolov6s.engine 文件。

3、行人视频:reference/YOLOv6-Trt8/xingren.mp4

该分支主要做的工作

1、在 ./src/main/example.cpp 中实现了读取视频文件,然后通过 dds 发送的事情。

2、将 ./reference/YOLOv6-Trt8 作为 库 引入到 c++ 代码工程中,库名字为 deeplib,位置:./deps/deeplib。 具体工作为修改cmakelist文件,生成动态库 deeplib.so,增加deeplib.h 作为yolo检测器的接口(实现了Inferclass这个对象进行检测)。

Task 1:读取视频文件,然后通过 dds 发送的事情

1、在之前的文章【QT开发(6)】0926-QT 中加入 fastDDS 通信库的程序使用说明中说明了dds 的使用方法。

2、我们基于上次的项目,修改 examples.hpp, 在 class Example 增加一个对象成员 cv::VideoCapture video_capture;。 特别说明以下,关于对象成员的初始化可以查看我的博客【C++学习(8)】类对象作为成员变量【C++学习(10)】将一个类作为另一个类的成员: 类对象和类指针; std::unique_ptr 智能管理类指针。成员对象的初始化还是有很多知识点,作为基础知识大家需要学习。

3、修改 examples.cpp对 video_capture 的一些属性进行修改。

video_capture.open("/var/files/yanyixiong/qt5.14-cpp_-empty_-project/deps/deeplib/xingren.mp4");
// 视频mp4解码
  int codec = cv::VideoWriter::fourcc('D', 'I', 'V', 'X');
//获得
  double fps = video_capture.get(cv::CAP_PROP_FPS);
// 宽度
  int width = video_capture.get(cv::CAP_PROP_FRAME_WIDTH);
//高度
  int height = video_capture.get(cv::CAP_PROP_FRAME_HEIGHT);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

4、然后在50ms定时器中设置发送dds 信息。如果不明白我说的这个定时器是什么东西,请查看博文【QT开发(6)】0926-QT 中加入 fastDDS 通信库的程序使用说明

我把那篇的截图放一下:
在这里插入图片描述

void Example::timer_WorkingStatus_callback()
{
  // Test Env
  std::vector<unsigned char> vec_data;
  cv::Mat frame_pub;
  video_capture.read(frame_pub);

  if (!frame_pub.data ) {
              debug::log("fail to imread");
              return ;
      }
  else
      {
              //cv::imshow("source image", img1);
              //cv::waitKey(1);
              //cv::resize(frame_pub, frame_pub, cv::Size(),0.1, 0.1);
              debug::log("success to imread");
      }

  cv::imencode(".jpg", frame_pub, vec_data);
  auto_msg::msg::FrameData msg1;
  msg1.time_stamp() = get_time_ms();
  msg1.data() = vec_data;
  //msg1.data.insert(msg1.data.end(), vec_data.begin(), vec_data.end());
  simulation_raw_images_pub_->publish(msg1);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

5、至此,dds 发送视频就完成了。接下来,我们需要接受dds 信息,并用 yolov6 推理。

Task 2.1:将 yolov6 作为deeplib 库。

将 ./reference/YOLOv6-Trt8 作为 库 引入到 c++ 代码工程中,库名字为 deeplib,位置:./deps/deeplib。 具体工作为修改cmakelist文件,生成动态库 deeplib.so,增加deeplib.h 作为yolo检测器的接口(实现了Inferclass这个对象进行检测)。

1、 ./deps/deeplib 修改cmakelists,增加库

ADD_LIBRARY(deeplib SHARED ${SOURCES_FILES})
target_include_directories(deeplib PUBLIC ${SOURCES_PATH})
target_link_libraries(deeplib cuda tensorrt opencv)
  • 1
  • 2
  • 3

2、写deeplib.h 接口程序
写一个对象 Inferclass,包含,构造函数,析构函数,推理接口inferIOmain,以及复制构造函数。
包含 私有成员类指针 Yolov6Detector,这个是在https://gitee.com/xiaoyuerCV/tensorrt-yolov6/里面已经实现的

class Inferclass {
public:
  Inferclass(std::string model_path = "/var/files/yanyixiong/qt5.14-cpp_-empty_-project/deps/deeplib/yolov6s.onnx");
	Inferclass(const Inferclass &S);
	void inferIOmain(cv::Mat input_image);
	~Inferclass();

private:
    std::string model_path ;
    std::unique_ptr<Yolov6Detector> yolov6_detector;

};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在 构造函数 中完成对 Yolov6Detector 对象的初始化。

Inferclass::Inferclass(std::string model_path):model_path(model_path)
{
    std::cout << "Start" << std::endl;
// 导入onnx 地址
  this->yolov6_detector.reset(new Yolov6Detector(model_path));
  if (!this->yolov6_detector->Init()) {
    std::cout << "Failed to initialize Yolov6 detector!";
  }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

析构函数 ,因为我们使用的是std::unique_ptr 类指针,不需要手动new和delete 指针。需要注意的是,如果我们是使用普通指针,一定到在 析构函数里面把 这个类指针释放,否则是内存泄漏!

Inferclass::~Inferclass()
{
    std::cout << "End" << std::endl;
	//-----------------代码-------------------------------
	if(NULL != pA)//此处需要初始化时设置指针为空。
	{
	  delete pA;
	  pA = new A;
	}  else {
	  pA = new A;
	}
	//-----------------代码-------------------------------

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

推理接口 inferIOmain函数:

void Inferclass::inferIOmain(cv::Mat input_image) {
  //cv::Mat input_image;
// 建立目标列表
    std::vector<Object> objects;
// 检测图像 
   this->yolov6_detector->Detect(input_image, &objects);
    //画图
    DrawObjects(input_image, objects);
// 展示图片
    cv::imshow("YOLOv6 Object detection", input_image);
    cv::waitKey(1);
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

3、我们有了 deeplib.h 和cmakelist文件,这就是一个库了,可以被其他项目使用。这是个基础的工作,如果你不懂怎么在主项目里面引入库,可以看之前的git仓库学习cmake practice

# Task 2.2:接收 dds 信息,用 deeplib 库推理图片。

在之前的文章【QT开发(6)】0926-QT 中加入 fastDDS 通信库的程序使用说明中,引入deeplib 库。

1、修改 cmakelists,增加头文件

# ===== 设置 include 目录路径 =====
target_include_directories ( emptyApp PUBLIC
    # === 第三方库 ===
    # 在此处添加更多 第三方库
    # 具体写法,请查阅各个 库文档
    ${CMAKE_CURRENT_SOURCE_DIR}/deeplib/src
    )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2、修改 cmakelists,增加 cmaklist 子目录

#---------------------------------------------------#
#             子目录 CMakeLists.txt
#---------------------------------------------------#
#-- 子 CMakeLists.txt 执行的 中间产物,将分别放在 
#      build/src  build/libhello  目录中。
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/deps/deeplib EXCLUDE_FROM_ALL)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

3、修改 cmakelists,增加一个 target_link_libraries

    target_link_libraries( emptyApp 
			    deeplib)
  • 1
  • 2

4、至此,修改完了 cmakelists。然后在 Examples.h 中增加成员类。

在博客【C++学习(10)】将一个类作为另一个类的成员: 类对象和类指针; std::unique_ptr 智能管理类指针,我们谈到,如果是在 一个 class 中增加另一个 类成员,首先,要将A类的对象作为B类的成员,你必须在B类声明前声明A类。其次,就是像声明一个成员变量一样,在B类中添加一个成员,如A m_a; 最后,初始化m_a。因为这个成员是一个类对象,因此需要调用构造函数才能初始化。因为这个对象m_a在B类中,m_a对象的构造必然是在B类对象构造之前进行,因此不能在B类构造函数中进行,又因为m_a不是全局对象,也不能在函数外部。如何解决这个问题呢?这就是C++提出的成员初始化列表,用来解决这类问题的。

因此,我们增加一个 类成员

class Example : public rclcpp::Node
{
 public:
  Example(std::string model_path);
  ~Example();
  int Init();
  int Start();
  int Stop();
  Inferclass InferPr;
...
...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

然后在 Examples.cpp 中class Examples 成员初始化列表 初始化。

Example::Example(std::string model_path) : rclcpp::Node("example"),InferPr(model_path)
{
  running_ = false;
  workingStatus_timer_ = nullptr;
}
  • 1
  • 2
  • 3
  • 4
  • 5

完成了初始化,就可以使用这个 InferPr 成员,在50ms 定时器中用它进行推理

void Example::timer_WorkingStatus_callback()
{
  auto_msg::msg::FrameData stitch_img = stitch_img_.Get();
    if ( running_ == true && stitch_img.time_stamp()>0) {
      cv::Mat frame = cv::imdecode(stitch_img.data(), CV_LOAD_IMAGE_COLOR);
      InferPr.inferIOmain(frame);
    }
    else
    {
        std::cout << "Timer trick 50ms, waiting" << std::endl;
    }
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

4、至此,完成了工作

演示gif 动画

ScreenToGif 很好用呀,推荐。
在这里插入图片描述

正文结束

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/81696
推荐阅读
相关标签
  

闽ICP备14008679号