SourceXtractorPlusPlus  0.19
SourceXtractor++, the next generation SExtractor
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DetectionImageConfig.cpp
Go to the documentation of this file.
1 
23 
24 #include <boost/regex.hpp>
25 using boost::regex;
26 using boost::regex_match;
27 using boost::smatch;
28 
32 
34 
36 
37 using namespace Euclid::Configuration;
38 namespace po = boost::program_options;
39 
40 namespace SourceXtractor {
41 
42 static const std::string DETECTION_IMAGE { "detection-image" };
43 static const std::string DETECTION_IMAGE_GAIN { "detection-image-gain" };
44 static const std::string DETECTION_IMAGE_FLUX_SCALE {"detection-image-flux-scale"};
45 static const std::string DETECTION_IMAGE_SATURATION { "detection-image-saturation" };
46 static const std::string DETECTION_IMAGE_INTERPOLATION { "detection-image-interpolation" };
47 static const std::string DETECTION_IMAGE_INTERPOLATION_GAP { "detection-image-interpolation-gap" };
48 
49 DetectionImageConfig::DetectionImageConfig(long manager_id) : Configuration(manager_id)
50 {}
51 
53  return { {"Detection image", {
54  {DETECTION_IMAGE.c_str(), po::value<std::string>(),
55  "Path to a fits format image to be used as detection image."},
56  {DETECTION_IMAGE_GAIN.c_str(), po::value<double>(),
57  "Detection image gain in e-/ADU (0 = infinite gain)"},
58  {DETECTION_IMAGE_FLUX_SCALE.c_str(), po::value<double>(),
59  "Detection image flux scale"},
60  {DETECTION_IMAGE_SATURATION.c_str(), po::value<double>(),
61  "Detection image saturation level (0 = no saturation)"},
62  {DETECTION_IMAGE_INTERPOLATION.c_str(), po::value<bool>()->default_value(true),
63  "Interpolate bad pixels in detection image"},
64  {DETECTION_IMAGE_INTERPOLATION_GAP.c_str(), po::value<int>()->default_value(5),
65  "Maximum number if pixels to interpolate over"}
66  }}};
67 }
68 
69 void DetectionImageConfig::initialize(const UserValues& args) {
70  // Normally we would define this one as required, but then --list-output-properties would be
71  // unusable unless we also specify --detection-image, which is not very intuitive.
72  // For this reason, we check for its existence here
73  if (args.find(DETECTION_IMAGE) == args.end()) {
74  throw Elements::Exception() << "'--" << DETECTION_IMAGE << "' is required but missing";
75  }
76 
78 
79  boost::regex hdu_regex(".*\\[[0-9]*\\]$");
80 
81  for (int i=0;; i++) {
82  DetectionImageExtension extension;
83 
84  std::shared_ptr<FitsImageSource> fits_image_source;
85  if (boost::regex_match(m_detection_image_path, hdu_regex)) {
86  if (i==0) {
87  fits_image_source = std::make_shared<FitsImageSource>(m_detection_image_path, 0, ImageTile::FloatImage);
88  } else {
89  break;
90  }
91  } else {
92  try {
93  fits_image_source = std::make_shared<FitsImageSource>(m_detection_image_path, i+1, ImageTile::FloatImage);
94  } catch (...) {
95  if (i==0) {
96  // Skip past primary HDU if it doesn't have an image
97  continue;
98  } else {
99  if (m_extensions.size() == 0) {
100  throw Elements::Exception() << "Can't find 2D image in FITS file: " << m_detection_image_path;
101  }
102  break;
103  }
104  }
105  }
106 
107  extension.m_image_source = fits_image_source;
109  extension.m_coordinate_system = std::make_shared<WCS>(*fits_image_source);
110 
111  double detection_image_gain = 0, detection_image_saturate = 0;
112  auto img_metadata = fits_image_source->getMetadata();
113 
114  if (img_metadata.count("GAIN")){
115  // read the keyword GAIN from the metadata
116  if (double* double_gain = boost::get<double>(&img_metadata.at("GAIN").m_value)){
117  detection_image_gain = *double_gain;
118  } else if (int64_t *int64_gain = boost::get<int64_t>(&img_metadata.at("GAIN").m_value)){
119  detection_image_gain = (double) *int64_gain;
120  }
121  else {
122  throw Elements::Exception() << "Keyword GAIN must be either float or int!";
123  }
124  }
125 
126  if (img_metadata.count("SATURATE")){
127  // read the keyword SATURATE from the metadata
128  if (double* double_saturate = boost::get<double>(&img_metadata.at("SATURATE").m_value)){
129  detection_image_saturate = *double_saturate;
130  } else if (int64_t *int64_saturate = boost::get<int64_t>(&img_metadata.at("SATURATE").m_value)){
131  detection_image_saturate = (double) *int64_saturate;
132  }
133  else {
134  throw Elements::Exception() << "Keyword SATURATE must be either float or int!";
135  }
136  }
137 
138  if (args.find(DETECTION_IMAGE_FLUX_SCALE) != args.end()) {
139  extension.m_flux_scale = args.find(DETECTION_IMAGE_FLUX_SCALE)->second.as<double>();
140  }
141  else if (img_metadata.count("FLXSCALE")) {
142  // read the keyword FLXSCALE from the metadata
143  if (double* f_scale = boost::get<double>(&img_metadata.at("FLXSCALE").m_value)){
144  extension.m_flux_scale = *f_scale;
145  } else if (int64_t *int64_f_scale = boost::get<int64_t>(&img_metadata.at("FLXSCALE").m_value)){
146  extension.m_flux_scale = (double) *int64_f_scale;
147  }
148  else {
149  throw Elements::Exception() << "Keyword FLXSCALE must be either float or int!";
150  }
151  }
152 
153  if (args.find(DETECTION_IMAGE_GAIN) != args.end()) {
154  extension.m_gain = args.find(DETECTION_IMAGE_GAIN)->second.as<double>();
155  }
156  else {
157  extension.m_gain = detection_image_gain;
158  }
159 
160  if (args.find(DETECTION_IMAGE_SATURATION) != args.end()) {
161  extension.m_saturation = args.find(DETECTION_IMAGE_SATURATION)->second.as<double>();
162  }
163  else {
164  extension.m_saturation = detection_image_saturate;
165  }
166 
167  extension.m_interpolation_gap = args.find(DETECTION_IMAGE_INTERPOLATION)->second.as<bool>() ?
168  std::max(0, args.find(DETECTION_IMAGE_INTERPOLATION_GAP)->second.as<int>()) : 0;
169 
170  // Adapt image and parameters to take flux_scale into consideration
171  if (extension.m_flux_scale != 1.0) {
172  extension.m_detection_image =
174  extension.m_gain /= extension.m_flux_scale;
175  extension.m_saturation *= extension.m_flux_scale;
176  }
177 
178  m_extensions.emplace_back(std::move(extension));
179  }
180 }
181 
183  return m_detection_image_path;
184 }
185 
187  if (getCurrentState() < State::INITIALIZED) {
188  throw Elements::Exception() << "getDetectionImage() call on not initialized DetectionImageConfig";
189  }
190  return m_extensions.at(index).m_detection_image;
191 }
192 
194  if (getCurrentState() < State::INITIALIZED) {
195  throw Elements::Exception() << "getCoordinateSystem() call on not initialized DetectionImageConfig";
196  }
197  return m_extensions.at(index).m_coordinate_system;
198 }
199 
200 } // SourceXtractor namespace
201 
202 
203 
static const std::string DETECTION_IMAGE_INTERPOLATION
static const std::string DETECTION_IMAGE_FLUX_SCALE
std::shared_ptr< DetectionImage > getDetectionImage(size_t index=0) const
static const std::string DETECTION_IMAGE_GAIN
static const std::string DETECTION_IMAGE_SATURATION
STL class.
static const std::string DETECTION_IMAGE_INTERPOLATION_GAP
STL class.
std::shared_ptr< CoordinateSystem > getCoordinateSystem(size_t index=0) const
std::map< std::string, Configuration::OptionDescriptionList > getProgramOptions() override
std::vector< DetectionImageExtension > m_extensions
void initialize(const UserValues &args) override
T max(T...args)
T move(T...args)
T find(T...args)
T c_str(T...args)
static const std::string DETECTION_IMAGE
static std::shared_ptr< ProcessedImage< T, P > > create(std::shared_ptr< const Image< T >> image_a, std::shared_ptr< const Image< T >> image_b)
static std::shared_ptr< BufferedImage< T > > create(std::shared_ptr< const ImageSource > source, std::shared_ptr< TileManager > tile_manager=TileManager::getInstance())