目标检测多线程框架(2)

目标检测用到的异步多线程处理(2)-安全拷贝队列   完整工程下载

继续接着上篇,上篇已经打破了线性的处理过程,相信用opencv的都知道Mat数据的拷贝其实内部是浅拷贝,这就在刷新显示时出问题了,绘制过程不一定是原子的。其实就是在绘制并没有结束时就发生了Mat转移造成的。

将线程休眠调小点(3ms)如下右边图就出现爆闪了。 这时就想起了GDI双缓冲。

不过还是std::move和std::forward才是王道

对比图  (左边是处理MAT数据完美转移显示,右边是Mat浅拷贝赋值lock显示)

这里两个exe是我先后点击的速度是不一致的

全部参考代码  将资源共享部分独立到安全队列中处理,代码就更加简洁了。

void testMutiThread_show(void)
{
    //图像数据结构
    using MAT = cv::Mat;
    //Mat缓存队列
    using Mat_que = class
    {
    public:
        size_t push(MAT& pFrame)
        {
            std::lock_guard<std::mutex> lock_guard(m_mutex);
            {
                m_frames.push_back(std::forward<MAT>(pFrame));    //这里是关键 完美转移
                //m_frames.push_back(pFrame.clone());             //深拷贝还是有性能牺牲             
                //m_frames.push_back(pFrame);                     //浅拷贝会爆闪
            }
            return m_frames.size();
        };
        bool pop(MAT& pFrame)
        {
            bool found = false;
            std::lock_guard<std::mutex> lock_guard(m_mutex);
            if (!m_frames.empty())
            {
                pFrame = m_frames.front();
                m_frames.pop_front();
                found = true;
            }
            return found;
        };
        size_t size()
        {
            std::lock_guard<std::mutex> lock_guard(m_mutex);
            return m_frames.size();
        };
        void clear()
        {
            std::lock_guard<std::mutex> lock_guard(m_mutex);
            MAT pFrame;
            while (pop(pFrame))
            {
            }
        };
    private:
        std::deque<MAT> m_frames;
        std::mutex m_mutex;
    };
    //共享队列
    using MyFrame = struct 
    {
        Mat_que image_data_queue;                   //解码数据
        Mat_que process_data_queue;                 //处理数据
        Mat_que draw_data_queue;                    //渲染数据
    };
    
    static MyFrame m_Frame;
    std::atomic_bool brun1(true), brun2(true), brun3(true);

    auto CollectTd = [&]
    {
        cv::VideoCapture vcap;
        MAT capture264;
        vcap.open("jay.mp4");           //打开文件
        vcap.set(cv::CAP_PROP_POS_FRAMES, 1);
        if (!vcap.isOpened())
        {
            brun1 = brun2 = brun3 = false;
            return;
        }
        int numflag(0);
        while (true)
        {
            std::string strnum = std::to_string(numflag++);
            vcap >> capture264;         //此处模拟相机采集数据
            if (!capture264.empty())
            {
                cout << "CollectThread image_data>> " << strnum << endl;
                m_Frame.image_data_queue.push(capture264);
            }
            else {
                brun1 = brun2 = brun3 = false;
                break;
            }
            this_thread::sleep_for(std::chrono::milliseconds(3));
        }
    };

    auto DecodeTd =[&]
    {
        while (brun1)
        {
            MAT image_data;
            m_Frame.image_data_queue.pop(image_data);
            cout << "DecodeThread image_data<< " << endl;
            if (!image_data.empty())
            {
                //从收到的数据进行解码,解码后送到处理线程
                cout << "DecodeThread process_data>> " << endl;
                m_Frame.process_data_queue.push(image_data);
            }
            else
                this_thread::sleep_for(std::chrono::milliseconds(50));
        }
    };

    auto ProcessTd = [&]
    {
        while (brun2)
        {
            MAT process_data;
            m_Frame.process_data_queue.pop(process_data);
            cout << "ProcessThread process_data<< " << endl;
            if (!process_data.empty())
            {
                //处理图像 处理完送到渲染线程
                cv::circle(process_data, cv::Point(300, 300), 300, cv::Scalar(0, 255, 0), 18);
                //ImageProcess(process_data);
                MAT draw_data = process_data.clone();
                cout << "ProcessThread draw_data>> " << endl;
                m_Frame.draw_data_queue.push(draw_data);
            }
            else
                this_thread::sleep_for(std::chrono::milliseconds(50));
        }
    };

    auto DrawTd = [&]
    {
        cv::namedWindow("DrawThread", cv::WINDOW_OPENGL);   //gl
        cv::resizeWindow("DrawThread", 320, 240);
        while (brun3)
        {
            MAT draw_data;
            m_Frame.draw_data_queue.pop(draw_data);
            //用opencv渲染
            if (!draw_data.empty())
            {
                cv::imshow("DrawThread", draw_data);
                cv::waitKey(1);
                cout << "DrawThread draw_data<< " << endl;
            }
            else
                this_thread::sleep_for(std::chrono::milliseconds(50));
        }
    };

    std::thread td1(CollectTd);
    std::thread td2(DecodeTd);
    std::thread td3(ProcessTd);
    std::thread td4(DrawTd);
    td1.join();
    td2.join();
    td3.join();
    td4.join();
    this_thread::sleep_for(std::chrono::hours(10));
}

当然我这里在安全队列采用的clone() 复制 性能上可能会有开销。

根据C11左右值引用特性,采用std::forward<MAT>(pFrame)完美转发就优化了。

拆成类的同理我就不贴出来了。

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
Qt是一个跨平台的C++应用开发框架,可以用于开发各种类型的应用程序,包括目标检测应用。 目标检测是计算机视觉领域的一个重要任务,旨在识别图像或视频中的特定对象并将其标记出来。Qt提供了丰富的功能和工具,可以帮助开发人员实现目标检测算法。 在Qt中实现目标检测可以按照以下步骤进行: 1.导入图像或视频数据:通过Qt的图像处理模块,可以将图像或视频数据导入到应用程序中,这是目标检测的基础。 2.图像预处理:在进行目标检测之前,通常需要对输入数据进行预处理,如图像增强、尺度调整等。Qt提供了丰富的图像处理功能,可以方便地实现这些操作。 3.选择目标检测算法:根据具体需求,选择合适的目标检测算法。常用的目标检测算法包括基于特征的方法(如Haar特征和HOG特征)和基于深度学习的方法(如卷积神经网络)等。 4.实现目标检测算法:利用C++编写目标检测算法的代码。Qt提供了一套易于使用的工具和库,可以快速实现和调试算法。 5.标记目标并显示结果:在检测到目标后,通过Qt的图形界面模块,可以将目标在图像或视频中标记出来,并将结果显示在应用程序的界面上。 6.性能优化:根据实际需求,对目标检测算法进行性能优化,如加速算法、减少误检率等。Qt提供了多线程、并行计算等功能,可以提高目标检测的速度和效率。 总之,Qt是一个强大的开发框架,在目标检测应用中可以发挥重要作用。通过利用Qt的功能和工具,开发人员可以更加便捷地实现目标检测算法,并开发出高效、稳定的目标检测应用程序。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值