I have a code here that captures the video stream from a camera running the video capture operation in a separate thread. The code compiles but when I try to run it I am receiving the following error.
I did some research and found out that this problem is related to the absence of th.join(); but I already do this when the user interrupts the process by pressing the q key. Until then, the code should keep on running in the created thread. So this tells me that I should join the thread somewhere else.
If I remove the thread by replacing thread th(&VideoCaptureAsync::update, this); with VideoCaptureAsync::update(); and deleting th.join();, the error goes away but this obviously defeats the purpose of this code.
Output
Inside initiate function
(process:10748): GStreamer-CRITICAL **: gst_element_get_state:
assertion 'GST_IS_ELEMENT (element)' failed
Inside start function
Inside update function
terminate called without an active exception
Inside read function
Aborted (core dumped)
Code
/*
* Asynchronous_video_capture.cpp
*
* Copyright (C) 2019 C. S. G.
*
* MIT License
*/
#include <iostream> // for standard I/O
#include <string> // for strings
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp> // Basic OpenCV structures (cv::Mat)
#include <opencv2/videoio.hpp> // Video write
#include <opencv2/opencv.hpp>
#include <opencv2/core/utility.hpp>
#include <thread>
#include <tuple>
using namespace cv;
using namespace std;
void foo(bool &keep_run){
cout << "Inside the thread: Interrupt flag = " << keep_run << endl;
if (std::cin.get() == 'q') {
keep_run = false;
cout << "User Interrupted the process. Interrupt flag = " << keep_run << endl;
}
}
class VideoCaptureAsync
{
private:
VideoCapture cam;
thread th;
bool read_lock;
Mat frame;
Mat grabbed;
bool isStarted;
public:
void initiate(unsigned int camId, unsigned int width, unsigned int height, double fps);
void start(); // a start function to create and start the thread
void update(); // an update function that will be called asynchronously
tuple<Mat, Mat> read(); // a read function that we will call from our code to retrieve a new frame.
void stop(); // a stop function to stop (join) the thread
void exit(); // an __exit__ function to clean up some resources.
};
void VideoCaptureAsync::initiate(unsigned int camId, unsigned int width, unsigned int height, double fps){
cout << "Inside initiate function" << endl;
cam.open(camId);
if (!cam.isOpened())
{
cerr << "Could not open the VideoCapture camera: " << camId << endl;
}
cam.set(CV_CAP_PROP_FRAME_WIDTH, width);
cam.set(CV_CAP_PROP_FRAME_HEIGHT, height);
cam.set(CAP_PROP_FPS, fps);
isStarted = false;
read_lock = false;
VideoCaptureAsync::start();
}
void VideoCaptureAsync::start(){
cout << "Inside start function" << endl;
if (isStarted) {
cout << "Asynchroneous video capturing has already been started" << endl;
}
isStarted = true;
thread th(&VideoCaptureAsync::update, this);
//VideoCaptureAsync::update();
}
void VideoCaptureAsync::update(){
cout << "Inside update function" << endl;
while(isStarted){
Mat frame_update;
Mat grabbed_update;
tie(frame_update, grabbed_update) = VideoCaptureAsync::read();
if(!read_lock){
frame_update.copyTo(frame);
grabbed_update.copyTo(grabbed);
}
}
}
tuple<Mat, Mat> VideoCaptureAsync::read(){
cout << "Inside read function" << endl;
if (!read_lock){
read_lock = true;
Mat frame_read;
cam.read(frame_read);
Mat grabbed_read;
read_lock = false;
return make_tuple(frame_read, grabbed_read);
}
}
void VideoCaptureAsync::stop(){
cout << "Inside stop function" << endl;
th.join();
isStarted = false;
read_lock = true;
}
void VideoCaptureAsync::exit(){
cout << "Finished writing ..." << endl;
cam.release();
}
int main(int argc, char *argv[]){
const unsigned int camId = 1;
const bool enableOutput = true;
const unsigned int w = 1280;
const unsigned int h = 720;
double fps = 30.0;
VideoCaptureAsync obj;
obj.initiate(camId,w,h,fps);
bool keep_running = true;
thread th1(foo, std::ref(keep_running));
Mat original_frame;
while (keep_running) {
std::tie(std::ignore, original_frame) = obj.read();
if (enableOutput) {
imshow("Retrieved Image", original_frame);
waitKey(1000/fps);
}
}
obj.stop();
obj.exit();
}
In your start() method:
thread th(&VideoCaptureAsync::update, this);
This statement creates a new local object in the start() method called th, a brand new, fresh off the assembly line, std::thread object, and constructs it in a manner that creates a new execution thread.
Immediately afterwards, start() returns. This destroys this local object, invoking its destructor, and resulting in your exception.
Your obvious intent is to use the th class member in order to create a new execution thread, instead of creating a new local object in the start() method. But the above C++ syntax is a declaration. It declares a new object, and when used in side a function it creates a new local object (in automatic scope), that gets automatically destroyed at the end of the scope. That's how C++ works.
In order to have the new execution thread started from your existing class member:
th=thread{&VideoCaptureAsync::update, this};
(using modern C++'s uniform initialization syntax). For more information see "Delayed start of thread in C++11".
Related
I am trying to use OpenCV to stream video from 2 cameras continuously via separate threads. The following code is displaying Segmentation fault (core dumped)
What is the reason for this and How do I fix this issue?
main.cpp
#include <iostream>
#include <pthread.h>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/videoio.hpp>
using namespace std;
struct thread_data {
string path;
int thread_id;
};
void *capture(void *threadarg)
{
struct thread_data *data;
data = (struct thread_data *) threadarg;
cv::VideoCapture cap(data->path);
if( !cap.isOpened())
{
std::cout<<"Not good, open camera failed"<<std::endl;
}
std::cout<< "Opened IP camera successfully!"<<std::endl;
cv::Mat frame;
string ext = ".jpg";
string result;
while (true) {
cap >> frame;
cv::imshow("Frame",frame);
cv::waitKey(1);
}
pthread_exit(NULL);
}
int main(void) {
pthread_t threads[2];
struct thread_data td[2];
int rc=0;
for( int i = 0; i < 2; i++ ) {
cout <<"main() : creating thread, " << i << endl;
td[i].thread_id = i;
td[0].path = "rtsp://admin:opencv123#192.168.1.23:554/Streaming/Channels/101/";
td[1].path = "rtsp://admin:opencv123#192.168.1.24:554/Streaming/Channels/101/";
rc = pthread_create(&threads[i], NULL, capture, (void *)&td[i]);
if (rc) {
cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
}
pthread_exit(NULL);
return 0;
}
log:
main() : creating thread, 0 main() : creating thread, 1
Segmentation fault (core dumped)
When I tried running it multiple times, I am able to open only one camera and that too isn't streaming continuously. It starts and stops in a few seconds.
Sometimes I get an error which says
OpenCV Error: Insufficient memory (Failed to allocate 140703464366800 bytes) in OutOfMemoryError
I have gone through various Q&As' on StackOverflow but none helped.
The problem here is that the code is facing race conditions. I was able to replicate the issue on my system and identified the following issues:
OpenCV window titles are not unique.
Spawned threads are not joined.
Race condition while opening the video stream.
Lets look into these issues in detail.
1.
OpenCV windows are uniquely identified by their title. In the current code, the title is a hardcoded string "Frame". So basically, both threads are creating/updating/destroying the same window in unknown order. That is a race condition which can be fixed by adding a string field to the struct thread_data which will serve as unique window identifier.
2.
In the main thread, the child threads are created asynchronously so the for loop will exit immediately after creating the threads and the program will exit pre-maturely without waiting for the spawned thread to complete execution. This problem can be solved by adding function calls to wait for the threads before the program exits. This process is called joining and can be achieved by calling pthread_join for each spawned thread.
3.
This issue was a bit trickier to track down. Due to some reason the backend library for video stream capture used by OpenCV is not behaving in a thread-safe manner. Seemingly, the video capture opening process is prone to race-condition and requires a synchronization lock. The lock can be easily implemented by calling the functions pthread_mutex_lock and pthread_mutex_unlock just before and after opening the VideoCapture object.
Here is the modified code demonstrating the solution for all of the above mentioned issues
#include <iostream>
#include <pthread.h>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/videoio.hpp>
using namespace std;
//Mutex for thread synchronization
static pthread_mutex_t foo_mutex = PTHREAD_MUTEX_INITIALIZER;
struct thread_data
{
string path;
int thread_id;
string window_title; //Unique window title for each thread
};
void *capture(void *threadarg)
{
struct thread_data *data;
data = (struct thread_data *) threadarg;
cv::VideoCapture cap;
//Safely open video stream
pthread_mutex_lock(&foo_mutex);
cap.open(data->path);
pthread_mutex_unlock(&foo_mutex);
if( !cap.isOpened())
{
std::cout<<"Not good, open camera failed"<<std::endl;
}
std::cout<< "Opened IP camera successfully!"<<std::endl;
cv::Mat frame;
string ext = ".jpg";
string result;
//Create window with unique title
cv::namedWindow(data->window_title);
while (true)
{
cap >> frame;
cv::imshow(data->window_title,frame);
cv::waitKey(10);
}
//Release VideoCapture object
cap.release();
//Destroy previously created window
cv::destroyWindow(data->window_title);
//Exit thread
pthread_exit(NULL);
}
int main(void)
{
const int thread_count = 2;
pthread_t threads[thread_count];
struct thread_data td[thread_count];
//Initialize thread data beforehand
td[0].path = "rtsp://admin:opencv123#192.168.1.23:554/Streaming/Channels/101/";
td[0].window_title = "First Window";
td[1].path = "rtsp://admin:opencv123#192.168.1.24:554/Streaming/Channels/101/";
td[1].window_title = "Second Window";
int rc=0;
for( int i = 0; i < thread_count; i++ )
{
cout <<"main() : creating thread, " << i << endl;
td[i].thread_id = i;
rc = pthread_create(&(threads[i]), NULL, capture, (void *)& (td[i]) );
if (rc)
{
cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
}
//Wait for the previously spawned threads to complete execution
for( int i = 0; i < thread_count; i++ )
pthread_join(threads[i], NULL);
pthread_exit(NULL);
return 0;
}
void writeFrametoDisk(const cv::Mat *frame, std::string path, int frameNum, std::string windowName)
{
cv::imwrite(path.append(std::to_string(frameNum)).append(".png"), *frame);
return;
}
void openCameraStream(int deviceId, std::string dirName)
{
cv::VideoCapture cap;
cap.open(deviceId);
if(!cap.isOpened()){std::cerr << "Unable to open the camera " << std::endl;}
std::cout << cap.get(cv::CAP_PROP_FRAME_WIDTH) << " " << cap.get(cv::CAP_PROP_FRAME_HEIGHT) << std::endl;
std::string windowName = deviceId == 0 ? "Cam 0" : "Cam 1";
std::string outputDir = dirName;
bool frameStFg = false;
while(!frameStFg)
{
cv::Mat frame;
cap.read(frame);
if(frame.empty()){std::cerr << "frame buffer empty " << std::endl;}
else
{
frameStFg = true;
}
}
cv::TickMeter timer;
timer.start();
int frameCount = 0;
while(1)
{
cv::Mat frame;
cap.read(frame);
if(frame.empty()){std::cerr << "frame buffer empty " << std::endl;}
frameCount++;
std::thread th(writeFrametoDisk, &frame, outputDir, frameCount, windowName);
th.join();
//// a simple wayto exit the loop
if(frameCount > 500)
{
break;
}
}
timer.stop();
std::cout << "Device id " << deviceId << " Capture ran for " << timer.getTimeSec() << " seconds" << std::endl;
std::cout << "Device id " << deviceId << " Number of frames to be capture should be " << timer.getTimeSec() * 30 << std::endl;
std::cout << "Device id " << deviceId << " Number of frames captured " << frameCount << std::endl;
cap.release();
}
int main(int argc, char * argv[])
{
std::string outputDir1 = "";
std::string outputDir2 = "";
std::thread camera1Thread(openCameraStream, 0, outputDir1);
std::thread camera2Thread(openCameraStream, 1, outputDir2);
camera1Thread.join();
camera2Thread.join();
}
As the comments mention, streaming without any imshow() of the image streams works well with out any problems. My setup includes, running two threads with two USB camera's and also these two threads launch a new thread each to save the image read from the cameras. I didn't observe any frame drops or errors and also was able to capture and write at approximately 30 fps.
A little debugging of the reason, it is recommended to use any imshow() in the main thread only i.e. main() function. Hope this helps anyone.
I'm want to achieve a "smooth" video recording using OpenCV and the Boost libaries.
For that i'm trying to implement the code I found here in to my program. I'm not too familiar with Boost yet and I keep getting the error \bind.hpp:313: error: no match for call to '(boost::_mfi::dm) (cv::Mat*&, cv::VideoCapture*&)'
unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_]);
My code is the following:
#include "recorder.h"
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "boost/thread.hpp"
using namespace cv;
using namespace std;
using namespace boost::posix_time;
Recorder::Recorder(){
webcamRecorder.open(1);
webcamRecorder.set(CV_CAP_PROP_FRAME_WIDTH, 1920);
webcamRecorder.set(CV_CAP_PROP_FRAME_HEIGHT, 1080);
recordingCount=0;
filename = "F:/MyVideo";
ext=".avi";
hasStarted=false;
}
void Recorder::captureFunc(Mat *matRecorder, VideoCapture *webcamRecorder){
for(;;){
//capture from webcame to Mat frame
(*webcamRecorder) >> (*matRecorder);
resize(*matRecorder,matOut,Size(1280,720),0,0,INTER_LINEAR);
}
}
void Recorder::setup(){
if (!hasStarted){
this->start();
boost::thread captureThread(&Recorder::captureFunc, &matRecorder, &webcamRecorder);
}
}
void Recorder::run(){
cout << "++++++++recorder thread called+++" << endl;
theVideoWriter.open(filename+countAsString+ext,CV_FOURCC('L','A','G','S'), 30, Size(1280,720), true);
nextFrameTimestamp = microsec_clock::local_time();
currentFrameTimestamp = nextFrameTimestamp;
td = (currentFrameTimestamp - nextFrameTimestamp);
if ( theVideoWriter.isOpened() == false ){
cout << "ERROR: Failed to write the video" << endl;
}
if (recording){
while(recording){
hasStarted=true;
while(td.total_microseconds() < 1000000/30){
//determine current elapsed time
currentFrameTimestamp = microsec_clock::local_time();
td = (currentFrameTimestamp - nextFrameTimestamp);
}
// determine time at start of write
initialLoopTimestamp = microsec_clock::local_time();
theVideoWriter << matOut; // write video file
nextFrameTimestamp = nextFrameTimestamp + microsec(1000000/30);
td = (currentFrameTimestamp - nextFrameTimestamp);
finalLoopTimestamp = microsec_clock::local_time();
td1 = (finalLoopTimestamp - initialLoopTimestamp);
delayFound = td1.total_milliseconds();
cout << delayFound << endl;
}
}
hasStarted=false;
cout << "finished recording" << endl;
theVideoWriter.release();
recordingCount++;
countAsString = static_cast<ostringstream*>( &(ostringstream() << recordingCount) )->str();
}
void Recorder::setRecording(bool x){ recording = x;}
What is wrong with my implementation? Again the original code pieces are from here
The problem, and the difference between your case and the link you provided, is that you use an object method for the thread function. Specifically:
boost::thread captureThread(&Recorder::captureFunc, &matRecorder, &webcamRecorder);
An object method needs a pointer for this. Since you create the thread in an object method, you can use its this pointer:
boost::thread captureThread(&Recorder::captureFunc, this, &matRecorder, &webcamRecorder);
Some general suggestions:
You don't need boost for threads anymore. C++11 has it in its standard library. I suggest you use it if you can.
The thread you created becomes detached - it continues executing, but you can't control it. You probably want to save it somewhere, so you can join it later.
To have the thread as an instance variable:
Have the thread declared in the class definition: std::thread captureThread;.
Have it initialized in the current function, and moved to the instance variable:
std::thread localCaptureThread(&Recorder::captureFunc, this, &matRecorder, &webcamRecorder);
captureThread = std::move(localCaptureThread);
I'm trying to implement a threaded object like this:
#include <pthread.h>
#include <iostream>
class Thread
{
private:
int id;
static void * run(void * arg)
{
int tid = (int)arg;
std::cout << "Thread " << tid << " executed." <<std::endl;
pthread_exit(NULL);
}
public:
Thread(int _id);
void start();
int get_id();
};
Here's the implementation of the public methods & constructor:
#include "std_thread.h"
Thread::Thread(int _id)
{
id = _id;
}
void Thread::start()
{
std::cout << "Thread created." <<std::endl;
pthread_t thread;
int rc = pthread_create(&thread, NULL, run, (void*)id);
if(rc)
std::cout << "Return code from thread is " << rc;
}
int Thread::get_id()
{
return id;
}
And here's main:
#include "std_thread.h"
int main()
{
Thread *thd = new Thread(0);
thd->start();
return 0;
}
When I create the thread object and call its start method, which is in turn supposed to print "Thread created." and run the thread body - it doesn't; actually, it does print Thread created to console, but doesn't seem to create a thread, or the thread just doesn't do anything. Everything compiles fine by the way, and there no run time errors.
Any ideas?
Your main returns before the thread gets a chance to run.
The program doesn't wait until all threads are done before exiting - once main is over, it's over, and the process is just shut down.
Have your pthread_t thread; as a member instead of a local variable, and add a method to wait for the thread to finish.
This is the simplest example I can come up with:
void Thread::wait()
{
pthread_join(thread, NULL);
}
int main()
{
Thread thd(0); // There's no point in using dynamic allocation here.
thd.start();
thd.wait();
return 0;
}
I am playing around with some sockets, thread and mutexes. My question concerns threads and mutexes:
int ConnectionHandler::addNewSocket(){
this->connectionList_mutex.lock();
std::cout << "test1" << std::endl;
this->connectionList_mutex.unlock();
return 0;
}
int ConnectionHandler::main(){
while(true){
this->connectionList_mutex.lock();
std::cout << "test2" << std::endl;
this->connectionList_mutex.unlock();
}
}`
The main function is running in one thread, while the addNewSocket is called by another thread. The problem is, that when addNewSocket is called once (by the second thread), the next unlock by thread 1 (main) will fail with a strange "signal SIGABRT". I have worked two days on this now, but i did not manage to get it fixed, sadly. I hope you can help me.
Edit: ConnectionHandler is a class, that has connectionList_mutex as a member.
Edit: Sometimes i also get this error: "Assertion failed: (ec == 0), function unlock, file /SourceCache/libcxx/libcxx-65.1/src/mutex.cpp, line 44." but it occurs randomly.
Edit: This is the whole class (Reduced to a minimum, should be context independant to a certain degree, but crashes when i put it right after a client connected, and works if i put it right after the start:
class ConnectionHandler{
public:
ConnectionHandler();
int addNewSocket();
private:
int main();
static void start(void * pThis);
std::mutex connectionList_mutex;
};
ConnectionHandler::ConnectionHandler(){
std::thread t(&this->start, this);
t.detach();
}
void ConnectionHandler::start(void * pThis){
ConnectionHandler *handlerThis;
handlerThis = (ConnectionHandler *)pThis;
handlerThis->main();
}
int ConnectionHandler::addNewSocket(){
this->connectionList_mutex.lock();
std::cout << "test1" << std::endl;
this->connectionList_mutex.unlock();
return 0;
}
int ConnectionHandler::main(){
while(true){
this->connectionList_mutex.lock();
std::cout << "test2" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
this->connectionList_mutex.unlock();
}
}
My guess is that your ConnectionHandler object is being destroyed somewhere. Also, you have defined ConnectionHandler::start in a silly way.
First, ConnectionHandler::start should be defined this way:
void ConnectionHandler::start(ConnectionHandler * pThis){
pThis->main();
}
The C++11 ::std::thread class is perfectly capable of preserving the type of the function argument so there is no need to resort to void *.
Secondly, add in this code:
void ConnectionHandler::~ConnectionHandler(){
const void * const meptr = this;
this->connectionList_mutex.lock();
::std::cout << "ConnectionHandler being destroyed at " << meptr << ::std::endl;
this->connectionList_mutex.unlock();
}
And change the constructor to read:
ConnectionHandler::ConnectionHandler(){
const void * const meptr = this;
::std::cout << "ConnectionHandler being created at " << meptr << ::std::endl;
std::thread t(&this->start, this);
t.detach();
}
This will show you when the ConnectionHandler object is being destroyed. And my guess is that your code is destroying it while your detached thread is still running.
The meptr thing is because operator << has an overload for void * that prints out the pointer value. Printing out the pointer value for this will allow you to match up calls to the constructor and destructor if you're creating multiple ConnectionHandler objects.
Edit: Since it turned out I was correct, here is how I would recommend you write the play ConnectionHandler class:
#include <iostream>
#include <atomic>
#include <thread>
#include <chrono>
#include <mutex>
class ConnectionHandler {
public:
ConnectionHandler();
~ConnectionHandler();
ConnectionHandler(const ConnectionHandler &) = delete;
const ConnectionHandler &operator =(const ConnectionHandler &) = delete;
int addNewSocket();
private:
int main();
static void start(ConnectionHandler * pThis);
::std::mutex connectionList_mutex;
volatile ::std::atomic_bool thread_shutdown;
::std::thread thread;
};
ConnectionHandler::ConnectionHandler()
: thread_shutdown(false), thread(&this->start, this)
{
}
ConnectionHandler::~ConnectionHandler()
{
thread_shutdown.store(true);
thread.join();
}
void ConnectionHandler::start(ConnectionHandler * pThis){
pThis->main();
}
int ConnectionHandler::addNewSocket(){
::std::lock_guard< ::std::mutex> lock(connectionList_mutex);
::std::cout << "test1" << ::std::endl;
return 0;
}
int ConnectionHandler::main(){
while(!thread_shutdown.load()){
::std::lock_guard< ::std::mutex> lock(connectionList_mutex);
::std::cout << "test2" << ::std::endl;
::std::this_thread::sleep_for(::std::chrono::milliseconds(100));
}
return 0;
}
I am trying to write a program that is able to capture images from two different cameras in two different threads. I want to do this because when I do this in the same thread I have to keep waiting for cvQueryFrame twice the amount of time and so i can not grab images at 30 fps (I get 15 FPS from each camera).
I have taken a look at this SO post, but this only works for one camera. Using cvQueryFrame and boost::thread together
My current program gives varying results, sometimes it gives memory leaks, usually I just don't see anything happening and sometimes it worls for a few seconds but the the image freezes again. The strange thing is that earlier when I didn't call cvShowImage, but had my imageProcessing function do something useful I could see that I was getting real time results from both cameras. I assume this means that it is possible to make this work, but that I made a stupid mistake somewhere. My OS is LINUX and I am using OpenCV 2.4
My code:
#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;
}
EDIT:
I added a simple function to detect a piece of paper to see if everything is working fine when I don't call on cvShowImage(). My program can detect a piece of paper fine if I don't call cvShowImage(). If I do the program has strange behavior again and freezes etc.
There should only be one thread manipulating the GUI (this is true for just about any GUI framework). You should organize your code so that cvShowImage is only invoked from the main "GUI thread".
It seems that the work that's being done in query_thread could just as easily be done inside the main thread.