Marco.Venturini
Marco.Venturini

Reputation: 71

OpenCV - imshow hangs if called two times from a thread

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.

Upvotes: 3

Views: 3208

Answers (1)

Yunus Temurlenk
Yunus Temurlenk

Reputation: 4352

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

Upvotes: 2

Related Questions