18 from __future__
import division, print_function
24 import _SourceXtractorPy
as cpp
26 if sys.version_info.major < 3:
27 from StringIO
import StringIO
29 from io
import StringIO
34 super(FitsFile, self).
__init__(str(filename))
48 d[a.key()] = headers[a.key()]
57 A MeasurementImage is the processing unit for SourceXtractor++. Measurements and model fitting can be done
58 over one, or many, of them. It models the image, plus its associated weight file, PSF, etc.
62 fits_file : str or FitsFile object
63 The path to a FITS image, or an instance of FitsFile
65 The path to a PSF. It can be either a FITS image, or a PSFEx model.
66 weight_file : str or FitsFile
67 The path to a FITS image with the pixel weights, or an instance of FitsFile
69 Image gain. If None, `gain_keyword` will be used instead.
71 Keyword for the header containing the gain.
73 Saturation value. If None, `saturation_keyword` will be used instead.
74 saturation_keyword : str
75 Keyword for the header containing the saturation value.
77 Flux scaling. Each pixel value will be multiplied by this. If None, `flux_scale_keyword` will be used
79 flux_scale_keyword : str
80 Keyword for the header containing the flux scaling.
82 The type of the weight image. It must be one of:
85 The image itself is used to compute internally a constant variance (default)
87 The image itself is used to compute internally a variance map
89 The weight image must contain a weight-map in units of absolute standard deviations
92 The weight image must contain a weight-map in units of relative variance.
94 The weight image must contain a weight-map in units of relative weights. The data are converted
96 weight_absolute : bool
97 If False, the weight map will be scaled according to an absolute variance map built from the image itself.
98 weight_scaling : float
99 Apply an scaling to the weight map.
100 weight_threshold : float
101 Pixels with weights beyond this value are treated just like pixels discarded by the masking process.
102 constant_background : float
103 If set a constant background of that value is assumed for the image instead of using automatic detection
105 For multi-extension FITS file specifies the HDU number for the image. Default 0 (primary HDU)
107 For multi-extension FITS file specifies the HDU number for the psf. Defaults to the same value as image_hdu
109 For multi-extension FITS file specifies the HDU number for the weight. Defaults to the same value as image_hdu
114 setattr(self, attr_name, value)
116 expected_type = type(getattr(self, attr_name))
117 raise TypeError(
'Expecting {} for {}, got {}'.format(expected_type.__name__, attr_name,
118 type(value).__name__))
120 def __init__(self, fits_file, psf_file=None, weight_file=None, gain=None,
121 gain_keyword=
'GAIN', saturation=
None, saturation_keyword=
'SATURATE',
122 flux_scale=
None, flux_scale_keyword=
'FLXSCALE',
123 weight_type=
'none', weight_absolute=
False, weight_scaling=1.,
124 weight_threshold=
None, constant_background=
None,
125 image_hdu=0, psf_hdu=
None, weight_hdu=
None
130 if isinstance(fits_file, FitsFile):
132 file_path = fits_file.filename
135 file_path = fits_file
137 if isinstance(weight_file, FitsFile):
138 weight_file = weight_file.filename
140 super(MeasurementImage, self).
__init__(os.path.abspath(file_path),
141 os.path.abspath(psf_file)
if psf_file
else '',
142 os.path.abspath(weight_file)
if weight_file
else '')
144 if image_hdu < 0
or (weight_hdu
is not None and weight_hdu < 0)
or (
145 psf_hdu
is not None and psf_hdu < 0):
146 raise ValueError(
'HDU indices start at 0')
149 'IMAGE_FILENAME': self.file,
150 'PSF_FILENAME': self.psf_file,
151 'WEIGHT_FILENAME': self.weight_file
154 self.meta.update(hdu_list.get_headers(image_hdu))
158 elif gain_keyword
in self.
meta:
163 if saturation
is not None:
165 elif saturation_keyword
in self.
meta:
170 if flux_scale
is not None:
172 elif flux_scale_keyword
in self.
meta:
180 if weight_threshold
is None:
186 if constant_background
is not None:
188 self.
_set_checked(
'constant_background_value', constant_background)
200 if weight_hdu
is None:
210 Human readable representation for the object
212 return 'Image {}: {} / {}, PSF: {} / {}, Weight: {} / {}'.format(
213 self.id, self.
meta[
'IMAGE_FILENAME'], self.image_hdu, self.
meta[
'PSF_FILENAME'],
215 self.
meta[
'WEIGHT_FILENAME'], self.weight_hdu)
219 def __init__(self, fits_file, psf_file=None, weight_file=None, gain=None,
220 gain_keyword=
'GAIN', saturation=
None, saturation_keyword=
'SATURATE',
221 flux_scale=
None, flux_scale_keyword=
'FLXSCALE',
222 weight_type=
'none', weight_absolute=
False, weight_scaling=1.,
223 weight_threshold=
None, constant_background=
None,
224 image_hdu=0, psf_hdu=
None, weight_hdu=
None,
225 image_layer=0, weight_layer=0):
226 super(DataCubeSlice, self).
__init__(fits_file, psf_file, weight_file, gain,
227 gain_keyword, saturation, saturation_keyword,
228 flux_scale, flux_scale_keyword,
229 weight_type, weight_absolute, weight_scaling,
230 weight_threshold, constant_background,
231 image_hdu, psf_hdu, weight_hdu)
242 Human readable representation for the object
244 return 'DataCubeSlice {}: {} / {} / {}, PSF: {} / {}, Weight: {} / {} / {}'.format(
245 self.id, self.
meta[
'IMAGE_FILENAME'], self.image_hdu, self.
image_layer,
246 self.
meta[
'PSF_FILENAME'], self.psf_hdu,
252 Models the grouping of images. Measurement can *not* be made directly on instances of this type.
253 The configuration must be "frozen" before creating a MeasurementGroup
262 Constructor. It is not recommended to be used directly. Use instead load_fits_image or load_fits_images.
267 if len(kwargs) != 1
or (
'images' not in kwargs
and 'subgroups' not in kwargs):
268 raise ValueError(
'ImageGroup only takes as parameter one of "images" or "subgroups"')
269 key = list(kwargs.keys())[0]
271 if isinstance(kwargs[key], list):
275 if key ==
'subgroups':
278 self.__subgroup_names.add(name)
289 How may subgroups or images are there in this group
298 Allows to iterate on the contained subgroups or images
309 return self.__subgroups.__iter__()
311 return self.__images.__iter__()
315 Splits the group in various subgroups, applying a filter on the contained images. If the group has
316 already been split, applies the split to each subgroup.
320 grouping_method : callable
321 A callable that receives as a parameter the list of contained images, and returns
322 a list of tuples, with the grouping key value, and the list of grouped images belonging to the given key.
332 If some images have not been grouped by the callable.
337 sub_group.split(grouping_method)
339 subgrouped_images = grouping_method(self.
__images)
340 if sum(len(p[1])
for p
in subgrouped_images) != len(self.
__images):
342 raise ValueError(
'Some images were not grouped')
344 for k, im_list
in subgrouped_images:
346 self.__subgroup_names.add(k)
347 self.__subgroups.append((k,
ImageGroup(images=im_list)))
352 Add new images to the group.
356 images : list of, or a single, MeasurementImage
361 If the group has been split, no new images can be added.
364 raise ValueError(
'ImageGroup is already subgrouped')
365 if isinstance(images, MeasurementImage):
366 self.__images.append(images)
368 self.__images.extend(images)
372 Add a subgroup to a group.
377 The new of the new group
382 raise Exception(
'ImageGroup is not subgrouped yet')
384 raise Exception(
'Subgroup {} alread exists'.format(name))
385 self.__subgroup_names.add(name)
386 self.__subgroups.append((name, group))
393 True if the group is a leaf group
404 The name of the subgroup.
414 If the group has not been split.
416 If the group has not been found.
419 raise ValueError(
'ImageGroup is not subgrouped yet')
421 return next(x
for x
in self.
__subgroups if x[0] == name)[1]
422 except StopIteration:
423 raise KeyError(
'Group {} not found'.format(name))
425 def print(self, prefix='', show_images=False, file=sys.stderr):
427 Print a human-readable representation of the group.
432 Print each line with this prefix. Used internally for indentation.
434 Show the images belonging to a leaf group.
436 Where to print the representation. Defaults to sys.stderr
439 print(
'{}Image List ({})'.format(prefix, len(self.
__images)), file=file)
442 print(
'{} {}'.format(prefix, im), file=file)
444 print(
'{}Image sub-groups: {}'.format(prefix,
448 print(
'{} {}:'.format(prefix, name), file=file)
449 group.print(prefix +
' ', show_images, file)
456 A human-readable representation of the group
459 self.
print(show_images=
True, file=string)
460 return string.getvalue()
465 Callable that can be used to split an ImageGroup by a keyword value (i.e. FILTER).
470 FITS header keyword (i.e. FILTER)
487 images : list of MeasurementImage
488 List of images to group
492 list of tuples of str and list of MeasurementImage
494 (R, [frame_r_01.fits, frame_r_02.fits]),
495 (G, [frame_g_01.fits, frame_g_02.fits])
500 if self.
__key not in im.meta:
501 raise KeyError(
'The image {}[{}] does not contain the key {}'.format(
502 im.meta[
'IMAGE_FILENAME'], im.image_hdu, self.
__key
504 if im.meta[self.
__key]
not in result:
505 result[im.meta[self.
__key]] = []
506 result[im.meta[self.
__key]].append(im)
507 return [(k, result[k])
for k
in result]
512 Callable that can be used to split an ImageGroup by a keyword value (i.e. FILTER), applying a regular
513 expression and using the first matching group as key.
520 Regular expression. The first matching group will be used as grouping key.
538 images : list of MeasurementImage
539 List of images to group
543 list of tuples of str and list of MeasurementImage
547 if self.
__key not in im.meta:
548 raise KeyError(
'The image {}[{}] does not contain the key {}'.format(
549 im.meta[
'IMAGE_FILENAME'], im.image_hdu, self.
__key
552 if group
not in result:
554 result[group].append(im)
555 return [(k, result[k])
for k
in result]
560 Once an instance of this class is created from an ImageGroup, its configuration is "frozen". i.e.
561 no new images can be added, or no new grouping applied.
565 image_group : ImageGroup
568 def __init__(self, image_group, is_subgroup=False):
574 if image_group.is_leaf():
575 self.
__images = [im
for im
in image_group]
586 return self.__subgroups.__iter__()
588 return self.__images.__iter__()
592 The subgroup with the given name or image with the given index depending on whether this is a leaf group.
597 Subgroup name or image index
601 MeasurementGroup or MeasurementImage
606 If we can't find what we want
611 return next(x
for x
in self.
__subgroups if x[0] == index)[1]
612 except StopIteration:
613 raise KeyError(
'Group {} not found'.format(index))
618 raise KeyError(
'Image #{} not found'.format(index))
625 Number of subgroups, or images contained within the group
637 True if the group is a leaf group
641 def print(self, prefix='', show_images=False, file=sys.stderr):
643 Print a human-readable representation of the group.
648 Print each line with this prefix. Used internally for indentation.
650 Show the images belonging to a leaf group.
652 Where to print the representation. Defaults to sys.stderr
655 print(
'{}Image List ({})'.format(prefix, len(self.
__images)), file=file)
658 print(
'{} {}'.format(prefix, im), file=file)
660 print(
'{}Measurement sub-groups: {}'.format(prefix,
','.
join(
663 print(
'{} {}:'.format(prefix, name), file=file)
664 group.print(prefix +
' ', show_images, file=file)
671 A human-readable representation of the group
674 self.
print(show_images=
True, file=string)
675 return string.getvalue()
ELEMENTS_API auto join(Args &&...args) -> decltype(joinPath(std::forward< Args >(args)...))