Commit ead4a56ac9bbec8cfa15e917cbd85b1b416d41fe

Authored by Charles Otto
1 parent d4d04907

Slight reorganization and comment update in gui.cpp

Clearly obtuse solutions to obtuse problems deserve top billing.
Showing 1 changed file with 114 additions and 69 deletions
openbr/plugins/gui.cpp
@@ -18,6 +18,109 @@ using namespace cv; @@ -18,6 +18,109 @@ using namespace cv;
18 18
19 namespace br 19 namespace br
20 { 20 {
  21 +// Generally speaking, Qt wants GUI objects to be on the main thread, and
  22 +// for the main thread to be in an event loop. We don't restrict transform
  23 +// creation to just the main thread, but in br we do compromise and put
  24 +// the main thread in an event loop (and so should any applications wanting to
  25 +// use GUI transforms). This does mean we need a way to make our QWidget subclasses
  26 +// on the main thread. We can't create them from an arbitrary thread, then move them
  27 +// (you know, since that would be crazy), so we need some tricks to get the main
  28 +// thread to make these objects.
  29 +
  30 +// Part 1. A generic interface for creating objects, the type of object
  31 +// created is not exposed in the interface.
  32 +class NominalCreation
  33 +{
  34 +public:
  35 + virtual ~NominalCreation() {}
  36 + virtual void creation()=0;
  37 +};
  38 +
  39 +// Part 2. A template class that creates an object of the specified type
  40 +// through the interface defined in part 1. The point of this is that the
  41 +// type of object created can be hidden by using a NominalCreation *.
  42 +template<typename T>
  43 +class ActualCreation : public NominalCreation
  44 +{
  45 +public:
  46 + T * basis;
  47 +
  48 + void creation()
  49 + {
  50 + basis = new T();
  51 + }
  52 +};
  53 +
  54 +// Part 3. A class that inherits from QObject, but not QWidget. This means
  55 +// we are free to move it to the main thread.
  56 +// If this object is on the main thread, and we signal one of its slots, then
  57 +// the slot will be executed by the main thread, which is what we need.
  58 +// Unfortunately, since it uses Q_OBJECT we cannot make it a template class, but
  59 +// we still want to be able to make objects of arbitrary type on the main thread,
  60 +// so that we don't need a different adaptor for every type of QWidget subclass we use.
  61 +class MainThreadCreator : public QObject
  62 +{
  63 + Q_OBJECT
  64 +public:
  65 +
  66 + MainThreadCreator()
  67 + {
  68 + this->moveToThread(QApplication::instance()->thread());
  69 + // We actually bind a signal on this object to one of its own slots.
  70 + // the signal will be emitted by a call to getItem from an abitrary
  71 + // thread.
  72 + connect(this, SIGNAL(needCreation()), this, SLOT(createThing()), Qt::BlockingQueuedConnection);
  73 + }
  74 +
  75 + // While this cannot be a template class, it can still have a template
  76 + // method. Which is useful, but the slot which will actually be executed
  77 + // by the main thread cannot be a template. So, we use the template method
  78 + // here (called from an arbitrary thread, to create an object of arbitrary type)
  79 + // to instantiate an ActualCreation object with matching type, then we hide
  80 + // the template with the NominalCreation interface, and call worker->creation
  81 + // in the slot.
  82 + template<typename T>
  83 + T * getItem()
  84 + {
  85 + // If this is called by the main thread, we can just create the object
  86 + // it's important to check, otherwise we will have problems trying to
  87 + // wait for a blocking connection that is supposed to be processed by
  88 + // the thread that is waiting.
  89 + if (QThread::currentThread() == QApplication::instance()->thread())
  90 + return new T();
  91 +
  92 + // Create the object creation interface
  93 + ActualCreation<T> * actualWorker;
  94 + actualWorker = new ActualCreation<T> ();
  95 + // hide it
  96 + worker = actualWorker;
  97 +
  98 + // emit the signal, we set up a blocking queued connection, so
  99 + // this is a blocking wait for the slot to finish being run.
  100 + emit needCreation();
  101 +
  102 + // collect the results, and return.
  103 + T * output = actualWorker->basis;
  104 + delete actualWorker;
  105 + return output;
  106 + }
  107 +
  108 + NominalCreation * worker;
  109 +
  110 +signals:
  111 + void needCreation();
  112 +
  113 +public slots:
  114 + // The actual slot, to be run by the main thread. The type
  115 + // of object being created is not, and indeed cannot, be exposed here
  116 + // since this cannot be a template method, and the class cannot be a
  117 + // template class.
  118 + void createThing()
  119 + {
  120 + worker->creation();
  121 + }
  122 +};
  123 +
21 QImage toQImage(const Mat &mat) 124 QImage toQImage(const Mat &mat)
22 { 125 {
23 // Convert to 8U depth 126 // Convert to 8U depth
@@ -280,75 +383,6 @@ private: @@ -280,75 +383,6 @@ private:
280 383
281 }; 384 };
282 385
283 -// I want a template class that doesn't look like a template class  
284 -class NominalCreation  
285 -{  
286 -public:  
287 - virtual ~NominalCreation() {}  
288 - virtual void creation()=0;  
289 -};  
290 -  
291 -// Putting the template on a subclass means we can maintain a pointer that  
292 -// doesn't include T in its type.  
293 -template<typename T>  
294 -class ActualCreation : public NominalCreation  
295 -{  
296 -public:  
297 - T * basis;  
298 -  
299 - void creation()  
300 - {  
301 - basis = new T();  
302 - }  
303 -};  
304 -  
305 -// We want to create a QLabel subclass on the main thread, but are running in another thread.  
306 -// We cannot move QWidget subclasses to a different thread (obviously that would be crazy), but  
307 -// we can create one of these, and move it to the main thread, and then use it to create the object  
308 -// we want.  
309 -// Additional fact: QObject subclasses cannot be template classes.  
310 -class MainThreadCreator : public QObject  
311 -{  
312 - Q_OBJECT  
313 -public:  
314 -  
315 - MainThreadCreator()  
316 - {  
317 - this->moveToThread(QApplication::instance()->thread());  
318 -  
319 - connect(this, SIGNAL(needCreation()), this, SLOT(createThing()), Qt::BlockingQueuedConnection);  
320 - }  
321 -  
322 - // While this cannot be a template class, it can still have a template method.  
323 - template<typename T>  
324 - T * getItem()  
325 - {  
326 - if (QThread::currentThread() == QApplication::instance()->thread())  
327 - return new T();  
328 -  
329 - ActualCreation<T> * actualWorker;  
330 - actualWorker = new ActualCreation<T> ();  
331 - worker = actualWorker;  
332 -  
333 - emit needCreation();  
334 -  
335 - T * output = actualWorker->basis;  
336 - delete actualWorker;  
337 - return output;  
338 - }  
339 -  
340 - NominalCreation * worker;  
341 -  
342 -signals:  
343 - void needCreation();  
344 -  
345 -public slots:  
346 - void createThing()  
347 - {  
348 - worker->creation();  
349 - }  
350 -};  
351 -  
352 /*! 386 /*!
353 * \ingroup transforms 387 * \ingroup transforms
354 * \brief Displays templates in a GUI pop-up window using QT. 388 * \brief Displays templates in a GUI pop-up window using QT.
@@ -666,6 +700,11 @@ public: @@ -666,6 +700,11 @@ public:
666 BR_REGISTER(Transform, SurveyTransform) 700 BR_REGISTER(Transform, SurveyTransform)
667 701
668 702
  703 +/*!
  704 + * \ingroup transforms
  705 + * \brief Limits the frequency of projects going through this transform to the input targetFPS
  706 + * \author Charles Otto \cite caotto
  707 + */
669 class FPSLimit : public TimeVaryingTransform 708 class FPSLimit : public TimeVaryingTransform
670 { 709 {
671 Q_OBJECT 710 Q_OBJECT
@@ -716,6 +755,12 @@ protected: @@ -716,6 +755,12 @@ protected:
716 }; 755 };
717 BR_REGISTER(Transform, FPSLimit) 756 BR_REGISTER(Transform, FPSLimit)
718 757
  758 +/*!
  759 + * \ingroup transforms
  760 + * \brief Calculates the average FPS of projects going through this transform, stores the result in AvgFPS
  761 + * Reports an average FPS from the initialization of this transform onwards.
  762 + * \author Charles Otto \cite caotto
  763 + */
719 class FPSCalc : public TimeVaryingTransform 764 class FPSCalc : public TimeVaryingTransform
720 { 765 {
721 Q_OBJECT 766 Q_OBJECT