3

everybody.

I'm trying to have a separate thread to display and process images coming from a webcam. Those operations cannot be in the main thread, since it's dedicated to other tasks. What I need to do is to stop and eventually restart the thread.

What happens is that the thread works the very first time, but at the second run the imshow call freezes forever.

I reproduced the problew with a simple example deviated from another SO question (cv::imshow does not display cv::mat color when on different thread)

non working multithread code

#include <opencv2/opencv.hpp>
#include <thread>
#include <string>

using namespace std;
using namespace cv;

class Capture {
private:
    bool running;

    std::thread thread;
    cv::Mat background;
    void loop() {

        while (running) {
            cv::imshow(windowName, background);  // at the second time the thread is started this instruction will hang
            cv::waitKey(500);
            Scalar color(rand()&255, rand()&255, rand()&255);
            background.setTo(color);
        }
     cv::destroyWindow(windowName);
    cv::waitKey(1);
    }
public:
    char windowName[128];
    Capture() :
    windowName{"test"},
    running{ false },
        thread{},
        background{ 800, 800, CV_8UC3, cv::Scalar{ 255, 0, 255 } } {
    }
    inline ~Capture() {
        if (running) stop(); // stop and join the thread
    }
    void run() {
        if (!running) {
            running = true;
            thread = std::thread{ &Capture::loop, this };
        }
    }
    inline void join() { if (thread.joinable()) thread.join(); };
    inline void stop() {
        running = false;
        if (thread.joinable()) {
            thread.join();
        }
    }
};

int main()
{
    Capture cap;
    // run the thread one time
    cap.run();
    std::this_thread::sleep_for(std::chrono::milliseconds(2500));
    cap.stop();
    // wait
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    // run again
    cap.run(); //stuck!!!
    std::this_thread::sleep_for(std::chrono::milliseconds(2500));
    cap.stop();

    return 0;
}

working singlethread code

#include <opencv2/opencv.hpp>
#include <thread>
#include <string>

using namespace std;
using namespace cv;

int main()
{
    Scalar color(rand()&255, rand()&255, rand()&255);
    cv::Mat background(800, 800, CV_8UC3, cv::Scalar{ 255, 0, 255 }) ;
    background.setTo(color);
    // try the first time to display an image
    for (int i=0; i<5; i++)
    {
    cv::imshow("test", background);
        cv::waitKey(500);
        color=(rand()&255, rand()&255, rand()&255);
        background.setTo(color);
    }
    // destroy the image
    cv::destroyWindow("test");

    // repeat the same as before
    for (int i=0; i<5; i++)
    {
    cv::imshow("test", background);
        cv::waitKey(500);
        color=(rand()&255, rand()&255, rand()&255);
        background.setTo(color);
    }
    cv::destroyWindow("test");
    // it worked !
    return 0;
}

is there any reason why snippet #1 should not be working?

Thanks,

Marco

edit

It seems that both the snippets work using opencv3.x from the repository. It fails with opencv4.x compiled from scratch on Xubuntu 19.04.

  • there's nothing wrong with the multithreaded version, except for 'wi**non working multithread code**ndowName' :). It seems to work ok. I would however add some synchronization when updating the state, although there should be no issue in your particular example. On what os are you trying the example? – Nicolae Natea Mar 18 '20 at 11:23
  • D'ho!! mi finger slipped... Apart form that i have tested it on Xubuntu 19.04, i compiled myself the opencv libraries (version 4 i guees). I may try to link the ones in the repository, thanks for your help! – Marco.Venturini Mar 18 '20 at 12:22
  • AFAIK, `imshow()` is just a quick 'n' easy way to show an image during debugging. It is not production quality code. If you want a sophisticated, multi threaded GUI you need to write some `Tkinter`, or `Qt` or `wxwidgets`. – Mark Setchell Mar 18 '20 at 21:11

1 Answers1

2

All the UI things should stay on the main thread! Thats the problem causing that problem. You can not use UI stuff on an another thread like waitKey(), imshow() etc.

Also you are trying to stop a timer from another thread, this is also an another problem.

Here are the topics mentioning same issue:

Post1

Post2

Post3

Yunus Temurlenk
  • 4,085
  • 4
  • 18
  • 39