JeVois  1.10
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
Component.H
Go to the documentation of this file.
1 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2016 by Laurent Itti, the University of Southern
4 // California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5 //
6 // This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7 // redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8 // Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10 // License for more details. You should have received a copy of the GNU General Public License along with this program;
11 // if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12 //
13 // Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14 // Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16 /*! \file */
17 
18 // This code is inspired by the Neuromorphic Robotics Toolkit (http://nrtkit.org)
19 
20 #pragma once
21 
23 #include <boost/thread.hpp>
24 #include <string>
25 #include <vector>
26 #include <map>
27 #include <unordered_map>
28 #include <future>
29 
30 namespace jevois
31 {
32  class Manager;
33  class UserInterface;
34 
35  /*! \defgroup component Model components, parameters, manager, and associated classes
36 
37  These classes define how a complex model or vision processing pipeline with user-tunable parameters can be built
38  from components.
39 
40  How to explore this documentation module:
41 
42  - Start with looking at Component, which highlights the broad conceptual framework of how one may assemble complex
43  vision processing pipelines in JeVois, with substantial re-use of shared algorithmic elements.
44 
45  - Then have a look a \ref parameter which provides details on how to implement and use parameters in your
46  components. Parameters can be created for any valid C++ type, and serve the goal of allowing end-users of your
47  algorithm to tune some of the behavior of your algorithms.
48 
49  - Finally have a look at Manager, which is a special component that is the root of a component hierarchy.
50 
51  - You will then be ready to move to the next level by loking at the other elements in the documentation
52  module.
53 
54  \ingroup core */
55 
56  // ######################################################################
57  //! A component of a model hierarchy.
58  /*! Model Components form the heart of every JeVois application, as their main purpose is to allow 1) building complex
59  vision processing pipelines from shared, re-usable processing elements; 2) a uniform interface for tunable
60  parameters that these processing elements may have. In fact, every class which needs to expose parameters to the
61  user should inherit directly or indirectly from Component. Parameters are simple wrappers around any valid C++
62  type, along with some description, default values, possibly specification of valid values, etc. Parameters are
63  used to adjust the behavior of processing elements by allowing end-users to change the parameter values (think,
64  e.g., of a threshold in some image processing algorithm).
65 
66  Components typically form a component hierarchy with a Manager (including Engine) at the root, and a tree of
67  sub-Components below. To form this tree, just use the Manager::addComponent() and Component::addSubComponent()
68  methods to add some children, and then add some children to those children, etc...
69 
70  One intent behind Component is to enable substantial code re-use when implementing complex vision processing
71  frameworks, and to alleviate the burden of passing many parameters to function calls when invoking the processing
72  elements. This is a strong departure from many other frameworks such as OpenCV, which by and large rely on
73  functions with many parameters (though later versions do use classes as well). For example, the way one invokes a
74  Canny edge detector in OpenCV is to call the function:
75 
76  \code
77  void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2,
78  int apertureSize = 3, bool L2gradient = false)
79  \endcode
80 
81  Beyond possible confusion about which value goes to which argument in the long list (which languages such as
82  Python solve by allowing access to arguments by name), one major issue with this approach is that either every
83  function using Canny must provide a mechanism for the user to set the parameters (threshold1, threshold2, etc),
84  or, in most cases, those will just end up being hardwired, limiting the applicability of the end application to
85  different image sizes, environment types, etc.
86 
87  In contrast, in the JeVois framework, one would create a Canny Component, with Parameter settings for the
88  thresholds, etc and a member function
89 
90  \code
91  OutputArray process(InputArray in)
92  \endcode
93 
94  One would typically first set the parameter values, then call the function. Setting the parameters can be done by
95  the code that will use the function, but, more often, it is left to the user. In a particular vision pipeline,
96  resonable default values may be provided for the parameters at the beginning, then leaving those parameters
97  accessible to end users who may want to modify them. Modification of parameters in JeVois is handled either at the
98  start of the application by parsing command-line arguments, when a new processing Module is instantiated, or while
99  it is running, by interacting with the Engine that manages the system via its Serial ports.
100 
101  Any complex vision processing pipeline that includes the Canny component in its hierarchy will expose its
102  parameters so that they can be set, either by users (via command-line arguments, commands issued over serial
103  ports, etc), or by other components in the hierarchy. If multiple instances of a Component are present in a
104  hierarchy, their parameters can either all be set at once to a single (shared) value, or they can be accessed and
105  set individually to different values (each Component has a unique instance name, and a so-called descriptor is
106  created by concatenating instance names of a component and all its parents; parameters of a specific Component
107  instance can be accessed by prefixing that instance's descriptor to the parameter name). Parameters provide a
108  uniform interface for setting/getting the parameter values, so that programmers do not have to program accessor
109  functions in each of their components for each of their parameters(e.g., adding a Parameter<int> for threshold1 to
110  your component will automatically add set(), get(), etc functions for it into your component).
111 
112 
113  In addition, Component provides some level of introspection or reflection: one can access a component instance
114  name, class name, descriptor that includes names of all its parents in the hierarchy, and iterate over its
115  parameters, over its sub-components, etc.
116 
117  Component is inherently thread-safe and the component interface is written so as to encourage thread-safe use; for
118  example, no function is provided that returns the parent of a component, as another thread could change that
119  between the time that parent is returned and the time it is used. Instead, functions are provided that can
120  traverse the hierarchy up or down in a thread-safe manner and execute some action on the components that are
121  encountered during that traversal.
122 
123  Components are brought into action in several phases:
124 
125  - Construction: In constructors, Parameter values have not been set yet so nothing that depends on them should be
126  initialized yet. Typically, constructors should only initialize fixed component resources which are independent
127  of Parameter values, or they can also set default values for parameters, which may later be overriden by
128  command-line arguments. In many situations, the constructor would do nothing, and most of the initialization
129  work would be delayed until the Parameter values have been set, during the component's init() phase.
130 
131  - initialization: When init() is called on the manager (including Engine), it propagates down the entire Component
132  hierarchy, as follows:
133 
134  - recursively call preInit() on all sub-components.
135  - run preInit() on the current component (the preInit() function can be overriden by derived classes to
136  implement some custom initialization; note that Parameter values are not yet finalized at this point and
137  should not be used yet).
138  - Manager then parses the command-line and possibly sets parameters. Parameters are considered ready to use from
139  this point on.
140  - for parameters of this component that have a callback but it has not yet been invoked because that parameter
141  has not been explicitly set at the command line, call the callback one first time with the default parameter
142  value. This is so that callbacks that create resources (e.g., callback for a parameter for the device name of
143  a device, which opens the device when called) are called at least once before init() is complete.
144  - recursively flip the state of all sub-components to initialized, then flip the component state to initialized.
145  - recursively run postInit() on all sub-components (derived classes may override postInit(), and would typically
146  allocate resources that depend on parameter values in their override of postInit()), then on the current
147  component.
148 
149  The initialization flow is fixed. Classes that derive from Component can override preInit() for intializations
150  that do not rely on Parameter values and postInit() for those that do. Once init() is complete on the Manager,
151  all components in the hierarchy are considered ready for operation.
152 
153  If a component is added to an already-initialized hierarchy, it will be brought up to the same init state as its
154  parent at the time of addition. This is typically the case when one selects a new video format from a USB host
155  on a JeVois system that is already running and streaming video. The Module handling the old format is furst
156  un-initialized by Engine, then it is destroyed, the new Module is instantiated for the new format, and it is
157  initialized before the stream of video frames is directed to it.
158 
159  - uninit: This is the dual of init(), with preUninit() and postUninit() following the same logic as preInit() and
160  postInit(). Specific order is:
161 
162  - preUninit() is recursively called on all sub-component then on the component (note that initialized() is still
163  true at this point);
164  - component flips to un-initalized, then recursivey all its sub-components
165  - postUninit() is called on component, then recursively on all its sub-components.
166 
167  Note how both init() and uninit() are private in Component, and thus cannot be called directly. Manager (and hence
168  Engine which derives from Manager) makes them public so that you can call them on the manager. That is, your
169  entire hierarchy is either initialized or not.
170 
171  Because powering up the JeVois hardware platform automatically constructs and initializes the default processing
172  pipeline, and because of the aforementioned was in which Engine changes processing modules when users change video
173  format, most components just assume that their vision processing functions will never be called when the component
174  is not initialized, and thus they just skip testing for initialized() altogether (to save CPU cycles).
175 
176  \ingroup component */
177  class Component : public virtual ParameterRegistry
178  {
179  public:
180  //protected: // FIXME inherited constructor does not compile if protected!
181  //! Constructor
182  /*! The standard way to create a component is via Component::addSubComponent() or Manager::addComponent(), rather
183  than constructing them by hand. Components constructed via the constructor (e.g., calling operator new) will
184  not be attached to a Component hierarchy. It is recommended that derived components also have an instance
185  constructor argument and pass it down to the base Component class, to allow complex systems with several
186  instances of a same Component. In fact, for most components, the inherited constructor is appropriate:
187 
188  \code
189  class MyComp : public jevois::Component
190  {
191  public:
192  // Inherited constructor
193  using jevois::Component::Component;
194 
195  // Virtual destructor for safe inheritance
196  virtual ~MyComp();
197  };
198  \endcode */
199  Component(std::string const & instance);
200 
201  //! Virtual destructor for safe inheritance
202  /*! Calls uninit() if component is initialized. */
203  virtual ~Component();
204 
205  //! @name Component hierarchies
206  //! @{
207 
208  //! Pseudo-constructor: construct and add another component as a subcomponent of this one
209  /*! A child component of type Comp (which must derive from jevois::Component) will be created and added as a
210  sub-component of this. The child logically "belongs" to this component, and will automatically be initialized,
211  un-initialized, and deleted when the parent component is. In addition to construction, adding a subcomponent
212  will bring it up to the same init() state as the owner component.
213 
214  When setting parameters, the sub-Component can be referenced as a child of this component. For instance, if
215  we have a ComponentParent which has ComponentChild as a sub-Component, and ComponentChild has parameter named
216  coolChildParam, then that parameter could be specified on the command line by
217 
218  \code
219  --ComponentParentInstanceName:ComponentChildInstanceName:coolChildParamName="whatever"
220  \endcode
221 
222  or over a Serial port by
223 
224  \code
225  setpar ComponentParentInstanceName:ComponentChildInstanceName:coolChildParamName whatever
226  \endcode
227 
228  \param instance A string identifying a particular instance of a Component, no two sub-components of a
229  component may have the same instance name. The instance name should be passed in through your derived
230  Component's constructor, allowing users to disambiguate between multiple instances of your Component. If the
231  instance name is empty, the actual instance will be named <ComponentClassname># with # replaced (if necessary)
232  by a unique number. If the instance name is not empty but contains a #, only that # is replaced (if necessary)
233  by a number that makes the instance name unique. The final name is accessible via instanceName() once your
234  component is constructed. There is no default value for instance in the base class to catch derived classes
235  that forgot to pass it down to the base, but it may be a good idea to set an empty string default to instance
236  in derived classes.
237 
238  \note Sub-components always inherit the path of their top-level parent (a top-level component is one that was
239  directly added to a Manager via Manager::addComponent()). See absolutePath(). This is so that different
240  modules can provide different data for their components; for example, a FaceDetector component may require
241  some face template data files to operate; if those are loaded using a relative path name, different modules
242  that use the FaceDetector may use different face template data files. */
243  template <class Comp, typename... Args>
244  std::shared_ptr<Comp> addSubComponent(std::string const & instance, Args && ...args);
245 
246  //! Remove a sub-Component from this Component, by shared_ptr
247  /*! \note Beware that the passed shared_ptr is invalidated in the process. A warning is issued if the use_count is
248  not down to zero after that (i.e., there are additional shared_ptr pointers to this Component floating around,
249  which prevent it from actually being deleted. */
250  template <class Comp>
251  void removeSubComponent(std::shared_ptr<Comp> & component);
252 
253  //! Remove a sub-Component from this Component, by instance name
254  void removeSubComponent(std::string const & instance, bool warnIfNotFound = true);
255 
256  //! Get a sub-component by instance name
257  /*! This method does a dynamic_pointer_cast to Comp if it is not the default (jevois::Component). Throws if
258  component is not found by instance name, or it is found but not of type Comp (if Comp is specified). Note that
259  once you hold a shared_ptr to a Component, it is guaranteed that the component will not be destroyed until
260  that shared_ptr is released. If the JeVois system tries to destroy the component (e.g., someone calls
261  removeSubComponent()), the component will be un-initialized and its parent will be unset, so it will not be
262  fully operational and will be actually deleted when the last shared_ptr to it runs out of scope. */
263  template <class Comp = jevois::Component>
264  std::shared_ptr<Comp> getSubComponent(std::string const & instance) const;
265 
266  //! Returns true if this component is top-level, i.e., its parent is jevois::Manager
267  /*! The Module of Engine is top-level. */
268  bool isTopLevel() const;
269 
270  //! @}
271 
272  //! @name Component runtime
273  //! @{
274 
275  //! Has this component been initialized yet?
276  bool initialized() const;
277 
278  //! @}
279 
280  //! @name Component metainfo-related functions
281  //! @{
282 
283  //! The class name of this component
284  std::string const & className() const;
285 
286  //! The instance name of this component
287  std::string const & instanceName() const;
288 
289  //! @}
290 
291  /*! @name Component Parameter-related functions
292 
293  Each Component can hold Parameter objects (through inheritance) that can be set externally by users to modify
294  the operation of the Component, and that can be accessed or set by the Component itself.
295 
296  Note how the JeVois framework uses inheritance for parameters as opposed to making them class data members of
297  the owning Component. See \ref parameter for detailed explanations. */
298  //! @{
299 
300  //! Set a parameter value
301  /*! Throws if we don't have a parameter by that name or the value does not work out. Here is how the descriptor
302  works:
303 
304  The basic format is
305 
306  \code
307  [ComponentInstanceName]:[...]:[paramname]
308  \endcode
309 
310  Note that any <code>[ComponentInstanceName]</code> token can also be replaced by a *, which is equivalent to
311  any number of any ComponentInstanceName specifications. So use the * to reach parameters when you don't know
312  how deep they are. If there is some other ComponentInstanceName between a * and the final paramname, then
313  recursion is turned off and anything between the * and paramname must match intervening components/instances.
314 
315  For example,
316 
317  @code
318  MyInst:*:CoolComp:MyParam
319  @endcode
320 
321  would match parameters where MyInst matches the top-level component (the one on which you call setParamVal()),
322  then would recurse through any number of subcomponents, until one of them matches CoolComp, and then we would
323  look for MyParam parameter in that subcomponent, and we would not look any deeper.
324 
325  Finally note that there is an implicit first *: that is automatically prepended to your description, so if you
326  just specify a paramname and nothing else before it, we will set all params by that name in all subcomponents
327  no matter how deep they are (as if you had specified *:paramname).
328 
329  @throws std::exception if no Parameter matches the given descriptor.
330  @return list of fully-unrolled (no '*') descriptors of the parameters that were matched and set. The list is
331  guaranteed to have at least one element since we throw if no matching parameter is found. */
332  template <typename T>
333  std::vector<std::string> setParamVal(std::string const & paramdescriptor, T const & val);
334 
335  //! Set a parameter value, simple version assuming only one parameter match
336  /*! This calls setParamVal(), and checks that exactly one match was found.
337  @throws std::exception if not exactly one Parameter matches the given descriptor. */
338  template <typename T>
339  void setParamValUnique(std::string const & paramdescriptor, T const & val);
340 
341  //! Get parameter(s) value(s) by descriptor
342  /*! Use this method to get the current value of a Component's parameter from the string descriptor. Values for all
343  parameters that match the descriptor are returned.
344 
345  For example, if the class MyComponent has an integer parameter named "myparam" you could get the
346  value like so:
347 
348  @code
349  std::shared_ptr<MyComponent> comp = addSubComponent<MyComponent>("mycomp");
350  auto paramValues = comp->getParamVal<int>("myparam");
351  for (auto const & pp : paramValues) LINFO("Parameter " << pp.first << " = " << pp.second);
352  @endcode
353 
354  @throws jevois::exception::ParameterException if no Parameter matches the given descriptor.
355  @return list of <paramdescriptor, value> for all parameters that matched the given descriptor. The list is
356  guaranteed to have at least one element since we throw if no matching parameter is found.
357 
358  \see setParamVal for a detailed explanation of the paramdescriptor */
359  template <typename T>
360  std::vector<std::pair<std::string, T> > getParamVal(std::string const & paramdescriptor) const;
361 
362  //! Get a parameter value, simple version assuming only one parameter match
363  /*! This calls getParamVal(), checks that exactly one match was found, and returns its value.
364  For example, if the class MyComponent has an integer parameter named "myparam" you could get the
365  value like so:
366 
367  @code
368  std::shared_ptr<MyComponent> comp(new MyComponent);
369  int paramValue = comp->getParamValUnique<int>("myparam");
370  @endcode
371 
372  @throws jevois::exception::ParameterException if not exactly one Parameter matches the given descriptor. */
373  template <typename T>
374  T getParamValUnique(std::string const & paramdescriptor) const;
375 
376  //! Set a parameter value, by string
377  /*! \see setParamVal for a detailed explanation of the paramdescriptor
378  @throws jevois::exception::ParameterException if no Parameter matches the given descriptor or if the
379  given string cannot be converted to the Parameter's native type.
380  @return list of fully-unrolled (no '*') descriptors of the parameters that were matched and set. The list is
381  guaranteed to have at least one element since we throw if no matching parameter is found. */
382  std::vector<std::string> setParamString(std::string const & paramdescriptor, std::string const & val);
383 
384  //! Set a parameter value by string, simple version assuming only one parameter match
385  /*! This calls setParamVal(), and checks that exactly one match was found.
386  @throws jevois::exception::ParameterException if not exactly one Parameter matches the given descriptor. */
387  void setParamStringUnique(std::string const & paramdescriptor, std::string const & val);
388 
389  //! Get a parameter value, by string
390  /*! \see setParamVal for a detailed explanation of the paramdescriptor
391  Use this method to get the current value of a Component's parameter from the string descriptor. Values for all
392  parameters that match the descriptor are returned, as string.
393  @throws jevois::exception::ParameterException if no Parameter matches the given descriptor.
394  @return list of <paramdescriptor, valuestring> for all parameters that matched the given descriptor. The list
395  is guaranteed to have at least one element since we throw if no matching parameter is found. */
396  std::vector<std::pair<std::string, std::string> > getParamString(std::string const & paramdescriptor) const;
397 
398  //! Get a parameter value by string, simple version assuming only one parameter match
399  /*! This calls getParamVal(), checks that exactly one match was found, and returns its value as a string.
400  @throws jevois::exception::ParameterException if not exactly one Parameter matches the given descriptor. */
401  std::string getParamStringUnique(std::string const & paramdescriptor) const;
402 
403  //! Freeze a parameter, by name, see ParameterBase::freeze()
404  void freezeParam(std::string const & paramdescriptor);
405 
406  //! Unfreeze a parameter, by name, see ParameterBase::unFreeze()
407  void unFreezeParam(std::string const & paramdescriptor);
408 
409  //! Freeze all parameters
410  void freezeAllParams();
411 
412  //! Unfreeze all parameters
413  void unFreezeAllParams();
414 
415  //! Get our full descriptor (including all parents) as [Instancename]:[...]:[...]
416  std::string descriptor() const;
417 
418  //! Set some parameters from a file
419  /*! The file should have entries "descriptor=value", one per line, where the parameter descriptors should be
420  relative to this component. If the file name is relative, our component path will be prefixed to it using
421  absolutePath(). */
422  void setParamsFromFile(std::string const & filename);
423 
424  //! Set some parameters from an open stream
425  /*! The stream should have entries "descriptor=value", one per line, where the parameter descriptors should be
426  relative to this component. absfile is only used for error messages and should be the absolute path of the
427  file opened in 'is', or some other text for error messages. */
428  std::istream & setParamsFromStream(std::istream & is, std::string const & absfile);
429 
430  //! Get machine-oriented descriptions of all parameters
431  virtual void paramInfo(std::shared_ptr<UserInterface> s, std::map<std::string, std::string> & categs,
432  bool skipFrozen, std::string const & cname = "", std::string const & pfx = "");
433 
434  //! @}
435 
436  /*! @name Component path-related functions
437 
438  Each Component can keep track of a preferred filesystem path. Typically, users should not tamper with this,
439  but Module objects (which derive from Component) that are dynamically loaded will have that path set to the
440  path where the Module's shared object file (.so) was found. This allows those modules to access some of their
441  local configuration data, which may, for example, be stored in an \c etc/ directory under the module path. */
442  //! @{
443 
444  //! Assign a filesystem path to this component
445  void setPath(std::string const & path);
446 
447  //! If given path is relative (not starting with /), prepend the Component path to it
448  /*! If path is absolute, no-op. If path is empty, return the Component's path as set with setPath(). */
449  std::string absolutePath(std::string const & path = "");
450 
451  //! @}
452 
453  protected:
454  //! @name Component setup functions overloadable by derived classes
455 
456  //! @{
457 
458  //! Called before all sub-Components are init()ed
459  virtual void preInit() { }
460 
461  //! Called after all sub-Components are init()ed
462  virtual void postInit() { }
463 
464  //! Called before all sub-Components are uninit()ed
465  virtual void preUninit() { }
466 
467  //! Called after all sub-Components are uninit()ed
468  virtual void postUninit() { }
469 
470  //! @}
471 
472  private:
473  template <typename T> friend class ParameterCore;
474  friend class Manager; // Allow Manager to access our subs directly (in addComponent, etc)
475  friend class Engine; // Allow Engine to add already-created components (the module)
476  friend class Module; // Allow Module to access itsParent
477 
478  mutable boost::shared_mutex itsMtx; // Mutex used to protect our internals other than subcomps and parameters
479 
480  // Storage for sub-Components
481  std::vector<std::shared_ptr<Component> > itsSubComponents;
482 
483  // Mutex to protect our list of subcomponents
484  mutable boost::shared_mutex itsSubMtx;
485 
486  // Recursively populate a list of parameters, for help message
487  void populateHelpMessage(std::string const & cname,
488  std::unordered_map<std::string /* categ+categdesc */,
489  std::unordered_map<std::string /* name+defaultval+validvals+descrip */,
490  std::vector<std::pair<std::string /* component */, std::string /* value */ > > > > &
491  helplist, bool recurse = true) const;
492 
493  //! Initialization
494  /*! Invoke: runPreInit(), then setInitialized(), finally runPostInit() */
495  virtual void init();
496 
497  //! Recursively run preInit()
498  void runPreInit();
499 
500  //! Recursively set initialized flag
501  void setInitialized();
502 
503  //! Recursively run postInit()
504  void runPostInit();
505 
506  //! Un-initialize
507  /* Invoke: runPreUninit(), then setUninitialized(), finally runPostUninit() */
508  virtual void uninit();
509 
510  //! Recursively run preUninit()
511  void runPreUninit();
512 
513  //! Recursively set uninitialized flag
514  void setUninitialized();
515 
516  //! Recursively run postUninit()
517  void runPostUninit();
518 
519  // Our meta information. Only access this through meta(), even from within Component!
520  mutable boost::shared_mutex itsMetaMtx;
521  std::string const itsClassName;
522  std::string itsInstanceName;
523 
524  // Has this Component been initialized?
525  volatile bool itsInitialized;
526 
527  // The Component which contains this one as a sub-Component - this may be NULL if the component is not part of any
528  // hierarchy, or is the manager.
529  Component * itsParent;
530 
531  void findParamAndActOnIt(std::string const & descriptor,
532  std::function<void(jevois::ParameterBase * param, std::string const & unrolled)> doit,
533  std::function<bool()> empty) const;
534  void findParamAndActOnIt(std::vector<std::string> const & descrip, bool recur, size_t idx,
535  std::string const & unrolled,
536  std::function<void(jevois::ParameterBase *, std::string const &)> doit) const;
537 
538  std::string itsPath; // filesystem path assigned to this Component, empty by default
539 
540  //! Helper function to compute an automatic instance name, if needed
541  /*! Parent modules call this before adding a sub-module, to make sure its name will not clash with existing
542  sub-modules. Parameter classname can be empty if instance is not. Throws if a unique name cannot be created
543  (e.g., no # was provided and the instance name clashes with other sub-modules). itsSubMtx on the parent must
544  be locked by caller to make sure the computed name remains available as we return it */
545  std::string computeInstanceName(std::string const & instance, std::string const & classname = "") const;
546 
547  //! Actually remove a sub, no type checking here, for internal use only
548  /*! Uplck is assumed to already be locked for read, will be upgraded to write lock. Itr is an iterator on
549  itsSubComponents pointing at the component to remove. It will get reset(). displayname is just Component,
550  SubModule, etc for messages purposes. */
551  void doRemoveSubComponent(std::vector<std::shared_ptr<Component> >::iterator & itr,
552  boost::upgrade_lock<boost::shared_mutex> & uplck,
553  std::string const & displayname);
554  };
555 } //jevois
556 
557 // Include inlined implementation details that are of no interest to the end user
559 
virtual void preInit()
Called before all sub-Components are init()ed.
Definition: Component.H:459
A changeable parameter for a Component, core class.
Definition: Parameter.H:183
std::vector< std::string > setParamString(std::string const &paramdescriptor, std::string const &val)
Set a parameter value, by string.
Definition: Component.C:347
std::vector< std::string > setParamVal(std::string const &paramdescriptor, T const &val)
Set a parameter value.
void setParamValUnique(std::string const &paramdescriptor, T const &val)
Set a parameter value, simple version assuming only one parameter match.
std::string const & className() const
The class name of this component.
Definition: Component.C:38
std::shared_ptr< Comp > addSubComponent(std::string const &instance, Args &&...args)
Pseudo-constructor: construct and add another component as a subcomponent of this one...
Definition: ComponentImpl.H:29
void setPath(std::string const &path)
Assign a filesystem path to this component.
Definition: Component.C:490
Manager of a hierarchy of Component objects.
Definition: Manager.H:73
void setParamStringUnique(std::string const &paramdescriptor, std::string const &val)
Set a parameter value by string, simple version assuming only one parameter match.
Definition: Component.C:363
T getParamValUnique(std::string const &paramdescriptor) const
Get a parameter value, simple version assuming only one parameter match.
void setParamsFromFile(std::string const &filename)
Set some parameters from a file.
Definition: Component.C:443
bool isTopLevel() const
Returns true if this component is top-level, i.e., its parent is jevois::Manager. ...
Definition: Component.C:118
void freezeParam(std::string const &paramdescriptor)
Freeze a parameter, by name, see ParameterBase::freeze()
Definition: Component.C:403
A component of a model hierarchy.
Definition: Component.H:177
bool initialized() const
Has this component been initialized yet?
Definition: Component.C:195
std::string getParamStringUnique(std::string const &paramdescriptor) const
Get a parameter value by string, simple version assuming only one parameter match.
Definition: Component.C:390
virtual void preUninit()
Called before all sub-Components are uninit()ed.
Definition: Component.H:465
virtual ~Component()
Virtual destructor for safe inheritance.
Definition: Component.C:53
std::vector< std::pair< std::string, T > > getParamVal(std::string const &paramdescriptor) const
Get parameter(s) value(s) by descriptor.
std::string descriptor() const
Get our full descriptor (including all parents) as [Instancename]:[...]:[...].
Definition: Component.C:265
std::shared_ptr< Comp > getSubComponent(std::string const &instance) const
Get a sub-component by instance name.
Definition: ComponentImpl.H:62
void removeSubComponent(std::shared_ptr< Comp > &component)
Remove a sub-Component from this Component, by shared_ptr.
Base class for Parameter.
Definition: Parameter.H:121
Component(std::string const &instance)
Constructor.
Definition: Component.C:31
std::istream & setParamsFromStream(std::istream &is, std::string const &absfile)
Set some parameters from an open stream.
Definition: Component.C:452
virtual void paramInfo(std::shared_ptr< UserInterface > s, std::map< std::string, std::string > &categs, bool skipFrozen, std::string const &cname="", std::string const &pfx="")
Get machine-oriented descriptions of all parameters.
Definition: Component.C:522
virtual void postInit()
Called after all sub-Components are init()ed.
Definition: Component.H:462
std::vector< std::pair< std::string, std::string > > getParamString(std::string const &paramdescriptor) const
Get a parameter value, by string.
Definition: Component.C:374
void unFreezeParam(std::string const &paramdescriptor)
Unfreeze a parameter, by name, see ParameterBase::unFreeze()
Definition: Component.C:415
JeVois processing engine - gets images from camera sensor, processes them, and sends results over USB...
Definition: Engine.H:265
Virtual base class for a vision processing module.
Definition: Module.H:336
void freezeAllParams()
Freeze all parameters.
Definition: Component.C:427
A simple registry of all parameters associated with a Component.
void unFreezeAllParams()
Unfreeze all parameters.
Definition: Component.C:435
std::string const & instanceName() const
The instance name of this component.
Definition: Component.C:49
virtual void postUninit()
Called after all sub-Components are uninit()ed.
Definition: Component.H:468
std::string absolutePath(std::string const &path="")
If given path is relative (not starting with /), prepend the Component path to it.
Definition: Component.C:504