OpenCV camera capture from within a thread - c++

This is a small part of the code I'm trying to get to work. This is also one of my first times working with C++. I'm used to higher-level languages, like Java or C#.
The main version is meant to be run as a shared object or DLL. The idea is that an external program (in C#) will start the main loops. The frames from the camera will be captured in a thread. Information will processed inside of that thread and copied to an array ("dataArray"). This copy process will be done while a class mutex is locked. Then, another function called externally will copy that saved array ("dataArray") to a second array ("outArray") and return a pointer to the second array. The external program will use the pointer to copy the data from the second Array, which will not be modified until the function is called again.
But for all that to work, I need the frames to constantly be captured. I realized that I needed something to keep my main function going, so I'm keeping an infinite loop in there. In the "real" version, the keepRunning variable will be changed by the external program running the library.
I was recently lectured on StackOverflow about not making global variables, so I'm keeping the one instance of my class in a static member. That's pretty standard in Java. I don't know if it's bad practice in C++. I was also taken by surprise as to how C++ threads start as soon as they're created, without an explicit "start" instructions. That's why I'm putting my only thread in a vector. That seems to be what most people recommend.
I understand that without keepRunning never being actually changed, the threads will never be joined, but I'll dear with that later. I'm running this on a Mac, but I'll need it to eventually run on Windows, Mac and Linux.
Here's my header:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <thread>
#include <vector>
using namespace cv;
using namespace std;
class MyCap {
public:
MyCap();
VideoCapture cap;
static MyCap * instance;
void run();
static void RunThreads(MyCap * cap);
bool keepRunning = true; // Will be changed by the external program.
vector<thread> capThreads;
private:
Mat frame;
};
And here's my code:
#include "theheader.h"
MyCap * MyCap::instance = NULL;
int main(int argc, char** argv) {
MyCap::instance = new MyCap();
MyCap::instance->capThreads.push_back(thread(MyCap::RunThreads, MyCap::instance));
// Outside loop.
while(MyCap::instance->keepRunning) {
}
for (int i = 0; i < MyCap::instance->capThreads.size(); i++) {
MyCap::instance->capThreads[i].join();
}
}
MyCap::MyCap() {
namedWindow("flow", 1);
cap.open(0);
}
void MyCap::RunThreads(MyCap * cap) {
cap->run();
}
void MyCap::run() {
// Inside loop.
while(keepRunning) {
cap >> frame;
imshow("flow", frame);
if (waitKey(30) >= 0) {
break;
}
}
}
With this code, I get a black screen. If I run cap.open(0) from within the run method, I don't even get that. I'm obviously doing something very wrong. But what really puzzles me is: why does it make a difference where that same code is called from? If I run what is now in run inside of main it will work. If I change the call of cap.open(0) from the constructor to run, that changes what the method does. Also the waitKey condition stops working from within the thread. What big thing am I missing?
Version 2
Based on the suggestions of #darien-pardibas, I made this second version:
Header:
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <thread>
#include <vector>
using namespace cv;
using namespace std;
class MyCap {
public:
MyCap();
void run();
bool keepRunning = true; // Will be changed by the external program.
static void RunThreads(MyCap * cap);
static vector<thread> capThreads;
static MyCap * getInstance();
private:
static MyCap * instance;
};
The main file:
#include "theprogram.h" // I'll admit that, even for a placeholder, it was a bad name.
MyCap * MyCap::instance = NULL;
vector<thread> MyCap::capThreads;
MyCap::MyCap() {
cout << "Instantiate" << endl;
}
MyCap * MyCap::getInstance() {
if (MyCap::instance == NULL) {
MyCap::instance = new MyCap;
}
return MyCap::instance;
}
void MyCap::RunThreads(MyCap * cap) {
cap->run();
}
void MyCap::run() {
cout << "Run" << endl;
namedWindow("flow", 1);
cout << "Window created." << endl;
VideoCapture cap(0); // HANGS HERE!
cout << "Camera open." << endl; // This never gets printed.
// Inside loop.
Mat frame;
while(keepRunning) {
cap >> frame;
imshow("flow", frame);
if (waitKey(30) >= 0) {
break;
}
}
}
int main(int argc, char** argv) {
MyCap::capThreads.push_back(thread(&MyCap::RunThreads, MyCap::getInstance()));
for (int i = 0; i < MyCap::capThreads.size(); i++) {
MyCap::capThreads[i].join();
}
}
This prints:
Instantiate
Run
Window created.
And hangs there.
But if I move the code from run to main and change keepRunning to true, then it works as expected. I think I'm missing something else, and I'm guessing it has something to do with how C++ works.

Okay, without looking at resolving all design patterns issues I can see in your code, I can confirm that the code below works. I think the main problem was that you needed to create the namedWindow in the same thread where you will be capturing the image and remove the while loop you had in your main method.
// "theheader.h"
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <thread>
#include <vector>
class MyCap {
public:
void run();
static void RunThreads(MyCap * cap);
bool keepRunning = true; // Will be changed by the external program.
std::vector<std::thread> capThreads;
private:
cv::Mat frame;
cv::VideoCapture cap;
MyCap() { }
static MyCap * s_instance;
public:
static MyCap *instance();
};
// "theheader.cpp"
#include "theheader.h"
#pragma comment(lib, "opencv_core248d")
#pragma comment(lib, "opencv_highgui248d")
using namespace std;
using namespace cv;
MyCap * MyCap::s_instance = NULL;
MyCap* MyCap::instance() {
if (s_instance == NULL)
s_instance = new MyCap();
return s_instance;
}
void MyCap::RunThreads(MyCap * cap) {
cap->run();
}
void MyCap::run() {
namedWindow("flow", 1);
cap.open(0);
// Inside loop.
while (keepRunning) {
cap >> frame;
imshow("flow", frame);
if (waitKey(30) >= 0) {
break;
}
}
}
int main(int argc, char** argv) {
MyCap::instance()->capThreads.push_back(thread(&MyCap::RunThreads, MyCap::instance()));
for (int i = 0; i < MyCap::instance()->capThreads.size(); i++) {
MyCap::instance()->capThreads[i].join();
}
}

Related

I am having trouble to utilize a WindowsForms method in a different thread (C++)

Sorry for my english, if something is not clear, please ask me. I am having trouble to make that application for WindowsForms ("ThreadTeste" is a representation of "MyForm1"):
#include <chrono>
#include <iostream>
#include <thread>
using namespace std;
using namespace std::chrono;
class ThreadTeste
{
public:
void loop()
{
for(int i = 0 ; i < 5 ; i++)
{
cout << i << endl;
this_thread::sleep_for(seconds(1));
}
}
thread getThread()
{
return thread(&ThreadTeste::loop, this);
}
ThreadTeste()
{
thread myThread = getThread();
myThread.detach();
}
};
int main(int argc, char *argv[])
{
ThreadTeste* t = new ThreadTeste();
while(true)
{
cout << "Working" << endl;
this_thread::sleep_for(seconds(1));
}
}
//That works!!
D:
If you want to output from 0 to 4 and then output working, then you could not use detach. Because detach means that the main thread does not need to wait for the execution of the child thread to complete and the two are out of relationship,then it will run by itself.
You could use join.
ThreadTeste()
{
thread myThread = getThread();
myThread.join();
}

No sound when using SDL_Mixer in C++/Linux

I'm trying to use SDL_mixer in C++ under Linux to play sounds asynchronously, but it somehow doesn't work. When I execute it, no sound is playing at all. I'm not quite familiar with SDL and classes though, so it would be very helpful if someone could detect where the error in my code is.
My header file (sample.h):
#pragma once
#include <string>
#include <memory>
#include "SDL_mixer.h"
class sample {
public:
sample(const std::string &path, int volume);
void play();
void play(int times);
void set_volume(int volume);
private:
std::unique_ptr<Mix_Chunk, void (*)(Mix_Chunk *)> chunk;
};
My main program (.cpp):
#include "sample.h"
#include <iostream>
sample::sample(const std::string &path, int volume) : chunk(Mix_LoadWAV(path.c_str()), Mix_FreeChunk) {
if (!chunk.get()) {
std::cout << "Could not load audio sample: " << path << std::endl;
}
Mix_VolumeChunk(chunk.get(), volume);
}
void sample::play() {
Mix_PlayChannel(-1, chunk.get(), 0);
}
void sample::play(int times) {
Mix_PlayChannel(-1, chunk.get(), times - 1);
}
void sample::set_volume(int volume) {
Mix_VolumeChunk(chunk.get(), volume);
}
int main() {
if (Mix_Init(MIX_INIT_FLAC | MIX_INIT_MP3 | MIX_INIT_OGG) < 0) {
return -1;
}
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024) < 0) {
std::cout << "Can not initialize mixer!" << std::endl;
return -1;
}
// Amount of channels (Max amount of sounds playing at the same time)
Mix_AllocateChannels(32);
sample s("Snare-Drum-1.wav", MIX_MAX_VOLUME / 2);
s.play();
Mix_Quit();
return 0;
}
Your binary runs and finishes before phaffing about long enough to render the audio so solution is to make the code remain running longer ... I got your code working by adding this
s.play();
std::chrono::milliseconds timespan(2000); // or whatever
std::this_thread::sleep_for(timespan);
in your header replace
#include "SDL_mixer.h"
with
#include <SDL2/SDL_mixer.h>
#include <chrono>
#include <thread>
so now its compiled using SDL2 and not SDL
g++ -o sample sample.cpp -lSDL2 -lSDL2_mixer
So .... what is the real SDL2 solution ? well I would say a typical use case is SDL2 is part of a game which remains running hence the code base has an event loop which remains active long enough to hear the audio getting rendered. Another solution short of explicitly using a sleep or a gui is to put the code into a server ... SDL2 api itself must have their one-liner as well

Handle threads between classes with C++, libvlc and ubuntu

I have an application in C++ with a GUI interface that needs to reproduce some mp3 depending on user's interactions. I need to reproduce the mp3 without blocking the program's flow.
In order to save code, I decided to write a class to handle the mp3 reproducing and to reproduce it in a new thread, but I'm having problems when I need to stop the playing.
I know that libvlc have already some locking function, but the flow of the program stops when the mp3 is playing.
The mp3 starts correctly, but if I try to call the stop_mp3() function, I get a core dumped error.
The error is generated when I call the stop function from the secondpanel.cpp.
// replay.h
#include <vlc/vlc.h>
class rePlay
{
public:
rePlay();
virtual ~rePlay();
void play_mp3(const char*);
void stop_mp3();
protected:
libvlc_instance_t *inst;
libvlc_media_player_t *mp;
libvlc_media_t *m;
private:
};
// rePlay.cpp
#include "rePlay.h"
#include <vlc/vlc.h>
#include <mutex>
std::mutex mp3_mutex;
rePlay::rePlay()
{
//ctor
}
rePlay::~rePlay()
{
//dtor
}
void rePlay::play_mp3(const char* path){
mp3_mutex.lock();
// load the vlc engine
inst = libvlc_new(0, NULL);
printf("apro il file %d\n", inst);
// create a new item
m = libvlc_media_new_path(inst, path);
// create a media play playing environment
mp = libvlc_media_player_new_from_media(m);
// no need to keep the media now
libvlc_media_release(m);
// play the media_player
libvlc_media_player_play(mp);
printf("Done.\n");
}
void rePlay::stop_mp3(){
mp3_mutex.unlock();
// stop playing
libvlc_media_player_stop(mp);
// free the media_player
libvlc_media_player_release(mp);
libvlc_release(inst);
}
// firstpanel.h
class firstpanel: public wxPanel
{
public:
firstpanel(wxWindow* parent, Isola02Frame*, wxWindowID id=wxID_ANY,const wxPoint& pos=wxDefaultPosition,const wxSize& size=wxDefaultSize);
virtual ~firstpanel();
void checkValue(wxCommandEvent& event);
void check_cf(wxTimerEvent& event);
rePlay *mp3_apertura_porta = new rePlay(); // <-- I DECLARED THE pointer here
//(*Declarations(firstpanel)
wxStaticText* assistenza;
wxStaticText* first_panel;
wxStaticText* identificazione;
wxTextCtrl* tessera;
//*)
...
}
// firstpanel.cpp
std::thread second = std::thread([this]() noexcept {
this->mp3_apertura_porta->play_mp3("/home/robodyne/Project/audio/scegli-rifiuto.mp3"); });
second.join();
// secondpanel.cpp
void secondpanel::OnBitmapButton2Click(wxCommandEvent& event)
{
firstpanel *ptr;
ptr->mp3_apertura_porta->stop_mp3();
}
EDIT1: Thanks to #Ted Lyngmo, I used the libvlcpp library which seems to be async somehow and it works fine. The only problem is that I do not know how to call mp.stopAsync() from stop_mp3() to stop the audio file because variable mp is not global.
#include "rePlay.h"
#include <vlc/vlc.h>
#include <mutex>
#include <unistd.h>
#include "vlcpp/vlc.hpp"
std::mutex mp3_mutex;
rePlay::rePlay()
{
//ctor
}
rePlay::~rePlay()
{
//dtor
}
void rePlay::play_mp3(const char* path){
auto instance = VLC::Instance(0, nullptr);
auto media = VLC::Media(instance, path, VLC::Media::FromPath);
auto mp = VLC::MediaPlayer(media);
auto mp.play();
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(4, 0, 0, 0)
#else
mp.stop();
#endif
}
void rePlay::stop_mp3(){
mp.stopAsync(); <-- variable mp is not global!
}
EDIT2:
I think the libvlcpp doesn't work well with GUI applications.
If I run it in a console application, I'm able to perform other operations in parallel, but when I execute it in the WxWidgets application, it blocks the flow.
This is the terminal console application:
#include "vlcpp/vlc.hpp"
#include <thread>
#include <iostream>
int main(int ac, char** av)
{
if (ac < 2)
{
std::cerr << "usage: " << av[0] << " <file to play>" << std::endl;
return 1;
}
auto instance = VLC::Instance(0, nullptr);
auto media = VLC::Media(instance, av[1], VLC::Media::FromPath);
auto mp = VLC::MediaPlayer(media);
mp.play();
for (int i=0; i < 10000000; i++){
printf("%d\n", i);
}
std::this_thread::sleep_for( std::chrono::seconds( 10 ) );
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(4, 0, 0, 0)
mp.stopAsync();
#else
mp.stop();
#endif
}
the for() cycle works in parallel while the mp3 is playing.
The same doesn't happen if I use it with my application.

C++: creating an event repeatedly called by timer

I wanted to redo a Conway's Game of Life thing I did in Java, but this time use ncurses and C++. Obviously I need a timed event so I can run out the simulation at a rate which it can be viewed. Turns out it is a hell of a lot harder to make a timed event in C++ than it is in Java. I am not as experienced in C++ than I am in Java. I have already looked around online, and what I found led me to the code I have below. Upon executing it produces no result in the terminal. What exactly am I doing wrong?
main.cpp:
#include <iostream>
#include <functional>
#include <chrono>
#include <future>
#include <cstdio>
using namespace std;
class callBackTimer //no idea how this works, got it from Stack Overflow thread
{
public:
callBackTimer()
:_execute(false)
{}
void start(int interval, std::function<void(void)> func)
{
_execute = true;
std::thread([=]()
{
while (_execute)
{
func();
std::this_thread::sleep_for(
std::chrono::milliseconds(interval));
}
}).detach();
}
void stop()
{
_execute = false;
}
private:
bool _execute;
};
void timerExec()
{
cout << "SNAFU" << endl;
}
int main(int argc, const char * argv[])
{
callBackTimer timer; //declare the timer
std::function<void(void)> exec = timerExec; //declare a pointer to timerExec
timer.start(25, std::bind(exec)); //start the timer
return 0;
}
You need to wait for the thread to finish what it is doing, which is usually accomplished by calling join(). So maybe something like this:
#include <iostream>
#include <functional>
#include <chrono>
#include <future>
#include <cstdio>
using namespace std;
class callBackTimer //no idea how this works, got it from Stack Overflow thread
{
public:
callBackTimer()
:_execute(false)
{}
void setup(int interval, std::function<void(void)> func)
{
_execute = true;
thread = std::thread([=]()
{
// while (_execute)
for (int steps = 0; steps < 100; ++steps)
{
func();
std::this_thread::sleep_for(std::chrono::milliseconds(interval));
}
});
}
void stop()
{
_execute = false;
}
void run()
{
thread.join();
}
private:
bool _execute;
std::thread thread;
};
void timerExec()
{
cout << "SNAFU" << endl;
}
int main(int argc, const char * argv[])
{
callBackTimer timer; //declare the timer
std::function<void(void)> exec = timerExec; //declare a pointer to timerExec
timer.setup(25, std::bind(exec)); //start the timer
timer.run();
return 0;
}
Calling detach() is OK, but you have to make main() wait for the thread manually. You also need a condition to break out of the while loop, otherwise it will go on forever. Hope that helps!

Visual Studio 2010 OpenCV Multithread Mat does not copy to another Mat

Good afternoon to all!
I've been using Visual Studio 2010 with OpenCV to develop a code for Face recognition. I'm trying to reach the task by two Threads (I need to do it this way, because i´m going to apply it on a bigger project), one (the main) to show the frames and the second to capture (from the Webcam of my laptop) and store the frames on a Mat object (Fast Capture).
The inconvenient here is that the second Thread is capturing the frames, but the main is not showing them. I think there is a problem with copying the Mat from the capture Thread to the Mat on the main thread ("current_frame" seems to be empty after I do the assignation)
Here is the code (I'm using Boost::Thread for Multithreading)
New code with suggestions
Global declarations
#include <iostream>
#include <stdio.h>
#include <boost\thread.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
boost::mutex mtx;
The function
void camCapture(VideoCapture& cap, Mat& frame, bool* Capture)
{
while (*Capture==true)
{
mtx.lock();
cap >> frame;
mtx.unlock();
if(frame.empty())
{
cout<<"No hay captura"<<endl;
}
else
{
cout<<"Frame capturado"<<endl;
}
}cout << "camCapture finished\n";
return;}
The main
int main() {
try{
VideoCapture cap(0); // open the default camera
Mat frame,current_frame, SFI, Input;
bool *Capture = new bool;
*Capture = true;
if (!cap.isOpened()) // check if we succeeded
return -1;
//your capture thread has started
boost::thread captureThread(camCapture, cap, frame, Capture);
while(1)
{
if(frame.empty())
{
cout<<"Frame en hilo principal vacio"<<endl;
}
else{
cout<<"Frame en hilo principal capturado"<<endl;
}
mtx.lock();
current_frame = frame.clone();
mtx.unlock();
if(current_frame.empty())
{
cout<<"Current_Frame vacio"<<endl;
}
else{
imshow("Streaming",current_frame);
if(waitKey(10)==27)break;
}
}
//Terminate the thread
captureThread.join();
}
catch(Exception & e)
{
cout<<e.what()<<endl;
}
return 0;}
according to Boost threads - passing parameters by reference you have to use boost::ref(v) if you want to pass a variable by reference to a boost::thread function. But you could use pointers instead.
In addition you should share the mutex to the thread by passing it as pointer or reference variable instead of using it as global:
#include <iostream>
#include <stdio.h>
#include <boost/thread.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
boost::mutex mtx;
void camCapture(VideoCapture& cap, Mat& frame, bool* Capture)
{
while (*Capture == true)
{
mtx.lock();
cap >> frame;
mtx.unlock();
if (frame.empty())
{
cout << "No hay captura" << endl;
}
else
{
cout << "Frame capturado" << endl;
}
}cout << "camCapture finished\n";
return;
}
int main() {
try{
VideoCapture cap(0); // open the default camera
Mat frame, current_frame, SFI, Input;
bool *Capture = new bool; // better not use a pointer here, but use a bool and pass the address or by reference.
*Capture = true;
if (!cap.isOpened()) // check if we succeeded
return -1;
//your capture thread has started
boost::thread captureThread(camCapture, boost::ref(cap), boost::ref(frame), Capture);
while (1)
{
mtx.lock();
current_frame = frame.clone();
mtx.unlock();
if (current_frame.empty())
{
cout << "Current_Frame vacio" << endl;
}
else{
imshow("Streaming", current_frame);
if (waitKey(10) == 27)
{
// TODO: you should use a mutex (or an atomic type) here, too, maybe setting a bool is thread-safe, but this can't be guaranteed for each hardware!
*Capture = false;
break;
}
}
}
//Terminate the thread
captureThread.join();
// give memory free:
delete Capture;
}
catch (Exception & e)
{
cout << e.what() << endl;
}
return 0;
}