27 from .rgb
import replaceSaturatedPixels, getZScale
31 """Return a naive total intensity from the red, blue, and green intensities 35 imageR : `lsst.afw.image.MaskedImage`, `lsst.afw.image.Image`, or `numpy.ndarray`, (Nx, Ny) 36 intensity of image that'll be mapped to red; or intensity if imageG and imageB are None 37 imageG : `lsst.afw.image.MaskedImage`, `lsst.afw.image.Image`, or `numpy.ndarray`, (Nx, Ny) 38 intensity of image that'll be mapped to green; or None 39 imageB : `lsst.afw.image.MaskedImage`, `lsst.afw.image.Image`, or `numpy.ndarray`, (Nx, Ny) 40 intensity of image that'll be mapped to blue; or None 44 image : type of ``imageR``, ``imageG``, and `imageB`` 46 if imageG
is None or imageB
is None:
47 assert imageG
is None and imageB
is None, \
48 "Please specify either a single image or red, green, and blue images" 51 imageRGB = [imageR, imageG, imageB]
53 for i, c
in enumerate(imageRGB):
54 if hasattr(c,
"getImage"):
55 c = imageRGB[i] = c.getImage()
56 if hasattr(c,
"getArray"):
57 imageRGB[i] = c.getArray()
59 intensity = (imageRGB[0] + imageRGB[1] + imageRGB[2])/
float(3)
63 Image = afwImage.ImageU
if intensity.dtype ==
'uint16' else afwImage.ImageF
65 if hasattr(imageR,
"getImage"):
67 elif hasattr(imageR,
"getArray"):
68 intensity = Image(intensity)
74 """Base class to map red, blue, green intensities into uint8 values 78 minimum : `float` or sequence of `float` 79 Intensity that should be mapped to black. If an array, has three 82 The image to be used to calculate the mapping. 83 If provided, also the default for makeRgbImage() 93 assert len(minimum) == 3,
"Please provide 1 or 3 values for minimum" 98 def makeRgbImage(self, imageR=None, imageG=None, imageB=None,
99 xSize=None, ySize=None, rescaleFactor=None):
100 """Convert 3 arrays, imageR, imageG, and imageB into a numpy RGB image 102 imageR : `lsst.afw.image.Image` or `numpy.ndarray`, (Nx, Ny) 103 Image to map to red (if `None`, use the image passed to the ctor) 104 imageG : `lsst.afw.image.Image` or `numpy.ndarray`, (Nx, Ny), optional 105 Image to map to green (if `None`, use imageR) 106 imageB : `lsst.afw.image.Image` or `numpy.ndarray`, (Nx, Ny), optional 107 Image to map to blue (if `None`, use imageR) 108 xSize : `int`, optional 109 Desired width of RGB image. If ``ySize`` is `None`, preserve aspect ratio 110 ySize : `int`, optional 111 Desired height of RGB image 112 rescaleFactor : `float`, optional 113 Make size of output image ``rescaleFactor*size`` of the input image 118 "You must provide an image (or pass one to the constructor)")
126 imageRGB = [imageR, imageG, imageB]
127 for i, c
in enumerate(imageRGB):
128 if hasattr(c,
"getImage"):
129 c = imageRGB[i] = c.getImage()
130 if hasattr(c,
"getArray"):
131 imageRGB[i] = c.getArray()
133 if xSize
is not None or ySize
is not None:
134 assert rescaleFactor
is None,
"You may not specify a size and rescaleFactor" 135 h, w = imageRGB[0].shape
141 size = (ySize, xSize)
142 elif rescaleFactor
is not None:
143 size =
float(rescaleFactor)
150 except ImportError
as e:
152 "Unable to rescale as scipy.misc is unavailable: %s" % e)
154 for i, im
in enumerate(imageRGB):
155 imageRGB[i] = scipy.misc.imresize(
156 im, size, interp=
'bilinear', mode=
'F')
161 """Return the total intensity from the red, blue, and green intensities 165 This is a naive computation, and may be overridden by subclasses 170 """Map an intensity into the range of a uint8, [0, 255] (but not converted to uint8) 172 with np.errstate(invalid=
'ignore', divide=
'ignore'):
173 return np.where(intensity <= 0, 0,
176 def _convertImagesToUint8(self, imageR, imageG, imageB):
177 """Use the mapping to convert images imageR, imageG, and imageB to a triplet of uint8 images 179 imageR = imageR - self.
minimum[0]
180 imageG = imageG - self.
minimum[1]
181 imageB = imageB - self.
minimum[2]
185 imageRGB = [imageR, imageG, imageB]
186 with np.errstate(invalid=
"ignore"):
194 r0, g0, b0 = imageRGB
197 with np.errstate(invalid=
'ignore', divide=
'ignore'):
198 for i, c
in enumerate(imageRGB):
199 c = np.where(r0 > g0,
201 np.where(r0 >= pixmax, c*pixmax/r0, c),
202 np.where(b0 >= pixmax, c*pixmax/b0, c)),
204 np.where(g0 >= pixmax, c*pixmax/g0, c),
205 np.where(b0 >= pixmax, c*pixmax/b0, c))).astype(np.uint8)
206 c[c > pixmax] = pixmax
214 """A linear map of red, blue, green intensities into uint8 values 218 minimum : `float` or sequence of `float` 219 Intensity that should be mapped to black. If an array, has three 220 elements for R, G, B. 222 Intensity that should be mapped to white 224 Image to estimate minimum/maximum if not explicitly set 227 def __init__(self, minimum=None, maximum=None, image=None):
228 if minimum
is None or maximum
is None:
229 assert image
is not None,
"You must provide an image if you don't set both minimum and maximum" 233 minimum = stats.getValue(afwMath.MIN)
235 maximum = stats.getValue(afwMath.MAX)
237 Mapping.__init__(self, minimum, image)
243 assert maximum - minimum != 0,
"minimum and maximum values must not be equal" 247 """Return an array which, when multiplied by an image, returns that 248 image mapped to the range of a uint8, [0, 255] (but not converted to uint8) 250 The intensity is assumed to have had ``minimum`` subtracted (as that 251 can be done per-band) 253 with np.errstate(invalid=
'ignore', divide=
'ignore'):
254 return np.where(intensity <= 0, 0,
255 np.where(intensity >= self.
_range,
260 """A mapping for a linear stretch chosen by the zscale algorithm 261 (preserving colours independent of brightness) 263 x = (I - minimum)/range 268 Image whose parameters are desired 270 The number of samples to use to estimate the zscale parameters 274 def __init__(self, image, nSamples=1000, contrast=0.25):
275 if not hasattr(image,
"getArray"):
276 image = afwImage.ImageF(image)
277 z1, z2 =
getZScale(image, nSamples, contrast)
279 LinearMapping.__init__(self, z1, z2, image)
283 """A mapping for an asinh stretch (preserving colours independent of brightness) 285 x = asinh(Q (I - minimum)/range)/Q 289 This reduces to a linear stretch if Q == 0 291 See http://adsabs.harvard.edu/abs/2004PASP..116..133L 295 Mapping.__init__(self, minimum)
315 """Return an array which, when multiplied by an image, returns that image mapped to the range of a 316 uint8, [0, 255] (but not converted to uint8) 318 The intensity is assumed to have had minimum subtracted (as that can be done per-band) 320 with np.errstate(invalid=
'ignore', divide=
'ignore'):
321 return np.where(intensity <= 0, 0, np.arcsinh(intensity*self.
_soften)*self.
_slope/intensity)
325 """A mapping for an asinh stretch, estimating the linear stretch by zscale 327 x = asinh(Q (I - z1)/(z2 - z1))/Q 332 The image to analyse, or a list of 3 images to be converted to an intensity image 334 The asinh softening parameter 335 pedestal : `float` or sequence of `float`, optional 336 The value, or array of 3 values, to subtract from the images 338 N.b. pedestal, if not None, is removed from the images when calculating the zscale 339 stretch, and added back into Mapping.minimum[] 348 assert len(image)
in (1, 3,),
"Please provide 1 or 3 images" 352 if pedestal
is not None:
354 assert len(pedestal)
in (
355 1, 3,),
"Please provide 1 or 3 pedestals" 357 pedestal = 3*[pedestal]
360 for i, im
in enumerate(image):
361 if pedestal[i] != 0.0:
362 if hasattr(im,
"getImage"):
364 if hasattr(im,
"getArray"):
367 image[i] = im - pedestal[i]
369 pedestal = len(image)*[0.0]
375 dataRange = zscale.maximum - zscale.minimum[0]
376 minimum = zscale.minimum
378 for i, level
in enumerate(pedestal):
381 AsinhMapping.__init__(self, minimum, dataRange, Q)
385 def makeRGB(imageR, imageG=None, imageB=None, minimum=0, dataRange=5, Q=8, fileName=None,
386 saturatedBorderWidth=0, saturatedPixelValue=None,
387 xSize=None, ySize=None, rescaleFactor=None):
388 """Make a set of three images into an RGB image using an asinh stretch and 389 optionally write it to disk 396 minimum : `float` or sequence of `float` 400 The output file. The suffix defines the format, and must be supported by matplotlib 402 If saturatedBorderWidth is non-zero, replace saturated pixels with 403 ``saturatedPixelValue``. Note that replacing saturated pixels requires 404 that the input images be `lsst.afw.image.MaskedImage`. 415 if saturatedBorderWidth:
416 if saturatedPixelValue
is None:
418 "saturatedPixelValue must be set if saturatedBorderWidth is set")
420 saturatedBorderWidth, saturatedPixelValue)
423 rgb = asinhMap.makeRgbImage(imageR, imageG, imageB,
424 xSize=xSize, ySize=ySize, rescaleFactor=rescaleFactor)
433 """Display an rgb image using matplotlib 438 The RGB image in question 440 If `True`, call `matplotlib.pyplot.show()` 442 import matplotlib.pyplot
as plt
443 plt.imshow(rgb, interpolation=
'nearest', origin=
"lower")
450 """Write an RGB image to disk 455 The output file. The suffix defines the format, and must be supported by matplotlib 457 Most versions of matplotlib support png and pdf (although the eps/pdf/svg writers may be buggy, 458 possibly due an interaction with useTeX=True in the matplotlib settings). 460 If your matplotlib bundles pil/pillow you should also be able to write jpeg and tiff files. 462 The image, as made by e.g. makeRGB 464 import matplotlib.image
465 matplotlib.image.imsave(fileName, rgbImage)
473 """Deprecated object used to support legacy API 477 self.minimum = minimum
478 self.dataRange = dataRange
483 """Deprecated object used to support legacy API 486 def __init__(self, imageR, imageG, imageB, mapping):
487 asinh =
AsinhMapping(mapping.minimum, mapping.dataRange, mapping.Q)
488 self.
rgb = asinh.makeRgbImage(imageR, imageG, imageB)
495 """Deprecated legacy API 497 return _RgbImageF(imageR, imageG, imageB, mapping)
Angle abs(Angle const &a)
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.
def __init__(self, imageR, imageG, imageB, mapping)
def mapIntensityToUint8(self, intensity)
def displayRGB(rgb, show=True)
def makeRGB(imageR, imageG=None, imageB=None, minimum=0, dataRange=5, Q=8, fileName=None, saturatedBorderWidth=0, saturatedPixelValue=None, xSize=None, ySize=None, rescaleFactor=None)
def __init__(self, minimum=None, image=None)
def makeRgbImage(self, imageR=None, imageG=None, imageB=None, xSize=None, ySize=None, rescaleFactor=None)
def RgbImageF(imageR, imageG, imageB, mapping)
def _convertImagesToUint8(self, imageR, imageG, imageB)
void replaceSaturatedPixels(ImageT &rim, ImageT &gim, ImageT &bim, int borderWidth=2, float saturatedPixelValue=65535)
MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > * makeMaskedImage(typename std::shared_ptr< Image< ImagePixelT >> image, typename std::shared_ptr< Mask< MaskPixelT >> mask=Mask< MaskPixelT >(), typename std::shared_ptr< Image< VariancePixelT >> variance=Image< VariancePixelT >())
A function to return a MaskedImage of the correct type (cf.
Statistics makeStatistics(lsst::afw::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
The makeStatistics() overload to handle lsst::afw::math::MaskedVector<>
def mapIntensityToUint8(self, intensity)
def writeRGB(fileName, rgbImage)
def __init__(self, minimum, dataRange, Q=8)
def __init__(self, minimum, dataRange, Q)
def mapIntensityToUint8(self, intensity)
def write(self, fileName)
def intensity(self, imageR, imageG, imageB)
def __init__(self, image, Q=8, pedestal=None)
def __init__(self, image, nSamples=1000, contrast=0.25)
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...
def computeIntensity(imageR, imageG=None, imageB=None)
daf::base::PropertyList * list
def __init__(self, minimum=None, maximum=None, image=None)