Interactive GUI Applications

Most of the time, applications demand user input e.g. clicking interesting image regions, or adjusting a threshold using a slider. ICL’s GUI creation framework provides a very intuitive and easy-to-use interface to create even complex interactive applications.

Let’s start with a very simple interactive application. Consider a simple online image thresholding application, where a slider is to be used to define the current threshold value at run-time.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <ICLQt/Common.h>
#include <ICLFilter/UnaryCompareOp.h>
#include <ICLUtils/FPSLimiter.h>

GUI gui;                 
GenericGrabber grabber;  
UnaryCompareOp cmp(">"); 
FPSLimiter fps(25);  

void init(){
  gui << Image().handle("image")
      << Slider(0,255,127).handle("thresh")
         .label("threshold").maxSize(100,2)
      << Show();
  grabber.init(pa("-i"));
}

void run(){
  cmp.setValue(gui["thresh"]);
  gui["image"] = cmp.apply(grabber.grab());
  fps.wait();
}
int main(int n, char **args){
  return ICLApp(n,args,"-input|-i(2)",
                init,run).exec();
}
shadow

Step by Step

Ok, let’s go through the code line by line in order to discuss it’s ingredients. we begin with including the headers, needed for our example.

#include <ICLQt/Common.h>
#include <ICLFilter/UnaryCompareOp.h>
#include <ICLUtils/FPSLimiter.h>

Now, some global data is defined. Even though, using global data is not optimal in terms of programming style, this is completely ok here, because we define a final application rather then a reusable tool. Therefore, the global variables cannot interfere with other symbols linked against later. Again, we use a GUI instance and a GenericGrabber. Additionally, we instantiate a UnaryCompareOp for the thresholding operation [1] and an FPSLimiter that can be used to limit the run loops iteration count per second.

GUI gui;                 
GenericGrabber grabber;  
UnaryCompareOp cmp(">"); 
FPSLimiter fps(25);  

Once the application data is instantiated, it needs to be initialized, which is commonly performed in the init function, called by the ICLApp instance, created in main. In this example, the GUI is set up to also show a slider that is used for adapting the threshold at run time. As one can see, the GUI‘s stream-operator << can be used add GUIComponents in a very simple manner. Components, that need to be accessed later, can be referenced by a string-ID called handle. Each GUIComponent has a set of component-specific parameters that are given to the component constructor an a set of more general, but optional parameters, that can be added using the .-operator.

  gui << Image().handle("image")
      << Slider(0,255,127).handle("thresh")
         .label("threshold").maxSize(100,2)
      << Show();

Note

The GUI-creation framework is also described in TODO

The actual image processing part is implemented in the run method. First, we need to extract the current slider value from our global GUI instance. Accessing GUI components for both reading or setting values is performed using the index operator (gui[“handle”]). This allows to seamlessly synchronize the GUI thread and the working thread of interactive applications. First, the current slider value is used as comparison threshold for the UnaryCompareOp instance, which is then applied on the next grabbed image. The result is directly passed to the visualization. Finally, fps.wait() will wait to ensure the desired FPS count.

void run(){
  cmp.setValue(gui["thresh"]);
  gui["image"] = cmp.apply(grabber.grab());
  fps.wait();
}

The run method basically stayed the same as in the prior example.

Footnotes

[1]Actually, even though we commonly describe the shown operations as thresholding, it should be named pixel-wise comparison