OpenCV - imshow зависает, если вызывается два раза из потока - PullRequest
1 голос
/ 18 марта 2020

всех.

Я пытаюсь создать отдельный поток для отображения и обработки изображений, поступающих с веб-камеры. Эти операции не могут быть в главном потоке, так как он предназначен для других задач. Что мне нужно сделать, это остановить и перезапустить поток.

Что происходит, когда поток работает в первый раз, но при втором запуске вызов imshow останавливается навсегда.

I воспроизвел проблему с простым примером, отклоненным от другого вопроса SO ( cv :: imshow не отображает цвет cv :: mat при работе в другом потоке )

нерабочий многопоточный код

#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;
}

рабочий однопоточный код

#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;
}

есть ли причина, по которой фрагмент 1 не должен работать?

Спасибо,

Marco

edit

Кажется, что оба фрагмента работают с использованием opencv3.x из репозитория. Сбой с opencv4.x, скомпилированной с нуля на Xubuntu 19.04.

1 Ответ

0 голосов
/ 18 марта 2020

Все элементы пользовательского интерфейса должны оставаться в главном потоке! Это проблема, вызывающая эту проблему. Вы не можете использовать пользовательский интерфейс в другом потоке, например waitKey(), imshow() et c.

Также вы пытаетесь остановить таймер из другого потока, это также другая проблема.

Вот темы, в которых упоминается та же проблема:

Пост1

Пост2

Post3

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...