SourceXtractorPlusPlus  0.19
SourceXtractor++, the next generation SExtractor
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MeasurementImageConfig.cpp
Go to the documentation of this file.
1 /*
2  * Copyright © 2019-2022 Université de Genève, LMU Munich - Faculty of Physics, IAP-CNRS/Sorbonne Université
3  *
4  * This library is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU Lesser General Public License as published by the Free
6  * Software Foundation; either version 3.0 of the License, or (at your option)
7  * any later version.
8  *
9  * This library is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12  * details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 /*
19  * @file MeasurementImageConfig.cpp
20  * @author Nikolaos Apostolakos <nikoapos@gmail.com>
21  */
22 
23 #include <utility>
24 #include <limits>
25 
26 #include <boost/algorithm/string.hpp>
27 #include <boost/python/extract.hpp>
28 #include <boost/tokenizer.hpp>
29 
30 #include <ElementsKernel/Logging.h>
31 
32 #include <Pyston/GIL.h>
33 
37 
43 
45 
46 using namespace Euclid::Configuration;
47 namespace fs = boost::filesystem;
48 namespace py = boost::python;
49 
50 namespace SourceXtractor {
51 
52 MeasurementImageConfig::MeasurementImageConfig(long manager_id) : Configuration(manager_id) {
53  declareDependency<PythonConfig>();
54  declareDependency<WeightImageConfig>();
55  declareDependency<DetectionImageConfig>();
56 }
57 
58 namespace {
59 
61 
69 };
70 
71 void validateImagePaths(const PyMeasurementImage& image) {
72  if (!fs::exists(image.file)) {
73  throw Elements::Exception() << "File " << image.file << " does not exist";
74  }
75  if (image.weight_file != "" && !fs::exists(image.weight_file)) {
76  throw Elements::Exception() << "File " << image.weight_file << " does not exist";
77  }
78  if (image.psf_file != "" && boost::to_upper_copy(fs::path(image.psf_file).filename().string())!="NOPSF" && !fs::exists(image.psf_file)) {
79  throw Elements::Exception() << "File " << image.psf_file << " does not exist";
80  }
81 }
82 
83 std::shared_ptr<MeasurementImage> createMeasurementImage(
84  std::shared_ptr<FitsImageSource> fits_image_source, double flux_scale) {
86  if (flux_scale != 1.) {
87  image = MultiplyImage<MeasurementImage::PixelType>::create(image, flux_scale);
88  }
89  return image;
90 }
91 
92 WeightImageConfig::WeightType getWeightType(const std::string& type_string, const std::string& file_name) {
93  // check for a valid weight type
94  auto weight_type_name = boost::to_upper_copy(type_string);
95  if (weight_type_map.find(weight_type_name) == weight_type_map.end()) {
96  throw Elements::Exception() << "Unknown weight map type for measurement weight image " << file_name << ": "<< type_string;
97  }
98 
99  return weight_type_map[weight_type_name];
100 }
101 
102 std::shared_ptr<WeightImage> createWeightMap(const PyMeasurementImage& py_image) {
103  auto weight_type = getWeightType(py_image.weight_type, py_image.weight_file);
104 
105  // without an image nothing can be done
106  if (py_image.weight_file == "") {
109  throw Elements::Exception() << "Weight type '" << py_image.weight_type << "' is meaningless without a weight image";
110  }
111 
112  return nullptr;
113  }
114 
117  throw Elements::Exception() << "Please give an appropriate weight type for image: " << py_image.weight_file;
118  }
119 
120  auto weight_image_source =
121  std::make_shared<FitsImageSource>(py_image.weight_file, py_image.weight_hdu+1, ImageTile::FloatImage);
123  if (py_image.is_data_cube) {
124  weight_image_source->setLayer(py_image.weight_layer);
125  }
126 
127  logger.debug() << "w: " << weight_map->getWidth() << " h: " << weight_map->getHeight()
128  << " t: " << py_image.weight_type << " s: " << py_image.weight_scaling;
129  weight_map = WeightImageConfig::convertWeightMap(weight_map, weight_type, py_image.weight_scaling);
130 
131  return weight_map;
132 }
133 
134 WeightImage::PixelType extractWeightThreshold(const PyMeasurementImage& py_image) {
135  if (!py_image.has_weight_threshold) {
137  }
138  WeightImage::PixelType threshold = py_image.weight_threshold;
139  auto weight_type_name = boost::to_upper_copy(py_image.weight_type);
140  switch (weight_type_map[weight_type_name]) {
141  default:
144  threshold = threshold * threshold;
145  break;
147  break;
149  if (threshold > 0) {
150  threshold = 1.0 / threshold;
151  } else {
153  }
154  break;
155  }
156  return threshold;
157 }
158 
159 }
160 
161 void MeasurementImageConfig::initialize(const UserValues&) {
162  auto images = getDependency<PythonConfig>().getInterpreter().getMeasurementImages();
163 
164  if (images.size() > 0) {
165  for (auto& p : images) {
166  PyMeasurementImage& py_image = p.second;
167  validateImagePaths(py_image);
168 
169  logger.debug() << "Loading measurement image: " << py_image.file << " HDU: " << py_image.image_hdu;
170  logger.debug() << "\tWeight: " << py_image.weight_file << " HDU: " << py_image.weight_hdu;
171  logger.debug() << "\tWeight threshold: " << py_image.weight_threshold << " hasThreshold: " << py_image.has_weight_threshold;
172  logger.debug() << "\tPSF: " << py_image.psf_file << " HDU: " << py_image.psf_hdu;
173  logger.debug() << "\tGain: " << py_image.gain;
174  logger.debug() << "\tSaturation: " << py_image.saturation;
175  logger.debug() << "\tFlux scale: " << py_image.flux_scale;
176 
177  auto flux_scale = py_image.flux_scale;
178 
180 
181  info.m_path = py_image.file;
182  info.m_psf_path = py_image.psf_file;
183 
184  info.m_is_data_cube = py_image.is_data_cube;
185  info.m_image_layer = py_image.image_layer;
186  info.m_weight_layer = py_image.weight_layer;
187 
188  auto fits_image_source =
189  std::make_shared<FitsImageSource>(py_image.file, py_image.image_hdu+1, ImageTile::FloatImage);
190 
191  if (py_image.is_data_cube) {
192  fits_image_source->setLayer(py_image.image_layer);
193  }
194 
195  info.m_measurement_image = createMeasurementImage(fits_image_source, py_image.flux_scale);
196  info.m_coordinate_system = std::make_shared<WCS>(*fits_image_source);
197 
198  info.m_gain = py_image.gain / flux_scale;
199  info.m_saturation_level = py_image.saturation * flux_scale;
200  info.m_id = py_image.id;
201 
202  info.m_absolute_weight= py_image.weight_absolute;
203  info.m_weight_threshold = extractWeightThreshold(py_image);
204 
207 
208  auto weight_map = createWeightMap(py_image);
209 
210  if (weight_map != nullptr && flux_scale != 1. && py_image.weight_absolute) {
212  weight_map, py_image.flux_scale * py_image.flux_scale);
213  } else {
214  info.m_weight_image = weight_map;
215  }
216 
217  info.m_weight_type = getWeightType(py_image.weight_type, py_image.weight_file);
218 
219  info.m_image_hdu = py_image.image_hdu + 1;
220  info.m_psf_hdu = py_image.psf_hdu + 1;
221  info.m_weight_hdu = py_image.weight_hdu + 1;
222 
223  m_image_infos.emplace_back(std::move(info));
224  }
225  } else {
226  logger.debug() << "No measurement image provided, using the detection image for measurements";
227 
228  auto detection_image = getDependency<DetectionImageConfig>();
229  auto weight_image = getDependency<WeightImageConfig>();
230 
231  // note: flux scale was already applied
232 
233  m_image_infos.emplace_back(MeasurementImageInfo {
234  detection_image.getDetectionImagePath(),
235  "", // psf path
236 
237  detection_image.getDetectionImage(),
238  detection_image.getCoordinateSystem(),
239  weight_image.getWeightImage(),
240  weight_image.getWeightType(),
241 
242  weight_image.isWeightAbsolute(),
243  weight_image.getWeightThreshold(),
244  (SeFloat) detection_image.getGain(),
245  (SeFloat) detection_image.getSaturation(),
246 
247  false,
248  0.0,
249 
250  0, // id
251 
252  1,1,1 // HDUs
253  });
254 
255 
256  }
257 }
258 
259 } // end of namespace SourceXtractor
static auto logger
Definition: WCS.cpp:41
const int id
Definition: PyId.h:35
SeFloat32 SeFloat
Definition: Types.h:32
void debug(const std::string &logMessage)
STL class.
STL class.
void initialize(const UserValues &args) override
static std::shared_ptr< WeightImage > convertWeightMap(std::shared_ptr< WeightImage > weight_image, WeightType weight_type, WeightImage::PixelType scaling=1)
std::vector< MeasurementImageInfo > m_image_infos
T move(T...args)
static Logging getLogger(const std::string &name="")
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())