• C++中双线程调用网络摄像头,用多线程调用多个摄像头并同步执行算法


              在调用网络摄像头处理自己的算法时,当解码的速度与算法运行的速度差太多时,会出现类似下面的错误

    error while decoding MB 148 4, bytestream

    所以需要使用两个线程,一个线程调用摄像头,一个线程用来处理图像。

    一、使用双线程调用网络摄像头,并执行算法

    方法一:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. static std::mutex mutex;
    9. static std::atomic_bool isOpen;
    10. static void cameraThreadFunc(std::string camId, cv::Mat* pFrame)
    11. {
    12. cv::VideoCapture capture(camId);
    13. //capture.set(cv::CAP_PROP_FOURCC, CV_FOURCC('M', 'J', 'P', 'G'));
    14. capture.set(cv::CAP_PROP_FPS, 30);
    15. if (!capture.isOpened()) {
    16. isOpen = false;
    17. std::cout << "Failed to open camera with index " << camId << std::endl;
    18. }
    19. cv::Mat frame;
    20. while (isOpen) {
    21. capture >> frame;
    22. if (mutex.try_lock()) {
    23. frame.copyTo(*pFrame);
    24. mutex.unlock();
    25. }
    26. cv::waitKey(5);
    27. }
    28. capture.release();
    29. }
    30. int main(int argc, char* argv[])
    31. {
    32. std::string rtsps = "rtsp://admin:bs123456@192.168.1.64:554/h264/ch1/main/av_stream/1";
    33. isOpen = true;
    34. cv::Mat frame(1440, 2560, CV_8UC3);
    35. //cv::Mat* frame = new cv::Mat(1440, 2560, CV_8UC3);
    36. std::thread thread(cameraThreadFunc, rtsps, &frame); //调用摄像头
    37. //std::thread thread(cameraThreadFunc, rtsps, frame);
    38. //*****************************************************
    39. //调用自己的算法处理图像
    40. void* p_algorithm;
    41. p_algorithm = (void*)(new WindNetDetect());
    42. std::string net_bins = "./models/visdrone_1009-opt.bin";
    43. std::string net_paras = "./models/visdrone_1009-opt.param";
    44. int init_res = ((WindNetDetect*)p_algorithm)->init1(net_bins, net_paras);
    45. WindNetDetect* tmp = (WindNetDetect*)(p_algorithm);
    46. std::vector objects;
    47. //*****************************************************
    48. while (isOpen) {
    49. //*********************************
    50. //调用目标检测的算法
    51. tmp->detect(frame, objects);
    52. tmp->draw_objects(frame, objects);
    53. //*********************************
    54. if (cv::waitKey(1) == 'q') {
    55. break;
    56. }
    57. }
    58. frame.release();
    59. isOpen = false;
    60. thread.join();
    61. return 0;
    62. }
    63.  方法二:

      1. // video_test.cpp
      2. #include
      3. #include
      4. #include
      5. #include
      6. #include
      7. #include
      8. #include
      9. #include
      10. class VideoCaptureMT {
      11. public:
      12. VideoCaptureMT(int index, int height=480, int width=640);
      13. VideoCaptureMT(std::string filePath, int height=480, int width=640);
      14. ~VideoCaptureMT();
      15. bool isOpened() {
      16. return m_IsOpen;
      17. }
      18. void release() {
      19. m_IsOpen = false;
      20. }
      21. bool read(cv::Mat& frame);
      22. private:
      23. void captureInit(int index, std::string filePath, int height, int width);
      24. void captureFrame();
      25. cv::VideoCapture* m_pCapture;
      26. cv::Mat* m_pFrame;
      27. std::mutex* m_pMutex;
      28. std::thread* m_pThread;
      29. std::atomic_bool m_IsOpen;
      30. };
      31. VideoCaptureMT::VideoCaptureMT(int index, int height, int width)
      32. {
      33. captureInit(index, std::string(), height, width);
      34. }
      35. VideoCaptureMT::VideoCaptureMT(std::string filePath, int height, int width)
      36. {
      37. captureInit(0, filePath, height, width);
      38. }
      39. VideoCaptureMT::~VideoCaptureMT()
      40. {
      41. m_IsOpen = false;
      42. m_pThread->join();
      43. if (m_pCapture->isOpened()) {
      44. m_pCapture->release();
      45. }
      46. delete m_pThread;
      47. delete m_pMutex;
      48. delete m_pCapture;
      49. delete m_pFrame;
      50. }
      51. void VideoCaptureMT::captureInit(int index, std::string filePath, int height, int width)
      52. {
      53. if (!filePath.empty()) {
      54. m_pCapture = new cv::VideoCapture(filePath);
      55. }
      56. else {
      57. m_pCapture = new cv::VideoCapture(index);
      58. }
      59. m_pCapture->set(cv::CAP_PROP_FRAME_WIDTH, width);
      60. m_pCapture->set(cv::CAP_PROP_FRAME_HEIGHT, height);
      61. m_pCapture->set(cv::CAP_PROP_FPS, 30);
      62. m_IsOpen = true;
      63. m_pFrame = new cv::Mat(height, width, CV_8UC3);
      64. m_pMutex = new std::mutex();
      65. m_pThread = new std::thread(&VideoCaptureMT::captureFrame, this);
      66. }
      67. void VideoCaptureMT::captureFrame()
      68. {
      69. cv::Mat frameBuff;
      70. while (m_IsOpen) {
      71. (*m_pCapture) >> frameBuff;
      72. if (m_pMutex->try_lock()) {
      73. frameBuff.copyTo(*m_pFrame);
      74. m_pMutex->unlock();
      75. }
      76. cv::waitKey(5);
      77. }
      78. }
      79. bool VideoCaptureMT::read(cv::Mat& frame)
      80. {
      81. if (m_pFrame->empty()) {
      82. m_IsOpen = false;
      83. }
      84. else {
      85. m_pMutex->lock();
      86. m_pFrame->copyTo(frame);
      87. m_pMutex->unlock();
      88. }
      89. return m_IsOpen;
      90. }
      91. int main(int argc, char* argv[])
      92. {
      93. VideoCaptureMT capture(0);
      94. cv::Mat frame, gray;
      95. while (capture.isOpened()) {
      96. if (!capture.read(frame)) {
      97. break;
      98. }
      99. cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);
      100. cv::blur(gray, gray, cv::Size(3, 3));
      101. cv::Canny(gray, gray, 5 , 38 , 3);
      102. cv::waitKey(100);
      103. cv::imshow("image", gray);
      104. if (cv::waitKey(5) == 'q') {
      105. break;
      106. }
      107. }
      108. capture.release();
      109. return 0;
      110. }

       二、使用多线程调用多路摄像头并同步执行多个算法:

              使用两个线程调用两个函数,get_cam1中包含了调用网络摄像头的类VideoCaptureMT (见上面代码),以及调用算法。另外一个函数是一样的。代码如下 :

      1. void get_cam1()
      2. {
      3. clock_t start, end, end1, end2;
      4. std::string rtsps = "rtsp://admin:bs123456@192.168.1.64:554/h264/ch1/main/av_stream/1";
      5. VideoCaptureMT capture(rtsps);
      6. //VideoCaptureMT capture, captureusb;
      7. cv::namedWindow("外接摄像头检测", 0);
      8. cv::Mat frame, gray;
      9. while (capture.isOpened()) {
      10. std::lock_guard mtx_locker(mtx);
      11. start = clock();
      12. if (!capture.read(frame)) {
      13. break;
      14. }
      15. //gray = frame;
      16. end = clock();
      17. std::vector objects;
      18. tmp->detect(frame, objects);
      19. for (size_t i = 0; i < objects.size(); i++)
      20. {
      21. const Object& obj = objects[i];
      22. fprintf(stderr, "%d = %.5f at %.2f %.2f %.2f x %.2f\n", obj.label, obj.prob,
      23. obj.rect.x, obj.rect.y, obj.rect.width, obj.rect.height);
      24. cv::rectangle(frame, obj.rect, cv::Scalar(255, 0, 0));
      25. char text[256];
      26. //sprintf(text, "%s %.1f%%", class_names[obj.label], obj.prob * 100);
      27. sprintf(text, "%s", class_names[obj.label]);
      28. int baseLine = 0;
      29. cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
      30. int x = obj.rect.x;
      31. int y = obj.rect.y - label_size.height - baseLine;
      32. if (y < 0)
      33. y = 0;
      34. if (x + label_size.width > frame.cols)
      35. x = frame.cols - label_size.width;
      36. cv::rectangle(frame, cv::Rect(cv::Point(x, y), cv::Size(label_size.width, label_size.height + baseLine)),
      37. cv::Scalar(255, 255, 255), -1);
      38. cv::putText(frame, text, cv::Point(x, y + label_size.height),
      39. cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
      40. }
      41. //cv::imwrite("./result20.jpg", image);
      42. cv::imshow("外接摄像头检测", frame);
      43. end2 = clock();
      44. float rumtime = (float)(end2 - start) / CLOCKS_PER_SEC;
      45. std::stringstream buf;
      46. buf.precision(3);//����Ĭ�Ͼ���
      47. buf.setf(std::ios::fixed);//����С��λ
      48. buf << rumtime;
      49. std::string strtime;
      50. strtime = buf.str();
      51. std::cout << "strtime1111 = " << strtime << std::endl;
      52. //start = end2;
      53. if (cv::waitKey(5) == 'q') {
      54. break;
      55. }
      56. }
      57. capture.release();
      58. }
      59. void get_camusb()
      60. {
      61. clock_t start, end, end1, end2;
      62. std::string rtsps = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4";
      63. VideoCaptureMT capture(rtsps);
      64. cv::Mat frameusb;
      65. cv::namedWindow("外接摄像头检测1", 0);
      66. //void* p_algorithmusb;
      67. //p_algorithmusb = (void*)(new WindNetDetect());
      68. //std::string net_binsusb = "./models/visdrone_1009-opt.bin";
      69. //std::string net_parasusb = "./models/visdrone_1009-opt.param";
      70. //int init_res = ((WindNetDetect*)p_algorithmusb)->init1(net_binsusb, net_parasusb);
      71. //WindNetDetect* tmp = (WindNetDetect*)(p_algorithmusb);
      72. while (capture.isOpened()) {
      73. std::lock_guard mtx_locker(mtx);
      74. start = clock();
      75. if (!capture.read(frameusb)) {
      76. break;
      77. }
      78. //gray = frame;
      79. end = clock();
      80. std::vector objectsusb;
      81. tmp->detect(frameusb, objectsusb);
      82. for (size_t i = 0; i < objectsusb.size(); i++)
      83. {
      84. const Object& obj = objectsusb[i];
      85. fprintf(stderr, "%d = %.5f at %.2f %.2f %.2f x %.2f\n", obj.label, obj.prob,
      86. obj.rect.x, obj.rect.y, obj.rect.width, obj.rect.height);
      87. cv::rectangle(frameusb, obj.rect, cv::Scalar(255, 0, 0));
      88. char text[256];
      89. //sprintf(text, "%s %.1f%%", class_names[obj.label], obj.prob * 100);
      90. sprintf(text, "%s", class_names[obj.label]);
      91. int baseLine = 0;
      92. cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
      93. int x = obj.rect.x;
      94. int y = obj.rect.y - label_size.height - baseLine;
      95. if (y < 0)
      96. y = 0;
      97. if (x + label_size.width > frameusb.cols)
      98. x = frameusb.cols - label_size.width;
      99. cv::rectangle(frameusb, cv::Rect(cv::Point(x, y), cv::Size(label_size.width, label_size.height + baseLine)),
      100. cv::Scalar(255, 255, 255), -1);
      101. cv::putText(frameusb, text, cv::Point(x, y + label_size.height),
      102. cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
      103. }
      104. //cv::imwrite("./result20.jpg", image);
      105. cv::imshow("外接摄像头检测1", frameusb);
      106. end2 = clock();
      107. float rumtime = (float)(end2 - start) / CLOCKS_PER_SEC;
      108. std::stringstream buf;
      109. buf.precision(3);//����Ĭ�Ͼ���
      110. buf.setf(std::ios::fixed);//����С��λ
      111. buf << rumtime;
      112. std::string strtime;
      113. strtime = buf.str();
      114. std::cout << "strtime1111 = " << strtime << std::endl;
      115. //start = end2;
      116. if (cv::waitKey(5) == 'q') {
      117. break;
      118. }
      119. }
      120. capture.release();
      121. }
      122. int main() {
      123. void* p_algorithm;
      124. p_algorithm = (void*)(new WindNetDetect());
      125. std::string net_bins = "./models/visdrone_1009-opt.bin";
      126. std::string net_paras = "./models/visdrone_1009-opt.param";
      127. int init_res = ((WindNetDetect*)p_algorithm)->init1(net_bins, net_paras);
      128. tmp = (WindNetDetect*)(p_algorithm);
      129. //HANDLE hThread1 = CreateThread(NULL, 0, get_cam1, NULL, 0, NULL);
      130. //CloseHandle(hThread1);
      131. //HANDLE hThread2 = CreateThread(NULL, 0, get_camusb, NULL, 0, NULL);
      132. //CloseHandle(hThread2);
      133. std::thread thrd_1(get_cam1);
      134. std::thread thrd_2(get_camusb);
      135. thrd_1.join();
      136. thrd_2.join();
      137. while (true)
      138. {
      139. std::cout << "Main Thread Display!" << std::endl;
      140. Sleep(3000);
      141. }
      142. return 0;
      143. }
      144. 运行上面的代码时,两个函数没有同步运行。如下strtime1111表示一个线程调用的函数,strtime2222表示另一个线程调用的函数,能看出没有同时调用两个函数。

         所以需对代码进行如下改进:

        1. static std::mutex mutexk;
        2. void get_cam1()
        3. {
        4. clock_t start, end, end1, end2;
        5. std::string rtsps = "rtsp://admin:bs123456@192.168.1.64:554/h264/ch1/main/av_stream/1";
        6. VideoCaptureMT capture(rtsps);
        7. cv::Mat frame;
        8. cv::namedWindow("ss", 0);
        9. while (capture.isOpened()) {
        10. //pthread_rwlock_rdlock(&rwlock);
        11. //std::lock_guard mtx_locker(mtx);
        12. start = clock();
        13. if (!capture.read(frame)) {
        14. break;
        15. }
        16. if (mutexk.try_lock()) {
        17. //gray = frame;
        18. end = clock();
        19. std::vector objects;
        20. tmp->detect(frame, objects);
        21. //tmp->draw_objects(frame, objects);
        22. for (size_t i = 0; i < objects.size(); i++)
        23. {
        24. const Object& obj = objects[i];
        25. fprintf(stderr, "%d = %.5f at %.2f %.2f %.2f x %.2f\n", obj.label, obj.prob,
        26. obj.rect.x, obj.rect.y, obj.rect.width, obj.rect.height);
        27. cv::rectangle(frame, obj.rect, cv::Scalar(255, 0, 0));
        28. char text[256];
        29. //sprintf(text, "%s %.1f%%", class_names[obj.label], obj.prob * 100);
        30. sprintf(text, "%s", class_names[obj.label]);
        31. int baseLine = 0;
        32. cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
        33. int x = obj.rect.x;
        34. int y = obj.rect.y - label_size.height - baseLine;
        35. if (y < 0)
        36. y = 0;
        37. if (x + label_size.width > frame.cols)
        38. x = frame.cols - label_size.width;
        39. cv::rectangle(frame, cv::Rect(cv::Point(x, y), cv::Size(label_size.width, label_size.height + baseLine)),
        40. cv::Scalar(255, 255, 255), -1);
        41. cv::putText(frame, text, cv::Point(x, y + label_size.height),
        42. cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
        43. }
        44. //cv::imwrite("./result20.jpg", image);
        45. cv::imshow("ss", frame);
        46. end2 = clock();
        47. float rumtime = (float)(end2 - start) / CLOCKS_PER_SEC;
        48. std::stringstream buf;
        49. buf.precision(3);//����Ĭ�Ͼ���
        50. buf.setf(std::ios::fixed);//����С��λ
        51. buf << rumtime;
        52. std::string strtime;
        53. strtime = buf.str();
        54. std::cout << "strtime2222 = " << strtime << std::endl;
        55. //start = end2;
        56. if (cv::waitKey(5) == 'q') {
        57. break;
        58. }
        59. mutexk.unlock();
        60. }
        61. }
        62. capture.release();
        63. }
        64. void get_camusb()
        65. {
        66. //std::lock_guard mtx_locker(mtx);
        67. clock_t start, end, end1, end2;
        68. //std::string rtsps = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4";
        69. std::string rtsps = "rtsp://admin:bs123456@192.168.1.64:554/h264/ch1/main/av_stream/1";
        70. VideoCaptureMT capture(rtsps);
        71. cv::Mat frameusb;
        72. cv::namedWindow("zz1", 0);
        73. while (capture.isOpened()) {
        74. std::lock_guard mtx_locker1(mtx);
        75. start = clock();
        76. if (!capture.read(frameusb)) {
        77. break;
        78. }
        79. if (mutexk.try_lock()) {
        80. //gray = frame;
        81. end = clock();
        82. std::vector objectsusb;
        83. tmp->detect(frameusb, objectsusb);
        84. //tmp->draw_objects(frameusb, objectsusb);
        85. for (size_t i = 0; i < objectsusb.size(); i++)
        86. {
        87. const Object& obj = objectsusb[i];
        88. fprintf(stderr, "%d = %.5f at %.2f %.2f %.2f x %.2f\n", obj.label, obj.prob,
        89. obj.rect.x, obj.rect.y, obj.rect.width, obj.rect.height);
        90. cv::rectangle(frameusb, obj.rect, cv::Scalar(255, 0, 0));
        91. char text[256];
        92. //sprintf(text, "%s %.1f%%", class_names[obj.label], obj.prob * 100);
        93. sprintf(text, "%s", class_names[obj.label]);
        94. int baseLine = 0;
        95. cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
        96. int x = obj.rect.x;
        97. int y = obj.rect.y - label_size.height - baseLine;
        98. if (y < 0)
        99. y = 0;
        100. if (x + label_size.width > frameusb.cols)
        101. x = frameusb.cols - label_size.width;
        102. cv::rectangle(frameusb, cv::Rect(cv::Point(x, y), cv::Size(label_size.width, label_size.height + baseLine)),
        103. cv::Scalar(255, 255, 255), -1);
        104. cv::putText(frameusb, text, cv::Point(x, y + label_size.height),
        105. cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 0, 0));
        106. }
        107. //cv::imwrite("./result20.jpg", image);
        108. cv::imshow("zz1", frameusb);
        109. end2 = clock();
        110. float rumtime = (float)(end2 - start) / CLOCKS_PER_SEC;
        111. std::stringstream buf;
        112. buf.precision(3);//����Ĭ�Ͼ���
        113. buf.setf(std::ios::fixed);//����С��λ
        114. buf << rumtime;
        115. std::string strtime;
        116. strtime = buf.str();
        117. std::cout << "strtime1111 = " << strtime << std::endl;
        118. //start = end2;
        119. if (cv::waitKey(5) == 'q') {
        120. break;
        121. }
        122. mutexk.unlock();
        123. }
        124. }
        125. capture.release();
        126. }
        127. int main() {
        128. void* p_algorithm;
        129. p_algorithm = (void*)(new WindNetDetect());
        130. std::string net_bins = "./models/visdrone_1009-opt.bin";
        131. std::string net_paras = "./models/visdrone_1009-opt.param";
        132. int init_res = ((WindNetDetect*)p_algorithm)->init1(net_bins, net_paras);
        133. tmp = (WindNetDetect*)(p_algorithm);
        134. std::thread thrd_1(get_cam1);
        135. std::thread thrd_2(get_camusb);
        136. thrd_1.join();
        137. thrd_2.join();
        138. while (true)
        139. {
        140. std::cout << "Main Thread Display!" << std::endl;
        141. Sleep(3000);
        142. }
        143. return 0;
        144. }
        145.          使用多线线程调用多个函数同步执行模板如下:

          1. #include
          2. #include
          3. static std::mutex mutexk;
          4. void func1() {
          5. while (capture1.isOpened()) {
          6. if (mutexk.try_lock()) {
          7. //我的算法
          8. my_func1();
          9. mutexk.unlock();
          10. }
          11. }
          12. }
          13. void func2() {
          14. while (capture2.isOpened()) {
          15. if (mutexk.try_lock()) {
          16. //我的算法
          17. my_func2();
          18. mutexk.unlock();
          19. }
          20. }
          21. }
          22. int main() {
          23. std::thread thrd_1(func1);
          24. std::thread thrd_2(func2);
          25. thrd_1.join();
          26. thrd_2.join();
          27. return 0;
          28. }

          在ubuntu中c++opencv多线程显示图片时出现Gdk-WARNING **: xx: Fatal IO error

           解决办法:

          1、sudo apt install libx11-dev

          2、在代码中添加头文件#include

          3、在创建线程之前添加XInitThreads()

          4、在编译的时候需要添加-lX11 

          参考链接:OpenCV视频流的C++多线程处理方式_hlld26的博客-CSDN博客_opencv 多线程

        146. 相关阅读:
          如何构建城市经济大脑分析指标框架?六大分析主题
          【SpringSecurity】BCrypt密码加密和解密 一文学会使用BCryptPasswordEncoder
          Argo CD 保姆级入门教程
          内存泄露详细介绍
          基于udp协议的网络通信(windows客户端版+简易聊天室版),重定向到终端
          JavaScript 67 JavaScript HTML DOM 67.11 JavaScript HTML DOM 导航
          Docker 使用
          基于SSM SpringBoot vue个人博客网站
          【EMC专题】案例:PCB走线参考平面不完整导致辐射超标
          基于51单片机的羽毛球计分器设计
        147. 原文地址:https://blog.csdn.net/zk_ken/article/details/127802063