SourceXtractorPlusPlus  0.12
Please provide a description of the project.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SourceXtractor.cpp
Go to the documentation of this file.
1 
23 #include <typeinfo>
24 #include <map>
25 #include <string>
26 #include <iomanip>
27 
28 #include <boost/program_options.hpp>
29 #include <boost/algorithm/string/predicate.hpp>
31 
32 #include "ElementsKernel/Main.h"
33 #include "ElementsKernel/System.h"
35 
37 #include "Configuration/Utils.h"
38 
40 
48 
50 
53 
55 
61 
65 
67 
71 
79 
81 
83 #include "SEMain/PluginConfig.h"
84 #include "SEMain/Sorter.h"
85 
86 
87 namespace po = boost::program_options;
88 namespace fs = boost::filesystem;
89 using namespace SourceXtractor;
90 using namespace Euclid::Configuration;
91 
93 
94 static const std::string LIST_OUTPUT_PROPERTIES {"list-output-properties"};
95 static const std::string PROPERTY_COLUMN_MAPPING_ALL {"property-column-mapping-all"};
96 static const std::string PROPERTY_COLUMN_MAPPING {"property-column-mapping"};
97 static const std::string DUMP_CONFIG {"dump-default-config"};
98 
99 class GroupObserver : public Observer<std::shared_ptr<SourceGroupInterface>> {
100 public:
101  virtual void handleMessage(const std::shared_ptr<SourceGroupInterface>& group) override {
102  m_list.push_back(group);
103  }
104 
106 };
107 
108 class SourceObserver : public Observer<std::shared_ptr<SourceWithOnDemandProperties>> {
109 public:
110  virtual void handleMessage(const std::shared_ptr<SourceWithOnDemandProperties>& source) override {
111  m_list.push_back(source);
112  }
113 
115 };
116 
118 
119 static void setupEnvironment(void) {
120  // Some parts of boost (including boost::filesystem) can throw an exception when the
121  // locale as configured in the environment is invalid.
122  // We work around that overriding the locale if we find an invalid one.
123  // See https://svn.boost.org/trac10/ticket/10205
124  try {
125  std::locale("");
126  }
127  catch (...) {
128  ::setenv("LC_ALL", "C", 1);
129  }
130 }
131 
132 
133 class SEMain : public Elements::Program {
134 
135  std::shared_ptr<TaskFactoryRegistry> task_factory_registry = std::make_shared<TaskFactoryRegistry>();
136  std::shared_ptr<TaskProvider> task_provider = std::make_shared<TaskProvider>(task_factory_registry);
137  std::shared_ptr<OutputRegistry> output_registry = std::make_shared<OutputRegistry>();
138  SegmentationFactory segmentation_factory {task_provider};
139  OutputFactory output_factory { output_registry };
142  std::make_shared<SourceWithOnDemandPropertiesFactory>(task_provider);
144  std::make_shared<SourceGroupWithOnDemandPropertiesFactory>(task_provider);
145  PartitionFactory partition_factory {source_factory};
146  GroupingFactory grouping_factory {group_factory};
147  DeblendingFactory deblending_factory {source_factory};
148  MeasurementFactory measurement_factory { output_registry };
149  ProgressReporterFactory progress_printer_factory {};
150 
151  bool config_initialized = false;
152  po::options_description config_parameters;
153 
154 public:
155 
156  SEMain(const std::string& plugin_path, const std::vector<std::string>& plugin_list)
157  : plugin_manager { task_factory_registry, output_registry, config_manager_id, plugin_path, plugin_list } {
158  }
159 
163  po::options_description getConfigParameters() {
164  if (!config_initialized) {
165  auto& config_manager = ConfigManager::getInstance(config_manager_id);
166  config_manager.registerConfiguration<SourceXtractorConfig>();
167  config_manager.registerConfiguration<BackgroundConfig>();
168  config_manager.registerConfiguration<SE2BackgroundConfig>();
169  config_manager.registerConfiguration<MemoryConfig>();
170  config_manager.registerConfiguration<BackgroundAnalyzerFactory>();
171  config_manager.registerConfiguration<SamplingConfig>();
172 
174 
175  //plugins need to be registered before reportConfigDependencies()
176  plugin_manager.loadPlugins();
177  task_factory_registry->reportConfigDependencies(config_manager);
178  segmentation_factory.reportConfigDependencies(config_manager);
179  partition_factory.reportConfigDependencies(config_manager);
180  grouping_factory.reportConfigDependencies(config_manager);
181  deblending_factory.reportConfigDependencies(config_manager);
182  measurement_factory.reportConfigDependencies(config_manager);
183  output_factory.reportConfigDependencies(config_manager);
184 
185  config_parameters.add(config_manager.closeRegistration());
186  config_initialized = true;
187  }
188  return config_parameters;
189  }
190 
193  auto options = getConfigParameters();
194 
195  options.add_options() (LIST_OUTPUT_PROPERTIES.c_str(), po::bool_switch(),
196  "List the possible output properties for the given input parameters and exit");
197  options.add_options() (PROPERTY_COLUMN_MAPPING_ALL.c_str(), po::bool_switch(),
198  "Show the columns created for each property");
199  options.add_options() (PROPERTY_COLUMN_MAPPING.c_str(), po::bool_switch(),
200  "Show the columns created for each property, for the given configuration");
201  options.add_options() (DUMP_CONFIG.c_str(), po::bool_switch(),
202  "Dump parameters with default values into a configuration file");
203  progress_printer_factory.addOptions(options);
204 
205  // Allow to pass Python options as positional following --
206  po::positional_options_description p;
207  p.add("python-arg", -1);
208 
209  return {options, p};
210  }
211 
213  template <typename T>
214  static void writeDefault(std::ostream& out, const po::option_description& opt, const boost::any& default_value) {
215  out << opt.long_name() << '=' << boost::any_cast<T>(default_value) << std::endl;
216  }
217 
219  template <typename T>
220  static void writeDefaultMultiple(std::ostream& out, const po::option_description& opt, const boost::any& default_value) {
221  auto values = boost::any_cast<std::vector<T>>(default_value);
222  if (values.empty()) {
223  out << opt.long_name() << '=' << std::endl;
224  }
225  else {
226  for (const auto& v : values)
227  out << opt.long_name() << '=' << v << std::endl;
228  }
229  }
230 
232  void printDefaults() {
235  {typeid(bool), &writeDefault<bool>},
236  {typeid(int), &writeDefault<int>},
237  {typeid(double), &writeDefault<double>},
238  {typeid(std::string), &writeDefault<std::string>},
239  {typeid(std::vector<std::string>), &writeDefaultMultiple<std::string>}
240  };
241  decltype(printers)::const_iterator printer;
242 
243  auto config_parameters = getConfigParameters();
244  for (const auto& p : config_parameters.options()) {
245  boost::any default_value;
246 
247  std::cout << "# " << p->description() << std::endl;
248  if (!p->semantic()->apply_default(default_value)) {
249  std::cout << '#' << p->long_name() << "=" << std::endl;
250  }
251  else if ((printer = printers.find(default_value.type())) == printers.end()) {
252  std::cout << '#' << p->long_name() << "=<Unknown type " << default_value.type().name() << '>' << std::endl;
253  }
254  else {
255  printer->second(std::cout, *p, default_value);
256  }
257  std::cout << std::endl;
258  }
259 
260  // We need to print the log options manually, as that is set up by Elements
261  std::cout << "# Log level: FATAL, ERROR, WARN, INFO, DEBUG" << std::endl;
262  std::cout << "log-level=INFO" << std::endl;
263  std::cout << "# Log file" << std::endl;
264  std::cout << "#log-file" << std::endl;
265  }
266 
268 
269  // If the user just requested to see the possible output columns we show
270  // them and we do nothing else
271 
272  if (args.at(LIST_OUTPUT_PROPERTIES).as<bool>()) {
273  for (auto& name : output_registry->getOutputPropertyNames()) {
274  std::cout << name << std::endl;
275  }
276  return Elements::ExitCode::OK;
277  }
278 
279  if (args.at(PROPERTY_COLUMN_MAPPING_ALL).as<bool>()) {
280  output_registry->printPropertyColumnMap();
281  return Elements::ExitCode::OK;
282  }
283 
284  if (args.at(DUMP_CONFIG).as<bool>()) {
285  printDefaults();
286  return Elements::ExitCode::OK;
287  }
288 
289  // Elements does not verify that the config-file exists. It will just not read it.
290  // We verify that it does exist here.
291  if (args.find("config-file") != args.end()) {
292  auto cfg_file = args.at("config-file").as<fs::path>();
293  if (cfg_file != "" && !fs::exists(cfg_file)) {
294  throw Elements::Exception() << "The configuration file '" << cfg_file << "' does not exist";
295  }
296  }
297 
298  // Create the progress listener and printer ASAP
299  progress_printer_factory.configure(args);
300  auto progress_mediator = progress_printer_factory.createProgressMediator();
301 
302  // Initialize the rest of the components
303  auto& config_manager = ConfigManager::getInstance(config_manager_id);
304  config_manager.initialize(args);
305 
306  // Configure TileManager
307  auto memory_config = config_manager.getConfiguration<MemoryConfig>();
308  TileManager::getInstance()->setOptions(memory_config.getTileSize(),
309  memory_config.getTileSize(), memory_config.getTileMaxMemory());
310 
311  CheckImages::getInstance().configure(config_manager);
312 
313  task_factory_registry->configure(config_manager);
314  task_factory_registry->registerPropertyInstances(*output_registry);
315 
316  segmentation_factory.configure(config_manager);
317  partition_factory.configure(config_manager);
318  grouping_factory.configure(config_manager);
319  deblending_factory.configure(config_manager);
320  measurement_factory.configure(config_manager);
321  output_factory.configure(config_manager);
322 
323  if (args.at(PROPERTY_COLUMN_MAPPING).as<bool>()) {
324  output_registry->printPropertyColumnMap(config_manager.getConfiguration<OutputConfig>().getOutputProperties());
325  return Elements::ExitCode::OK;
326  }
327 
328  auto detection_image = config_manager.getConfiguration<DetectionImageConfig>().getDetectionImage();
329  auto detection_image_path = config_manager.getConfiguration<DetectionImageConfig>().getDetectionImagePath();
330  auto weight_image = config_manager.getConfiguration<WeightImageConfig>().getWeightImage();
331  bool is_weight_absolute = config_manager.getConfiguration<WeightImageConfig>().isWeightAbsolute();
332  auto weight_threshold = config_manager.getConfiguration<WeightImageConfig>().getWeightThreshold();
333 
334  auto detection_image_coordinate_system = config_manager.getConfiguration<DetectionImageConfig>().getCoordinateSystem();
335  auto detection_image_gain = config_manager.getConfiguration<DetectionImageConfig>().getGain();
336  auto detection_image_saturation = config_manager.getConfiguration<DetectionImageConfig>().getSaturation();
337 
338  auto segmentation = segmentation_factory.createSegmentation();
339  auto partition = partition_factory.getPartition();
340  auto source_grouping = grouping_factory.createGrouping();
341 
342  std::shared_ptr<Deblending> deblending = deblending_factory.createDeblending();
343  std::shared_ptr<Measurement> measurement = measurement_factory.getMeasurement();
344  std::shared_ptr<Output> output = output_factory.getOutput();
345 
346  auto sorter = std::make_shared<Sorter>();
347 
348  // Link together the pipeline's steps
349  segmentation->Observable<std::shared_ptr<SourceInterface>>::addObserver(partition);
350  segmentation->Observable<ProcessSourcesEvent>::addObserver(source_grouping);
351  partition->addObserver(source_grouping);
352  source_grouping->addObserver(deblending);
353  deblending->addObserver(measurement);
354  measurement->addObserver(sorter);
355  sorter->addObserver(output);
356 
357  segmentation->Observable<SegmentationProgress>::addObserver(progress_mediator->getSegmentationObserver());
358  segmentation->Observable<std::shared_ptr<SourceInterface>>::addObserver(progress_mediator->getDetectionObserver());
359  deblending->addObserver(progress_mediator->getDeblendingObserver());
360  measurement->addObserver(progress_mediator->getMeasurementObserver());
361 
362  // Add observers for CheckImages
363  if (CheckImages::getInstance().getSegmentationImage() != nullptr) {
364  segmentation->Observable<std::shared_ptr<SourceInterface>>::addObserver(
365  std::make_shared<DetectionIdCheckImage>());
366  }
367  if (CheckImages::getInstance().getPartitionImage() != nullptr) {
368  measurement->addObserver(
369  std::make_shared<SourceIdCheckImage>());
370  }
371  if (CheckImages::getInstance().getGroupImage() != nullptr) {
372  measurement->addObserver(
373  std::make_shared<GroupIdCheckImage>());
374  }
375  if (CheckImages::getInstance().getMoffatImage() != nullptr) {
376  measurement->addObserver(
377  std::make_shared<MoffatCheckImage>());
378  }
379 
380  auto interpolation_gap = config_manager.getConfiguration<DetectionImageConfig>().getInterpolationGap();
381  auto detection_frame = std::make_shared<DetectionImageFrame>(detection_image, weight_image,
382  weight_threshold, detection_image_coordinate_system, detection_image_gain,
383  detection_image_saturation, interpolation_gap);
384  detection_frame->setLabel(boost::filesystem::basename(detection_image_path));
385 
386  auto background_analyzer = config_manager.getConfiguration<BackgroundAnalyzerFactory>().createBackgroundAnalyzer();
387  auto background_model = background_analyzer->analyzeBackground(detection_frame->getOriginalImage(), weight_image,
388  ConstantImage<unsigned char>::create(detection_image->getWidth(), detection_image->getHeight(), false), detection_frame->getVarianceThreshold());
389 
390  // initial set of the variance and background check images, might be overwritten below
391  CheckImages::getInstance().setBackgroundCheckImage(background_model.getLevelMap());
392  CheckImages::getInstance().setVarianceCheckImage(background_model.getVarianceMap());
393 
394  detection_frame->setBackgroundLevel(background_model.getLevelMap(), background_model.getMedianRms());
395 
396  if (weight_image != nullptr) {
397  if (is_weight_absolute) {
398  detection_frame->setVarianceMap(weight_image);
399  } else {
400  auto scaled_image = MultiplyImage<SeFloat>::create(weight_image, background_model.getScalingFactor());
401  detection_frame->setVarianceMap(scaled_image);
402  }
403  } else {
404  detection_frame->setVarianceMap(background_model.getVarianceMap());
405  }
406  // re-set the variance check image to what's in the detection_frame()
407  CheckImages::getInstance().setVarianceCheckImage(detection_frame->getVarianceMap());
408 
409  const auto& background_config = config_manager.getConfiguration<BackgroundConfig>();
410 
411  // Override background level and threshold if requested by the user
412  if (background_config.isBackgroundLevelAbsolute()) {
414  detection_image->getWidth(), detection_image->getHeight(), background_config.getBackgroundLevel());
415 
416  detection_frame->setBackgroundLevel(background, 0.);
418  }
419 
420  if (background_config.isDetectionThresholdAbsolute()) {
421  detection_frame->setDetectionThreshold(background_config.getDetectionThreshold());
422  }
423  CheckImages::getInstance().setVarianceCheckImage(detection_frame->getVarianceMap());
424 
425  //CheckImages::getInstance().setFilteredCheckImage(detection_frame->getFilteredImage());
426 
427  // Perform measurements (multi-threaded part)
428  measurement->startThreads();
429 
430  try {
431  // Process the image
432  segmentation->processFrame(detection_frame);
433  }
434  catch (const std::exception &e) {
435  logger.error() << "Failed to process the frame! " << e.what();
436  measurement->waitForThreads();
438  }
439 
440  measurement->waitForThreads();
441 
442  CheckImages::getInstance().setFilteredCheckImage(detection_frame->getFilteredImage());
443  CheckImages::getInstance().setThresholdedCheckImage(detection_frame->getThresholdedImage());
444  CheckImages::getInstance().setSnrCheckImage(detection_frame->getSnrImage());
446  TileManager::getInstance()->flush();
447  FitsFileManager::getInstance()->closeAllFiles();
448 
449  size_t n_writen_rows = output->flush();
450 
451  progress_mediator->done();
452 
453  if (n_writen_rows > 0) {
454  logger.info() << n_writen_rows << " sources detected";
455  } else {
456  logger.info() << "NO SOURCES DETECTED";
457  }
458 
459  return Elements::ExitCode::OK;
460  }
461 };
462 
463 
465 
466 public:
468  m_plugin_path(plugin_path), m_plugin_list(plugin_list) {
469  }
470 
471  virtual ~PluginOptionsMain() = default;
472 
473  boost::program_options::options_description defineSpecificProgramOptions() override {
474  auto& config_manager = ConfigManager::getInstance(conf_man_id);
475  config_manager.registerConfiguration<PluginConfig>();
476  auto options = config_manager.closeRegistration();
477  // The following will consume any extra options in the configuration file
478  options.add_options()("*", po::value<std::vector<std::string>>());
479  return options;
480  }
481 
483  auto& config_manager = ConfigManager::getInstance(conf_man_id);
484  config_manager.initialize(args);
485  auto& conf = config_manager.getConfiguration<PluginConfig>();
486  m_plugin_path = conf.getPluginPath();
487  m_plugin_list = conf.getPluginList();
488  return Elements::ExitCode::OK;
489  }
490 
491 private:
492 
493  long conf_man_id = getUniqueManagerId();
496 
497 };
498 
499 
500 static void forwardOptions(int argc, char *const *argv, std::vector<std::string>& plugin_options_input) {
501  for (int i = 0; i < argc; ++i) {
502  std::string option{argv[i]};
503  if (option == "--config-file") {
504  plugin_options_input.emplace_back("--config-file");
505  plugin_options_input.emplace_back(std::string{argv[i + 1]});
506  }
507  if (boost::starts_with(option, "--config-file=")) {
508  plugin_options_input.emplace_back(option);
509  }
510  if (option == "--plugin-directory") {
511  plugin_options_input.emplace_back("--plugin-directory");
512  plugin_options_input.emplace_back(std::string{argv[i + 1]});
513  }
514  if (boost::starts_with(option, "--plugin-directory=")) {
515  plugin_options_input.emplace_back(option);
516  }
517  if (option == "--plugin") {
518  plugin_options_input.emplace_back("--plugin");
519  plugin_options_input.emplace_back(std::string{argv[i + 1]});
520  }
521  if (boost::starts_with(option, "--plugin=")) {
522  plugin_options_input.emplace_back(option);
523  }
524  }
525 }
526 
527 
528 ELEMENTS_API int main(int argc, char* argv[]) {
529  std::string plugin_path {};
530  std::vector<std::string> plugin_list {};
531 
532  // This adds the current directory as a valid location for the default "sourcextractor++.conf" configuration
533  Elements::TempEnv local_env;
534  if (local_env["ELEMENTS_CONF_PATH"].empty()) {
535  local_env["ELEMENTS_CONF_PATH"] = ".:/etc";
536  } else {
537  local_env["ELEMENTS_CONF_PATH"] = ".:" + local_env["ELEMENTS_CONF_PATH"] + ":/etc";
538  }
539 
541 
542  // Try to be reasonably graceful with unhandled exceptions
544 
545  try {
546  // First we create a program which has a sole purpose to get the options for
547  // the plugin paths. Note that we do not want to have this helper program
548  // to handle any other options except of the plugin-directory and plugin, so
549  // we create a subset of the given options with only the necessary ones. We
550  // also turn off the the logging.
551  std::vector<int> masked_indices{};
552  std::vector<std::string> plugin_options_input{};
553  plugin_options_input.emplace_back("DummyProgram");
554  plugin_options_input.emplace_back("--log-level");
555  plugin_options_input.emplace_back("ERROR");
556  forwardOptions(argc, argv, plugin_options_input);
557 
558  int argc_tmp = plugin_options_input.size();
559  std::vector<const char *> argv_tmp(argc_tmp);
560  for (unsigned int i = 0; i < plugin_options_input.size(); ++i) {
561  auto& option_str = plugin_options_input[i];
562  argv_tmp[i] = option_str.data();
563  }
564 
565  CREATE_MANAGER_WITH_ARGS(plugin_options_program, PluginOptionsMain, plugin_path, plugin_list);
566  plugin_options_program.run(argc_tmp, const_cast<char **>(argv_tmp.data()));
567 
568  CREATE_MANAGER_WITH_ARGS(main, SEMain, plugin_path, plugin_list);
569  Elements::ExitCode exit_code = main.run(argc, argv);
570  return static_cast<Elements::ExitCodeType>(exit_code);
571  }
572  catch (const std::exception &e) {
573  logger.fatal() << e.what();
575  }
576  catch (...) {
577  logger.fatal() << "Unknown exception type!";
578  logger.fatal() << "Please, report this as a bug";
580  }
581 }
static long config_manager_id
void setBackgroundCheckImage(std::shared_ptr< Image< SeFloat >> background_image)
Definition: CheckImages.h:110
T set_terminate(T...args)
std::list< std::shared_ptr< SourceWithOnDemandProperties > > m_list
void setThresholdedCheckImage(std::shared_ptr< Image< SeFloat >> thresholded_image)
Definition: CheckImages.h:122
PluginManager plugin_manager
static Elements::Logging logger
static std::shared_ptr< TileManager > getInstance()
Definition: TileManager.h:137
static const std::string LIST_OUTPUT_PROPERTIES
void setSnrCheckImage(std::shared_ptr< Image< SeFloat >> snr_image)
Definition: CheckImages.h:126
SEMain(const std::string &plugin_path, const std::vector< std::string > &plugin_list)
static const std::string PROPERTY_COLUMN_MAPPING
std::string & m_plugin_path
static ConfigManager & getInstance(long id)
void printDefaults()
Print a configuration file populated with defaults.
constexpr double e
static std::shared_ptr< FitsFileManager > getInstance()
static void onTerminate() noexcept
T endl(T...args)
void info(const std::string &logMessage)
void setFilteredCheckImage(std::shared_ptr< Image< SeFloat >> filtered_image)
Definition: CheckImages.h:118
T end(T...args)
std::pair< po::options_description, po::positional_options_description > defineProgramArguments() override
Return the arguments that the program accepts.
Provides the detection image.
STL class.
T partition(T...args)
STL class.
T at(T...args)
std::list< std::shared_ptr< SourceGroupInterface > > m_list
PluginOptionsMain(std::string &plugin_path, std::vector< std::string > &plugin_list)
static void setupEnvironment(void)
T data(T...args)
std::shared_ptr< WriteableImage< unsigned int > > getSegmentationImage() const
Definition: CheckImages.h:54
virtual void handleMessage(const std::shared_ptr< SourceWithOnDemandProperties > &source) override
po::options_description config_parameters
boost::program_options::options_description defineSpecificProgramOptions() override
T what(T...args)
const std::vector< std::string > getOutputProperties()
static CheckImages & getInstance()
Definition: CheckImages.h:136
Elements::ExitCode mainMethod(std::map< std::string, po::variable_value > &args) override
long getUniqueManagerId()
The SegmentationFactory will provide a Segmentation implementation based on the current configuration...
std::underlying_type< ExitCode >::type ExitCodeType
po::options_description getConfigParameters()
virtual void configure(Euclid::Configuration::ConfigManager &manager) override
Method which should initialize the object.
Definition: CheckImages.cpp:67
#define ELEMENTS_API
void fatal(const std::string &logMessage)
static void writeDefaultMultiple(std::ostream &out, const po::option_description &opt, const boost::any &default_value)
Print a multiple-value option.
STL class.
STL class.
ELEMENTS_API int main(int argc, char *argv[])
virtual void reportConfigDependencies(Euclid::Configuration::ConfigManager &manager) const override
Registers all the Configuration dependencies.
Definition: CheckImages.cpp:40
T find(T...args)
void error(const std::string &logMessage)
static void writeDefault(std::ostream &out, const po::option_description &opt, const boost::any &default_value)
Print a simple option.
T c_str(T...args)
Elements::ExitCode mainMethod(std::map< std::string, boost::program_options::variable_value > &args) override
static std::shared_ptr< ConstantImage< T > > create(int width, int height, T constant_value)
Definition: ConstantImage.h:42
Observer interface to be used with Observable to implement the Observer pattern.
Definition: Observable.h:38
static const std::string DUMP_CONFIG
virtual void handleMessage(const std::shared_ptr< SourceGroupInterface > &group) override
void setVarianceCheckImage(std::shared_ptr< Image< SeFloat >> variance_image)
Definition: CheckImages.h:114
PluginManager handles the loading of plugins and calls their registration function, providing them with with a PluginAPI implementation.
Definition: PluginManager.h:53
std::string getPluginPath() const
static void forwardOptions(int argc, char *const *argv, std::vector< std::string > &plugin_options_input)
static Logging getLogger(const std::string &name="")
STL class.
std::vector< std::string > & m_plugin_list
static const std::string PROPERTY_COLUMN_MAPPING_ALL
#define CREATE_MANAGER_WITH_ARGS(MANAGER, ELEMENTS_PROGRAM,...)
T emplace_back(T...args)
static std::shared_ptr< ProcessedImage< T, P > > create(std::shared_ptr< const Image< T >> image_a, std::shared_ptr< const Image< T >> image_b)