LSST Applications  21.0.0+04719a4bac,21.0.0-1-ga51b5d4+f5e6047307,21.0.0-11-g2b59f77+a9c1acf22d,21.0.0-11-ga42c5b2+86977b0b17,21.0.0-12-gf4ce030+76814010d2,21.0.0-13-g1721dae+760e7a6536,21.0.0-13-g3a573fe+768d78a30a,21.0.0-15-g5a7caf0+f21cbc5713,21.0.0-16-g0fb55c1+b60e2d390c,21.0.0-19-g4cded4ca+71a93a33c0,21.0.0-2-g103fe59+bb20972958,21.0.0-2-g45278ab+04719a4bac,21.0.0-2-g5242d73+3ad5d60fb1,21.0.0-2-g7f82c8f+8babb168e8,21.0.0-2-g8f08a60+06509c8b61,21.0.0-2-g8faa9b5+616205b9df,21.0.0-2-ga326454+8babb168e8,21.0.0-2-gde069b7+5e4aea9c2f,21.0.0-2-gecfae73+1d3a86e577,21.0.0-2-gfc62afb+3ad5d60fb1,21.0.0-25-g1d57be3cd+e73869a214,21.0.0-3-g357aad2+ed88757d29,21.0.0-3-g4a4ce7f+3ad5d60fb1,21.0.0-3-g4be5c26+3ad5d60fb1,21.0.0-3-g65f322c+e0b24896a3,21.0.0-3-g7d9da8d+616205b9df,21.0.0-3-ge02ed75+a9c1acf22d,21.0.0-4-g591bb35+a9c1acf22d,21.0.0-4-g65b4814+b60e2d390c,21.0.0-4-gccdca77+0de219a2bc,21.0.0-4-ge8a399c+6c55c39e83,21.0.0-5-gd00fb1e+05fce91b99,21.0.0-6-gc675373+3ad5d60fb1,21.0.0-64-g1122c245+4fb2b8f86e,21.0.0-7-g04766d7+cd19d05db2,21.0.0-7-gdf92d54+04719a4bac,21.0.0-8-g5674e7b+d1bd76f71f,master-gac4afde19b+a9c1acf22d,w.2021.13
LSST Data Management Base Package
Namespaces | Functions
lsst.afw.display Namespace Reference

Namespaces

 ds9
 
 ds9Regions
 
 interface
 
 rgb
 
 utils
 
 virtualDevice
 

Functions

 PYBIND11_MODULE (_simpleFits, mod)
 
 PYBIND11_MODULE (_rgb, mod)
 
template<typename ImageT >
void replaceSaturatedPixels (ImageT &rim, ImageT &gim, ImageT &bim, int borderWidth, float saturatedPixelValue)
 
template void replaceSaturatedPixels (image::MaskedImage< float > &rim, image::MaskedImage< float > &gim, image::MaskedImage< float > &bim, int borderWidth, float saturatedPixelValue)
 
template<class T >
std::pair< double, double > getZScale (image::Image< T > const &image, int const nSamples=1000, double const contrast=0.25)
 Calculate an IRAF/ds9-style zscaling. More...
 
template std::pair< double, double > getZScale (image::Image< std::uint16_t > const &image, int const nSamples, double const contrast)
 
template std::pair< double, double > getZScale (image::Image< float > const &image, int const nSamples, double const contrast)
 
template<typename ImageT >
void writeBasicFits (int fd, ImageT const &data, geom::SkyWcs const *Wcs, char const *title)
 
template<typename ImageT >
void writeBasicFits (std::string const &filename, ImageT const &data, geom::SkyWcs const *Wcs, char const *title)
 
template<typename ImageT >
void writeBasicFits (int fd, ImageT const &data, lsst::afw::geom::SkyWcs const *Wcs=NULL, char const *title=NULL)
 
template<typename ImageT >
void writeBasicFits (std::string const &filename, ImageT const &data, lsst::afw::geom::SkyWcs const *Wcs=NULL, const char *title=NULL)
 

Function Documentation

◆ getZScale() [1/3]

template std::pair<double, double> lsst::afw::display::getZScale ( image::Image< float > const &  image,
int const  nSamples,
double const  contrast 
)

◆ getZScale() [2/3]

template std::pair<double, double> lsst::afw::display::getZScale ( image::Image< std::uint16_t > const &  image,
int const  nSamples,
double const  contrast 
)

◆ getZScale() [3/3]

template<class T >
std::pair< double, double > lsst::afw::display::getZScale ( image::Image< T > const &  image,
int const  nSamples = 1000,
double const  contrast = 0.25 
)

Calculate an IRAF/ds9-style zscaling.

To quote Frank Valdes (http://iraf.net/forum/viewtopic.php?showtopic=134139)

ZSCALE ALGORITHM

The zscale algorithm is designed to display the  image  values  near
the  median  image  value  without  the  time  consuming  process of
computing a full image histogram.  This is particularly  useful  for
astronomical  images  which  generally  have a very peaked histogram
corresponding to  the  background  sky  in  direct  imaging  or  the
continuum in a two dimensional spectrum.

The  sample  of pixels, specified by values greater than zero in the
sample mask zmask or by an  image  section,  is  selected  up  to  a
maximum  of nsample pixels.  If a bad pixel mask is specified by the
bpmask parameter then any pixels with mask values which are  greater
than  zero  are not counted in the sample.  Only the first pixels up
to the limit are selected where the order is by line beginning  from
the  first line.  If no mask is specified then a grid of pixels with
even spacing along lines and columns that  make  up  a  number  less
than or equal to the maximum sample size is used.

If  a  contrast of zero is specified (or the zrange flag is used and
the image does not have a  valid  minimum/maximum  value)  then  the
minimum  and maximum of the sample is used for the intensity mapping
range.

If the contrast  is  not  zero  the  sample  pixels  are  ranked  in
brightness  to  form  the  function  I(i) where i is the rank of the
pixel and I is its value.  Generally the midpoint of  this  function
(the  median) is very near the peak of the image histogram and there
is a well defined slope about the midpoint which is related  to  the
width  of the histogram.  At the ends of the I(i) function there are
a few very bright and dark pixels due to objects and defects in  the
field.   To  determine  the  slope  a  linear  function  is fit with
iterative rejection;

<code>
        I(i) = intercept + slope * (i - midpoint)
</code>

If more than half of the points are rejected then there is  no  well
defined  slope  and  the full range of the sample defines z1 and z2.
Otherwise the endpoints of the linear function  are  used  (provided
they are within the original range of the sample):

<code>
        z1 = I(midpoint) + (slope / contrast) * (1 - midpoint)
        z2 = I(midpoint) + (slope / contrast) * (npoints - midpoint)
</code>

As  can  be  seen,  the parameter contrast may be used to adjust the
contrast produced by this algorithm.
Parameters
imageThe image we wish to stretch
nSamplesNumber of samples to use
contrastStretch parameter; see description

Definition at line 167 of file _scaling.cc.

167  {
168  // extract samples
169  std::vector<T> vSample;
170  getSample(image, nSamples, vSample);
171  int nPix = vSample.size();
172 
173  if (vSample.empty()) {
174  throw LSST_EXCEPT(pex::exceptions::RuntimeError, "ZScale: No pixel in image is finite");
175  }
176 
177  std::sort(vSample.begin(), vSample.end());
178 
179  // max, min, median
180  // N.b. you can get a median in linear time, but we need the sorted array for fitLine()
181  // If we wanted to speed this up, the best option would be to quantize
182  // the pixel values and build a histogram
183  double const zmin = vSample.front();
184  double const zmax = vSample.back();
185  int const iCenter = nPix / 2;
186  T median = (nPix & 1) ? vSample[iCenter] : (vSample[iCenter] + vSample[iCenter + 1]) / 2;
187 
188  // fit a line to the sorted sample
189  const int maxRejectionRatio = 2;
190  const int npixelsMin = 5;
191 
192  int minpix = std::max(npixelsMin, nPix / maxRejectionRatio);
193  int nGrow = std::max(1, nPix / 100);
194 
195  const double nSigmaClip = 2.5;
196  const int nIterations = 5;
197 
198  int nGoodPix = 0;
199  std::pair<double, double> ret = fitLine(&nGoodPix, vSample, nSigmaClip, nGrow, minpix, nIterations);
200 #if 0 // unused, but calculated and potentially useful
201  double const zstart = ret.first;
202 #endif
203  double const zslope = ret.second;
204 
205  double z1, z2;
206  if (nGoodPix < minpix) {
207  z1 = zmin;
208  z2 = zmax;
209  } else {
210  double const slope = zslope / contrast;
211 
212  z1 = std::max(zmin, median - iCenter * slope);
213  z2 = std::min(zmax, median + (nPix - iCenter - 1) * slope);
214  }
215 
216  return std::make_pair(z1, z2);
217 }
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
T back(T... args)
T begin(T... args)
T empty(T... args)
T end(T... args)
T front(T... args)
T make_pair(T... args)
T max(T... args)
T min(T... args)
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
T size(T... args)
T sort(T... args)

◆ PYBIND11_MODULE() [1/2]

lsst::afw::display::PYBIND11_MODULE ( _rgb  ,
mod   
)

Definition at line 38 of file _rgb.cc.

38  {
39  /* Module level */
40  lsst::utils::python::WrapperCollection wrappers(mod, "lsst.afw.display.rbg");
41  wrappers.wrap([](auto &mod) {
42  mod.def("replaceSaturatedPixels", replaceSaturatedPixels<lsst::afw::image::MaskedImage<float>>,
43  "rim"_a, "gim"_a, "bim"_a, "borderWidth"_a = 2, "saturatedPixelValue"_a = 65535);
44  mod.def("getZScale", getZScale<std::uint16_t>, "image"_a, "nsamples"_a = 1000, "contrast"_a = 0.25);
45  mod.def("getZScale", getZScale<float>, "image"_a, "nsamples"_a = 1000, "contrast"_a = 0.25);
46  });
47  wrappers.finish();
48 }
A class to manipulate images, masks, and variance as a single object.
Definition: MaskedImage.h:73
A helper class for subdividing pybind11 module across multiple translation units (i....
Definition: python.h:242
void replaceSaturatedPixels(ImageT &rim, ImageT &gim, ImageT &bim, int borderWidth, float saturatedPixelValue)
Definition: _saturated.cc:32

◆ PYBIND11_MODULE() [2/2]

lsst::afw::display::PYBIND11_MODULE ( _simpleFits  ,
mod   
)

Definition at line 58 of file _simpleFits.cc.

58  {
59  lsst::utils::python::WrapperCollection wrappers(mod, "lsst.afw.display");
60  declareAll<image::Image<std::uint16_t>>(wrappers);
61  declareAll<image::Image<std::uint64_t>>(wrappers);
62  declareAll<image::Image<int>>(wrappers);
63  declareAll<image::Image<float>>(wrappers);
64  declareAll<image::Image<double>>(wrappers);
65  declareAll<image::Mask<std::uint16_t>>(wrappers);
66  declareAll<image::Mask<image::MaskPixel>>(wrappers);
67  wrappers.finish();
68 }

◆ replaceSaturatedPixels() [1/2]

template void lsst::afw::display::replaceSaturatedPixels ( image::MaskedImage< float > &  rim,
image::MaskedImage< float > &  gim,
image::MaskedImage< float > &  bim,
int  borderWidth,
float  saturatedPixelValue 
)

◆ replaceSaturatedPixels() [2/2]

template<typename ImageT >
void lsst::afw::display::replaceSaturatedPixels ( ImageT &  rim,
ImageT &  gim,
ImageT &  bim,
int  borderWidth,
float  saturatedPixelValue 
)

Definition at line 32 of file _saturated.cc.

37  {
38  int const width = rim.getWidth(), height = rim.getHeight();
39  int const x0 = rim.getX0(), y0 = rim.getY0();
40 
41  if (width != gim.getWidth() || height != gim.getHeight() || x0 != gim.getX0() || y0 != gim.getY0()) {
42  throw LSST_EXCEPT(
43  pex::exceptions::InvalidParameterError,
44  str(boost::format("R image has different size/origin from G image "
45  "(%dx%d+%d+%d v. %dx%d+%d+%d") %
46  width % height % x0 % y0 % gim.getWidth() % gim.getHeight() % gim.getX0() % gim.getY0()));
47  }
48  if (width != bim.getWidth() || height != bim.getHeight() || x0 != bim.getX0() || y0 != bim.getY0()) {
49  throw LSST_EXCEPT(
50  pex::exceptions::InvalidParameterError,
51  str(boost::format("R image has different size/origin from B image "
52  "(%dx%d+%d+%d v. %dx%d+%d+%d") %
53  width % height % x0 % y0 % bim.getWidth() % bim.getHeight() % bim.getX0() % bim.getY0()));
54  }
55 
56  bool const useMaxPixel = !std::isfinite(saturatedPixelValue);
57 
58  SetPixels<typename ImageT::Image> setR, setG, setB; // functors used to set pixel values
59 
60  // Find all the saturated pixels in any of the three image
61  int const npixMin = 1; // minimum number of pixels in an object
62  afw::image::MaskPixel const SAT = rim.getMask()->getPlaneBitMask("SAT");
63  detection::Threshold const satThresh(SAT, detection::Threshold::BITMASK);
64 
65  detection::FootprintSet sat(*rim.getMask(), satThresh, npixMin);
66  sat.merge(detection::FootprintSet(*gim.getMask(), satThresh, npixMin));
67  sat.merge(detection::FootprintSet(*bim.getMask(), satThresh, npixMin));
68  // go through the list of saturated regions, determining the mean colour of the surrounding pixels
69  typedef detection::FootprintSet::FootprintList FootprintList;
70  std::shared_ptr<FootprintList> feet = sat.getFootprints();
71  for (FootprintList::const_iterator ptr = feet->begin(), end = feet->end(); ptr != end; ++ptr) {
73  auto const bigFoot = std::make_shared<detection::Footprint>(foot->getSpans()->dilated(borderWidth),
74  foot->getRegion());
75 
76  double sumR = 0, sumG = 0, sumB = 0; // sum of all non-saturated adjoining pixels
77  double maxR = 0, maxG = 0, maxB = 0; // maximum of non-saturated adjoining pixels
78 
79  for (auto span = bigFoot->getSpans()->begin(), send = bigFoot->getSpans()->end(); span != send;
80  ++span) {
81  int const y = span->getY() - y0;
82  if (y < 0 || y >= height) {
83  continue;
84  }
85  int sx0 = span->getX0() - x0;
86  if (sx0 < 0) {
87  sx0 = 0;
88  }
89  int sx1 = span->getX1() - x0;
90  if (sx1 >= width) {
91  sx1 = width - 1;
92  }
93 
94  for (typename ImageT::iterator rptr = rim.at(sx0, y), rend = rim.at(sx1 + 1, y),
95  gptr = gim.at(sx0, y), bptr = bim.at(sx0, y);
96  rptr != rend; ++rptr, ++gptr, ++bptr) {
97  if (!((rptr.mask() | gptr.mask() | bptr.mask()) & SAT)) {
98  float val = rptr.image();
99  sumR += val;
100  if (val > maxR) {
101  maxR = val;
102  }
103 
104  val = gptr.image();
105  sumG += val;
106  if (val > maxG) {
107  maxG = val;
108  }
109 
110  val = bptr.image();
111  sumB += val;
112  if (val > maxB) {
113  maxB = val;
114  }
115  }
116  }
117  }
118  // OK, we have the mean fluxes for the pixels surrounding this set of saturated pixels
119  // so we can figure out the proper values to use for the saturated ones
120  float R = 0, G = 0, B = 0; // mean intensities
121  if (sumR + sumB + sumG > 0) {
122  if (sumR > sumG) {
123  if (sumR > sumB) {
124  R = useMaxPixel ? maxR : saturatedPixelValue;
125 
126  G = (R * sumG) / sumR;
127  B = (R * sumB) / sumR;
128  } else {
129  B = useMaxPixel ? maxB : saturatedPixelValue;
130  R = (B * sumR) / sumB;
131  G = (B * sumG) / sumB;
132  }
133  } else {
134  if (sumG > sumB) {
135  G = useMaxPixel ? maxG : saturatedPixelValue;
136  R = (G * sumR) / sumG;
137  B = (G * sumB) / sumG;
138  } else {
139  B = useMaxPixel ? maxB : saturatedPixelValue;
140  R = (B * sumR) / sumB;
141  G = (B * sumG) / sumB;
142  }
143  }
144  }
145  // Now that we know R, G, and B we can fix the values
146  setR.setValue(R);
147  foot->getSpans()->applyFunctor(setR, *rim.getImage());
148  setG.setValue(G);
149  foot->getSpans()->applyFunctor(setG, *gim.getImage());
150  setB.setValue(B);
151  foot->getSpans()->applyFunctor(setB, *bim.getImage());
152  }
153 }
int end
uint64_t * ptr
Definition: RangeSet.cc:88
int y
Definition: SpanSet.cc:49
T isfinite(T... args)
std::int32_t MaskPixel
default type for Masks and MaskedImage Masks
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
ImageT val
Definition: CR.cc:146

◆ writeBasicFits() [1/4]

template<typename ImageT >
void lsst::afw::display::writeBasicFits ( int  fd,
ImageT const &  data,
geom::SkyWcs const *  Wcs,
char const *  title 
)

Definition at line 360 of file simpleFits.cc.

364  {
365  /*
366  * Allocate cards for FITS headers
367  */
368  std::list<Card> cards;
369  /*
370  * What sort if image is it?
371  */
372  int bitpix = lsst::afw::fits::getBitPix<typename ImageT::Pixel>();
373  if (bitpix == 20) { // cfitsio for "Unsigned short"
374  cards.push_back(Card("BZERO", 32768.0, ""));
375  cards.push_back(Card("BSCALE", 1.0, ""));
376  bitpix = 16;
377  } else if (bitpix == 0) {
378  throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError, "Unsupported image type");
379  }
380  /*
381  * Generate WcsA, pixel coordinates, allowing for X0 and Y0
382  */
383  addWcs("A", cards, data.getX0(), data.getY0());
384  /*
385  * Now WcsB, so that pixel (0,0) is correctly labelled (but ignoring XY0)
386  */
387  addWcs("B", cards);
388 
389  if (title) {
390  cards.push_back(Card("OBJECT", title, "Image being displayed"));
391  }
392  /*
393  * Was there something else?
394  */
395  if (Wcs == NULL) {
396  addWcs("", cards); // works around a ds9 bug that WCSA/B is ignored if no Wcs is present
397  } else {
398  typedef std::vector<std::string> NameList;
399 
400  auto shift = lsst::geom::Extent2D(-data.getX0(), -data.getY0());
401  auto newWcs = Wcs->copyAtShiftedPixelOrigin(shift);
402 
403  std::shared_ptr<lsst::daf::base::PropertySet> metadata = newWcs->getFitsMetadata();
404 
405  NameList paramNames = metadata->paramNames();
406 
407  for (NameList::const_iterator i = paramNames.begin(), end = paramNames.end(); i != end; ++i) {
408  if (*i == "SIMPLE" || *i == "BITPIX" || *i == "NAXIS" || *i == "NAXIS1" || *i == "NAXIS2" ||
409  *i == "XTENSION" || *i == "PCOUNT" || *i == "GCOUNT") {
410  continue;
411  }
412  std::type_info const &type = metadata->typeOf(*i);
413  if (type == typeid(bool)) {
414  cards.push_back(Card(*i, metadata->get<bool>(*i)));
415  } else if (type == typeid(int)) {
416  cards.push_back(Card(*i, metadata->get<int>(*i)));
417  } else if (type == typeid(float)) {
418  cards.push_back(Card(*i, metadata->get<float>(*i)));
419  } else if (type == typeid(double)) {
420  cards.push_back(Card(*i, metadata->get<double>(*i)));
421  } else {
422  cards.push_back(Card(*i, metadata->get<std::string>(*i)));
423  }
424  }
425  }
426  /*
427  * Basic FITS stuff
428  */
429  const int naxis = 2; // == NAXIS
430  int naxes[naxis]; /* values of NAXIS1 etc */
431  naxes[0] = data.getWidth();
432  naxes[1] = data.getHeight();
433 
434  write_fits_hdr(fd, bitpix, naxis, naxes, cards, 1);
435  for (int y = 0; y != data.getHeight(); ++y) {
436  if (write_fits_data(fd, bitpix, (char *)(data.row_begin(y)), (char *)(data.row_end(y))) < 0) {
438  (boost::format("Error writing data for row %d") % y).str());
439  }
440  }
441 
442  pad_to_fits_record(fd, data.getWidth() * data.getHeight(), bitpix);
443 }
char * data
Definition: BaseRecord.cc:62
table::Key< int > type
Definition: Detector.cc:163
std::vector< std::string > paramNames(bool topLevelOnly=true) const
A variant of names that excludes the names of subproperties.
std::type_info const & typeOf(std::string const &name) const
Get the type of values for a property name (possibly hierarchical).
T get(std::string const &name) const
Get the last value for a property name (possibly hierarchical).
Reports errors that are due to events beyond the control of the program.
Definition: Runtime.h:104
Extent< double, 2 > Extent2D
Definition: Extent.h:400
T push_back(T... args)

◆ writeBasicFits() [2/4]

template<typename ImageT >
void lsst::afw::display::writeBasicFits ( int  fd,
ImageT const &  data,
lsst::afw::geom::SkyWcs const *  Wcs = NULL,
char const *  title = NULL 
)

◆ writeBasicFits() [3/4]

template<typename ImageT >
void lsst::afw::display::writeBasicFits ( std::string const &  filename,
ImageT const &  data,
geom::SkyWcs const *  Wcs,
char const *  title 
)

Definition at line 446 of file simpleFits.cc.

450  {
451  int fd;
452  if ((filename.c_str())[0] == '|') { // a command
453  const char *cmd = filename.c_str() + 1;
454  while (isspace(*cmd)) {
455  cmd++;
456  }
457 
458  fd = fileno(popen(cmd, "w"));
459  } else {
460  fd = creat(filename.c_str(), 777);
461  }
462 
463  if (fd < 0) {
465  (boost::format("Cannot open \"%s\"") % filename).str());
466  }
467 
468  try {
469  writeBasicFits(fd, data, Wcs, title);
471  (void)close(fd);
472  throw;
473  }
474 
475  (void)close(fd);
476 }
Provides consistent interface for LSST exceptions.
Definition: Exception.h:107
T isspace(T... args)
void writeBasicFits(std::string const &filename, ImageT const &data, geom::SkyWcs const *Wcs, char const *title)
Definition: simpleFits.cc:446

◆ writeBasicFits() [4/4]

template<typename ImageT >
void lsst::afw::display::writeBasicFits ( std::string const &  filename,
ImageT const &  data,
lsst::afw::geom::SkyWcs const *  Wcs = NULL,
const char *  title = NULL 
)