1 from __future__
import division
2 from builtins
import object
29 from lsst.afw.display.displayLib
import replaceSaturatedPixels, getZScale
32 """!Return a naive total intensity from the red, blue, and green intensities
33 \param imageR intensity of image that'll be mapped to red; or intensity if imageG and imageB are None
34 \param imageG intensity of image that'll be mapped to green; or None
35 \param imageB intensity of image that'll be mapped to blue; or None
37 Inputs may be MaskedImages, Images, or numpy arrays and the return is of the same type
39 if imageG
is None or imageB
is None:
40 assert imageG
is None and imageB
is None, \
41 "Please specify either a single image or red, green, and blue images"
44 imageRGB = [imageR, imageG, imageB]
46 for i, c
in enumerate(imageRGB):
47 if hasattr(c,
"getImage"):
48 c = imageRGB[i] = c.getImage()
49 if hasattr(c,
"getArray"):
50 imageRGB[i] = c.getArray()
52 intensity = (imageRGB[0] + imageRGB[1] + imageRGB[2])/float(3)
56 Image = afwImage.ImageU
if intensity.dtype ==
'uint16' else afwImage.ImageF
58 if hasattr(imageR,
"getImage"):
60 elif hasattr(imageR,
"getArray"):
61 intensity = Image(intensity)
66 """!Baseclass to map red, blue, green intensities into uint8 values"""
70 \param minimum Intensity that should be mapped to black (a scalar or array for R, G, B)
71 \param image The image to be used to calculate the mapping.
73 If provided, also the default for makeRgbImage()
81 assert len(minimum) == 3,
"Please provide 1 or 3 values for minimum"
86 def makeRgbImage(self, imageR=None, imageG=None, imageB=None,
87 xSize=
None, ySize=
None, rescaleFactor=
None):
88 """!Convert 3 arrays, imageR, imageG, and imageB into a numpy RGB image
89 \param imageR Image to map to red (if None, use the image passed to the ctor)
90 \param imageG Image to map to green (if None, use imageR)
91 \param imageB Image to map to blue (if None, use imageR)
92 \param xSize Desired width of RGB image (or None). If ySize is None, preserve aspect ratio
93 \param ySize Desired height of RGB image (or None)
94 \param rescaleFactor Make size of output image rescaleFactor*size of the input image (or None)
96 N.b. images may be afwImage.Images or numpy arrays
100 raise RuntimeError(
"You must provide an image (or pass one to the constructor)")
108 imageRGB = [imageR, imageG, imageB]
109 for i, c
in enumerate(imageRGB):
110 if hasattr(c,
"getImage"):
111 c = imageRGB[i] = c.getImage()
112 if hasattr(c,
"getArray"):
113 imageRGB[i] = c.getArray()
115 if xSize
is not None or ySize
is not None:
116 assert rescaleFactor
is None,
"You may not specify a size and rescaleFactor"
117 h, w = imageRGB[0].shape
119 ySize = int(xSize*h/float(w) + 0.5)
121 xSize = int(ySize*w/float(h) + 0.5)
123 size = (ySize, xSize)
124 elif rescaleFactor
is not None:
125 size = float(rescaleFactor)
132 except ImportError
as e:
133 raise RuntimeError(
"Unable to rescale as scipy.misc is unavailable: %s" % e)
135 for i, im
in enumerate(imageRGB):
136 imageRGB[i] = scipy.misc.imresize(im, size, interp=
'bilinear', mode=
'F')
141 """!Return the total intensity from the red, blue, and green intensities
143 This is a naive computation, and may be overridden by subclasses
148 """Map an intensity into the range of a uint8, [0, 255] (but not converted to uint8)"""
149 with np.errstate(invalid=
'ignore', divide=
'ignore'):
153 """Use the mapping to convert images imageR, imageG, and imageB to a triplet of uint8 images"""
154 imageR = imageR - self.
minimum[0]
155 imageG = imageG - self.
minimum[1]
156 imageB = imageB - self.
minimum[2]
160 imageRGB = [imageR, imageG, imageB]
166 r0, g0, b0 = imageRGB
168 with np.errstate(invalid=
'ignore', divide=
'ignore'):
169 for i, c
in enumerate(imageRGB):
170 c = np.where(r0 > g0,
172 np.where(r0 >= pixmax, c*pixmax/r0, c),
173 np.where(b0 >= pixmax, c*pixmax/b0, c)),
175 np.where(g0 >= pixmax, c*pixmax/g0, c),
176 np.where(b0 >= pixmax, c*pixmax/b0, c))).astype(np.uint8)
177 c[c > pixmax] = pixmax
184 """!A linear map map of red, blue, green intensities into uint8 values"""
186 def __init__(self, minimum=None, maximum=None, image=None):
187 """!A linear stretch from [minimum, maximum]; if one or both are omitted use image minimum/maximum to set them
189 \param minimum Intensity that should be mapped to black (a scalar or array for R, G, B)
190 \param maximum Intensity that should be mapped to white (a scalar)
191 \param image Image to estimate minimum/maximum if not explicitly set
194 if minimum
is None or maximum
is None:
195 assert image
is not None,
"You must provide an image if you don't set both minimum and maximum"
199 minimum = stats.getValue(afwMath.MIN)
201 maximum = stats.getValue(afwMath.MAX)
203 Mapping.__init__(self, minimum, image)
209 assert maximum - minimum != 0,
"minimum and maximum values must not be equal"
210 self.
_range = float(maximum - minimum)
213 """Return an array which, when multiplied by an image, returns that image mapped to the range of a
214 uint8, [0, 255] (but not converted to uint8)
216 The intensity is assumed to have had minimum subtracted (as that can be done per-band)
218 with np.errstate(invalid=
'ignore', divide=
'ignore'):
219 return np.where(I <= 0, 0,
223 """!A mapping for a linear stretch chosen by the zscale algorithm
224 (preserving colours independent of brightness)
226 x = (I - minimum)/range
229 def __init__(self, image, nSamples=1000, contrast=0.25):
230 """!A linear stretch from [z1, z2] chosen by the zscale algorithm
231 \param image Image whose parameters are desired
232 \param nSamples The number of samples to use to estimate the zscale parameters
233 \param contrast The number of samples to use to estimate the zscale parameters
236 if not hasattr(image,
"getArray"):
237 image = afwImage.ImageF(image)
238 z1, z2 =
getZScale(image, nSamples, contrast)
240 LinearMapping.__init__(self, z1, z2, image)
243 """!A mapping for an asinh stretch (preserving colours independent of brightness)
245 x = asinh(Q (I - minimum)/range)/Q
247 This reduces to a linear stretch if Q == 0
249 See http://adsabs.harvard.edu/abs/2004PASP..116..133L
253 Mapping.__init__(self, minimum)
272 """Return an array which, when multiplied by an image, returns that image mapped to the range of a
273 uint8, [0, 255] (but not converted to uint8)
275 The intensity is assumed to have had minimum subtracted (as that can be done per-band)
277 with np.errstate(invalid=
'ignore', divide=
'ignore'):
278 return np.where(I <= 0, 0, np.arcsinh(I*self.
_soften)*self.
_slope/I)
281 """!A mapping for an asinh stretch, estimating the linear stretch by zscale
283 x = asinh(Q (I - z1)/(z2 - z1))/Q
290 Create an asinh mapping from an image, setting the linear part of the stretch using zscale
292 \param image The image to analyse, or a list of 3 images to be converted to an intensity image
293 \param Q The asinh softening parameter
294 \param pedestal The value, or array of 3 values, to subtract from the images; or None
296 N.b. pedestal, if not None, is removed from the images when calculating the zscale
297 stretch, and added back into Mapping.minimum[]
300 assert len(image)
in (1, 3,),
"Please provide 1 or 3 images"
304 if pedestal
is not None:
306 assert len(pedestal)
in (1, 3,),
"Please provide 1 or 3 pedestals"
308 pedestal = 3*[pedestal]
311 for i, im
in enumerate(image):
312 if pedestal[i] != 0.0:
313 if hasattr(im,
"getImage"):
315 if hasattr(im,
"getArray"):
318 image[i] = im - pedestal[i]
320 pedestal = len(image)*[0.0]
325 dataRange = zscale.maximum - zscale.minimum[0]
326 minimum = zscale.minimum
328 for i, level
in enumerate(pedestal):
331 AsinhMapping.__init__(self, minimum, dataRange, Q)
334 def makeRGB(imageR, imageG=None, imageB=None, minimum=0, dataRange=5, Q=8, fileName=None,
335 saturatedBorderWidth=0, saturatedPixelValue=
None,
336 xSize=
None, ySize=
None, rescaleFactor=
None):
337 """Make a set of three images into an RGB image using an asinh stretch and optionally write it to disk
339 If saturatedBorderWidth is non-zero, replace saturated pixels with saturatedPixelValue. Note
340 that replacing saturated pixels requires that the input images be MaskedImages.
347 if saturatedBorderWidth:
348 if saturatedPixelValue
is None:
349 raise ValueError(
"saturatedPixelValue must be set if saturatedBorderWidth is set")
353 rgb = asinhMap.makeRgbImage(imageR, imageG, imageB,
354 xSize=xSize, ySize=ySize, rescaleFactor=rescaleFactor)
362 """!Display an rgb image using matplotlib
363 \param rgb The RGB image in question
364 \param show If true, call plt.show()
366 import matplotlib.pyplot
as plt
367 plt.imshow(rgb, interpolation=
'nearest', origin=
"lower")
373 """!Write an RGB image to disk
374 \param fileName The output file. The suffix defines the format, and must be supported by matplotlib
375 \param rgbImage The image, as made by e.g. makeRGB
377 Most versions of matplotlib support png and pdf (although the eps/pdf/svg writers may be buggy,
378 possibly due an interaction with useTeX=True in the matplotlib settings).
380 If your matplotlib bundles pil/pillow you should also be able to write jpeg and tiff files.
382 import matplotlib.image
383 matplotlib.image.imsave(fileName, rgbImage)
390 """!\deprecated Object used to support legacy API"""
397 """!\deprecated Object used to support legacy API"""
398 def __init__(self, imageR, imageG, imageB, mapping):
399 """!\deprecated Legacy API"""
400 asinh =
AsinhMapping(mapping.minimum, mapping.dataRange, mapping.Q)
401 self.
rgb = asinh.makeRgbImage(imageR, imageG, imageB)
404 """!\deprecated Legacy API"""
408 """!\deprecated Legacy API"""
409 return _RgbImageF(imageR, imageG, imageB, mapping)
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 intensity
Return the total intensity from the red, blue, and green intensities.
MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > * makeMaskedImage(typename Image< ImagePixelT >::Ptr image, typename Mask< MaskPixelT >::Ptr mask=typename Mask< MaskPixelT >::Ptr(), typename Image< VariancePixelT >::Ptr variance=typename Image< VariancePixelT >::Ptr())
A function to return a MaskedImage of the correct type (cf.
def __init__
A linear stretch from [z1, z2] chosen by the zscale algorithm.
Baseclass to map red, blue, green intensities into uint8 values.
def __init__
Create an asinh mapping from an image, setting the linear part of the stretch using zscale...
A linear map map of red, blue, green intensities into uint8 values.
def makeRgbImage
Convert 3 arrays, imageR, imageG, and imageB into a numpy RGB image.
def _convertImagesToUint8
def displayRGB
Display an rgb image using matplotlib.
def __init__
Create a mapping.
A mapping for an asinh stretch, estimating the linear stretch by zscale.
A mapping for a linear stretch chosen by the zscale algorithm (preserving colours independent of brig...
def computeIntensity
Return a naive total intensity from the red, blue, and green intensities.
A mapping for an asinh stretch (preserving colours independent of brightness)
Statistics makeStatistics(afwImage::Mask< afwImage::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl)
Specialization to handle Masks.
def __init__
A linear stretch from [minimum, maximum]; if one or both are omitted use image minimum/maximum to set...
def writeRGB
Write an RGB image to disk.
template void replaceSaturatedPixels(image::MaskedImage< float > &rim, image::MaskedImage< float > &gim, image::MaskedImage< float > &bim, int borderWidth, float saturatedPixelValue)