2

This is a class I use to spawn a HighGui window with some content on different thread.

class Capture {
private:
  bool running;
  std::thread thread;
  cv::Mat background;
  void loop() {
    while (running) {
      cv::imshow("sth",background);
      cv::waitKey(settings::capture_wait_time);
    }
  }
  public:
   Capture()  :
     running {false},
     thread {},
     background { 800, 800,  CV_8UC3, cv::Scalar{255,0,255}} {
       cv::namedWindow("sth");  
   }
   inline ~Capture() {
     if (running) stop(); // stop and join the thread
     cv::destroyWindow("sth");
   }
   void run() {
     if (!running) {
       running = true;
       thread = std::thread{[this]{loop();}};
     }
   }
   inline void join() { if (thread.joinable()) thread.join(); };
   inline void stop() {
     running = false;
     if (thread.joinable()) thread.join();
   }
};

// main
Capture cap;
cap.run();
// ... 

The problem is that the window will always end up being black (in this case it should be purple). I am obviously missing something here....

Marinos K
  • 1,779
  • 16
  • 39
  • try to create the windows un the main thread with cv::namedWindow – Micka Feb 04 '16 at 06:55
  • the window is created in the main thread: Capture's constructor is called in my main (this is where the window is being created), then, Capture::run spawns a new thread. – Marinos K Feb 04 '16 at 08:40
  • what's the difference between CAPTURE_WINDOW_NAME and "sth"? – Micka Feb 04 '16 at 08:45
  • none, sorry I've edited the original – Marinos K Feb 04 '16 at 10:49
  • can you adf a cout before imshow, one after imshow and one cout after waitKey to check whether it is frozen there or whether it's just not displaying? – Micka Feb 04 '16 at 10:51

1 Answers1

2

It seems that you cannot create a window in another thread. Also, the way you're calling the member function on the other thread seems wrong.

Have a look at this code. It displays an image that change every second in a different thread, and returns after 5 seconds.

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

using namespace std;
using namespace cv;

class Capture {
private:
    bool running;
    std::thread thread;
    cv::Mat background;
    void loop() {

        while (running) {
            cv::imshow("sth", background);
            cv::waitKey(1000);

            Scalar color(rand()&255, rand()&255, rand()&255);
            background.setTo(color);
        }
    }
public:
    Capture() :
        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;
    cap.run();

    std::this_thread::sleep_for(std::chrono::milliseconds(5000));

    cap.stop();

    return 0;
}
Miki
  • 40,887
  • 13
  • 123
  • 202
  • any particular reason why cv::namedWindow has disappeared from the Ctor? I reckon it's just a typo right? – Marinos K Feb 04 '16 at 08:54
  • No, it's not a typo. It doesn't work if you use a window created in a different thread. – Miki Feb 04 '16 at 09:05
  • so where should I put it? within loop()? btw, the code in my next answer (where cv::nameWindow is in the Ctor) does work: – Marinos K Feb 04 '16 at 10:59
  • 1
    My code is not carved in stone, you can change it as you need. It solves the original problem of not showing the purple window. That's it. – Miki Feb 04 '16 at 11:11
  • just to report that when cv::namedWindow is added on the loop, it does work. I'll add this to your code, so that it compiles. – Marinos K Feb 04 '16 at 11:51