赞
踩
在之前的文章《【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
这个对象进行检测)。
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);
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); }
5、至此,dds 发送视频就完成了。接下来,我们需要接受dds 信息,并用 yolov6 推理。
将 ./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)
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;
};
在 构造函数 中完成对 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!";
}
}
析构函数 ,因为我们使用的是std::unique_ptr 类指针,不需要手动new和delete 指针。需要注意的是,如果我们是使用普通指针,一定到在 析构函数里面把 这个类指针释放,否则是内存泄漏!
Inferclass::~Inferclass()
{
std::cout << "End" << std::endl;
//-----------------代码-------------------------------
if(NULL != pA)//此处需要初始化时设置指针为空。
{
delete pA;
pA = new A;
} else {
pA = new A;
}
//-----------------代码-------------------------------
}
推理接口 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);
}
3、我们有了 deeplib.h 和cmakelist文件,这就是一个库了,可以被其他项目使用。这是个基础的工作,如果你不懂怎么在主项目里面引入库,可以看之前的git仓库学习cmake practice。
在之前的文章【QT开发(6)】0926-QT 中加入 fastDDS 通信库的程序使用说明中,引入deeplib 库。
1、修改 cmakelists,增加头文件
# ===== 设置 include 目录路径 =====
target_include_directories ( emptyApp PUBLIC
# === 第三方库 ===
# 在此处添加更多 第三方库
# 具体写法,请查阅各个 库文档
${CMAKE_CURRENT_SOURCE_DIR}/deeplib/src
)
2、修改 cmakelists,增加 cmaklist 子目录
#---------------------------------------------------#
# 子目录 CMakeLists.txt
#---------------------------------------------------#
#-- 子 CMakeLists.txt 执行的 中间产物,将分别放在
# build/src build/libhello 目录中。
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/deps/deeplib EXCLUDE_FROM_ALL)
3、修改 cmakelists,增加一个 target_link_libraries
target_link_libraries( emptyApp
deeplib)
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;
...
...
}
然后在 Examples.cpp 中class Examples 成员初始化列表 初始化。
Example::Example(std::string model_path) : rclcpp::Node("example"),InferPr(model_path)
{
running_ = false;
workingStatus_timer_ = nullptr;
}
完成了初始化,就可以使用这个 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;
}
}
4、至此,完成了工作
ScreenToGif 很好用呀,推荐。
正文结束
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。