使用 OpenCV、Boost 线程和多个摄像头

Posted

技术标签:

【中文标题】使用 OpenCV、Boost 线程和多个摄像头【英文标题】:Using OpenCV, Boost threading and multiple cameras 【发布时间】:2012-07-09 14:21:53 【问题描述】:

我正在尝试编写一个程序,该程序能够在两个不同的线程中从两个不同的相机捕获图像。我想这样做是因为当我在同一个线程中执行此操作时,我必须等待 cvQueryFrame 两倍的时间,所以我无法以 30 fps 的速度抓取图像(我从每个摄像头获得 15 FPS)。

我看过这篇 SO 帖子,但这只适用于一台相机。 Using cvQueryFrame and boost::thread together

我当前的程序给出了不同的结果,有时它会导致内存泄漏,通常我只是看不到任何事情发生,有时它会运行几秒钟但图像再次冻结。奇怪的是,早些时候当我没有调用 cvShowImage,但让我的 imageProcessing 函数做一些有用的事情时,我可以看到我从两个摄像头获得了实时结果。我认为这意味着可以完成这项工作,但是我在某个地方犯了一个愚蠢的错误。我的操作系统是 LINUX,我使用的是 OpenCV 2.4

我的代码:

#include <iostream>
#include <cstdio>
#include <cv.h>
#include <ml.h>
#include <cvaux.h>
#include <highgui.h>
#include <vector>
#include <stdio.h>
#include "producer_consumer_queue.hpp"



//Camera settings
int cameraWidth = 1280;
int cameraHeight = 720;
int waitKeyValue = 5;
bool threads_should_exit = false;

CvCapture * capture;
CvCapture * capture2;

using namespace std;
using namespace cv;

void grabFrame(concurrent_queue<IplImage* > * frame_queue, int camNumber) 
    try 
        //Load first frames
        cout << "grabFrame: " << camNumber << " init with " << cameraWidth << " x " << cameraHeight << endl;

        IplImage* frame;
        if (camNumber == 0)frame = cvQueryFrame(capture);
        if (camNumber == 1)frame = cvQueryFrame(capture2);
        while (frame && !threads_should_exit) 
            if (camNumber == 0)frame = cvQueryFrame(capture);
            if (camNumber == 1)frame = cvQueryFrame(capture2);
            IplImage* frame_copy = NULL;
            frame_copy = cvCloneImage(frame);

            if (camNumber == 0)cvShowImage("NE", frame);
            cout << "grabFrame: " << camNumber << " pushing back to queue" << endl;
            frame_queue->push(frame_copy);

            int k = cvWaitKey(waitKeyValue);

            if (k == 1048603 || k == 27 || k == '\r') 

                cout << "grabFrame: Process killed" << endl;
                //release memory
                threads_should_exit = true;
            

        
     catch (const concurrent_queue<IplImage* >::Canceled & e) 
        cout << "grabFrame: Show thread is canceled" << endl;
        return;
    



void processFrames(concurrent_queue<IplImage* > * frame_queue0, concurrent_queue<IplImage* > * frame_queue1) 
    try 
        do 
            cout << "processFrames: Processing two frames" << endl;
            IplImage* frm = NULL;
            frame_queue0->wait_and_pop(frm);
            IplImage * frm2 = NULL;
            frame_queue1->wait_and_pop(frm2);
            cvReleaseImage(&frm);
            cvReleaseImage(&frm2);
         while (!threads_should_exit);
     catch (const concurrent_queue<IplImage* >::Canceled & e) 
        cout << "processFrames: Processing thread is canceled" << endl;
        return;
    


int main() 
    capture = cvCreateCameraCapture(0);
    capture2 = cvCreateCameraCapture(1);
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, cameraWidth);
    cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, cameraHeight);
    cvSetCaptureProperty(capture2, CV_CAP_PROP_FRAME_WIDTH, cameraWidth);
    cvSetCaptureProperty(capture2, CV_CAP_PROP_FRAME_HEIGHT, cameraHeight);

    boost::thread_group frame_workers;
    boost::thread_group frame_workers2;
    concurrent_queue<IplImage* > frame_queue(&frame_workers);
    concurrent_queue<IplImage* > frame_queue2(&frame_workers2);

    boost::thread * query_thread = new boost::thread(processFrames, &frame_queue, &frame_queue2);
    boost::thread * cam0_thread = new boost::thread(grabFrame, &frame_queue, 0);
    usleep(10000);
    boost::thread * cam1_thread = new boost::thread(grabFrame, &frame_queue2, 1);

    frame_workers.add_thread(query_thread);
    frame_workers.add_thread(cam0_thread);

    frame_workers2.add_thread(query_thread);
    frame_workers2.add_thread(cam1_thread);
    while (true) 
        if (threads_should_exit) 
            cout << "Main: threads should be killed" << endl;
            while (!frame_queue.empty()) 
                usleep(10000);
            
            frame_workers.remove_thread(query_thread);
            frame_workers2.remove_thread(query_thread);
            frame_workers.remove_thread(cam0_thread);
            frame_workers2.remove_thread(cam1_thread);

            frame_workers.join_all();
            break;
        
        usleep(10000);
    

    return 0;


编辑:

我添加了一个简单的功能来检测一张纸,以查看当我不调用 cvShowImage() 时是否一切正常。如果我不调用cvShowImage(),我的程序可以很好地检测到一张纸。如果我这样做,程序再次出现奇怪的行为并冻结等。

【问题讨论】:

【参考方案1】:

应该只有一个线程在操作 GUI(几乎任何 GUI 框架都是如此)。您应该组织您的代码,以便仅从主“GUI 线程”调用cvShowImage

似乎在query_thread 中完成的工作可以在主线程中轻松完成。

【讨论】:

我按照您的建议调整了我的代码并将整个 query_thread 移动到主线程,但这会导致完全相同的行为。如果我不调用 cvShowImage 程序可以正常工作。 我做了,但我还需要将 cvWaitKey() 移动到主线程并将我的帧抓取限制为 30 FPS。感谢您的帮助!

以上是关于使用 OpenCV、Boost 线程和多个摄像头的主要内容,如果未能解决你的问题,请参考以下文章

利用face_recognition,dlib与OpenCV调用摄像头进行人脸识别

使用boost线程池(多线程使用opencv处理图片)

OpenCV:来自 VideoWriter 的写入是不是应该在独立线程中运行?

机器视觉行业实践技巧 -- OpenCV技巧与方法:避坑指南

使用 OpenCv 和多线程从 IP 摄像机提供实时视频

使用 OpenCV 的多个摄像头