|
lsst.pipe.tasks g1c91cc4c4e+1a7263aaf8
|
Classes | |
| class | fixes |
| class | PrettyPictureBackgroundFixerConnections |
| class | PrettyPictureConnections |
Functions | |
| Struct | run (self, Mapping[str, Exposure] images) |
| None | runQuantum (self, QuantumContext butlerQC, InputQuantizedConnection inputRefs, OutputQuantizedConnection outputRefs) |
| dict[str, Exposure] | makeInputsFromRefs (self, Iterable[DatasetRef] refs, Butler|QuantumContext butler) |
| dict[int, DeferredDatasetHandle] | makeInputsFromArrays (self, **kwargs) |
| dict[int, DeferredDatasetHandle] | makeInputsFromExposures (self, **kwargs) |
Variables | |
| doWrite | |
| r | |
| g | |
| b | |
| array : `numpy.array` | |
| mean : `float` | |
| sigma : `float` | |
| tuple | lower_pos = (array - mu) < sigma |
| sigma_ratio = min_sig / sigma | |
| R : `int` | |
| C : `int` | |
| slices : `list` of `tuple` | |
| image : `NDArray` | |
| inputCoadd : `Exposure` | |
| result : `Struct` | |
| results : `Struct` of `Mapping` of `str` to `ExposureF` | |
| dict[int, DeferredDatasetHandle] lsst.pipe.tasks.prettyPictureMaker._task.makeInputsFromArrays | ( | self, | |
| ** | kwargs ) |
Make valid inputs for the run method from numpy arrays.
Parameters
----------
kwargs : `NDArray`
This is standard python kwargs where the left side of the equals
is the data band, and the right side is the corresponding `NDArray`
array.
Returns
-------
sortedImages : `dict` of `str` to `Exposure`
A dictionary of `Exposure`\ s that keyed by the band they
correspond to.
| dict[int, DeferredDatasetHandle] lsst.pipe.tasks.prettyPictureMaker._task.makeInputsFromExposures | ( | self, | |
| ** | kwargs ) |
Make valid inputs for the run method from `Exposure` objects.
Parameters
----------
kwargs : `Exposure`
This is standard python kwargs where the left side of the equals
is the data band, and the right side is the corresponding
`Exposure`.
Returns
-------
sortedImages : `dict` of `str` to `Exposure`
A dictionary of `Exposure`\ s that keyed by the band they
correspond to.
| dict[str, Exposure] lsst.pipe.tasks.prettyPictureMaker._task.makeInputsFromRefs | ( | self, | |
| Iterable[DatasetRef] | refs, | ||
| Butler | QuantumContext | butler ) |
Make valid inputs for the run method from butler references.
Parameters
----------
refs : `Iterable` of `DatasetRef`
Some `Iterable` container of `Butler` `DatasetRef`\ s
butler : `Butler` or `QuantumContext`
This is the object that fetches the input data.
Returns
-------
sortedImages : `dict` of `str` to `Exposure`
A dictionary of `Exposure`\ s that keyed by the band they
correspond to.
| Struct lsst.pipe.tasks.prettyPictureMaker._task.run | ( | self, | |
| Mapping[str, Exposure] | images ) |
Turns the input arguments in arguments into an RGB array.
Parameters
----------
images : `Mapping` of `str` to `Exposure`
A mapping of input images and the band they correspond to.
Returns
-------
result : `Struct`
A struct with the corresponding RGB image, and mask used in
RGB image construction. The struct will have the attributes
outputRGBImage and outputRGBMask. Each of the outputs will
be a `NDarray` object.
Notes
-----
Construction of input images are made easier by use of the
makeInputsFrom* methods.
| None lsst.pipe.tasks.prettyPictureMaker._task.runQuantum | ( | self, | |
| QuantumContext | butlerQC, | ||
| InputQuantizedConnection | inputRefs, | ||
| OutputQuantizedConnection | outputRefs ) |
| lsst.pipe.tasks.prettyPictureMaker._task.array : `numpy.array` |
r = Field[float](doc="The amount of red contained in this channel") g = Field[float](doc="The amount of green contained in this channel") b = Field[float](doc="The amount of blue contained in this channel") class LumConfig(Config):
stretch = Field[float](doc="The stretch of the luminance in asinh", default=400)
max = Field[float](doc="The maximum allowed luminance on a 0 to 100 scale", default=85)
floor = Field[float](doc="A scaling factor to apply to the luminance before asinh scaling", default=0.0)
Q = Field[float](doc="softening parameter", default=0.7)
highlight = Field[float](
doc="The value of highlights in scaling factor applied to post asinh streaching", default=1.0
)
shadow = Field[float](
doc="The value of shadows in scaling factor applied to post asinh streaching", default=0.0
)
midtone = Field[float](
doc="The value of midtone in scaling factor applied to post asinh streaching", default=0.5
)
class LocalContrastConfig(Config):
doLocalContrast = Field[bool](
doc="Apply local contrast enhancements to the luminance channel", default=True
)
highlights = Field[float](doc="Adjustment factor for the highlights", default=-0.9)
shadows = Field[float](doc="Adjustment factor for the shadows", default=0.5)
clarity = Field[float](doc="Amount of clarity to apply to contrast modification", default=0.1)
sigma = Field[float](
doc="The scale size of what is considered local in the contrast enhancement", default=30
)
maxLevel = Field[int](
doc="The maximum number of scales the contrast should be enhanced over, if None then all",
default=4,
optional=True,
)
class ScaleColorConfig(Config):
saturation = Field[float](
doc=(
"The overall saturation factor with the scaled luminance between zero and one. "
"A value of one is not recommended as it makes bright pixels very saturated"
),
default=0.5,
)
maxChroma = Field[float](
doc=(
"The maximum chromaticity in the CIELCh color space, large "
"values will cause bright pixels to fall outside the RGB gamut."
),
default=50.0,
)
class RemapBoundsConfig(Config):
quant = Field[float](
doc=(
"The maximum values of each of the three channels will be multiplied by this factor to "
"determine the maximum flux of the image, values larger than this quantity will be clipped."
),
default=0.8,
)
absMax = Field[float](
doc="Instead of determining the maximum value from the image, use this fixed value instead",
default=220,
optional=True,
)
class PrettyPictureConfig(PipelineTaskConfig, pipelineConnections=PrettyPictureConnections):
channelConfig = ConfigDictField(
doc="A dictionary that maps band names to their rgb channel configurations",
keytype=str,
itemtype=ChannelRGBConfig,
default={},
)
imageRemappingConfig = ConfigField[RemapBoundsConfig](
doc="Configuration controlling channel normalization process"
)
luminanceConfig = ConfigField[LumConfig](
doc="Configuration for the luminance scaling when making an RGB image"
)
localContrastConfig = ConfigField[LocalContrastConfig](
doc="Configuration controlling the local contrast correction in RGB image production"
)
colorConfig = ConfigField[ScaleColorConfig](
doc="Configuration to control the color scaling process in RGB image production"
)
cieWhitePoint = ListField[float](
doc="The white point of the input arrays in ciexz coordinates", maxLength=2, default=[0.28, 0.28]
)
arrayType = ChoiceField[str](
doc="The dataset type for the output image array",
default="uint8",
allowed={
"uint8": "Use 8 bit arrays, 255 max",
"uint16": "Use 16 bit arrays, 65535 max",
"half": "Use 16 bit float arrays, 1 max",
"float": "Use 32 bit float arrays, 1 max",
},
)
doPSFDeconcovlve = Field[bool](
doc="Use the PSF in a richardson lucy deconvolution on the luminance channel.", default=True
)
exposureBrackets = ListField[float](
doc=(
"Exposure scaling factors used in creating multiple exposures with different scalings which will "
"then be fused into a final image"
),
optional=True,
default=[1.25, 1, 0.75],
)
doRemapGamut = Field[bool](
doc="Apply a color correction to unrepresentable colors, if false they will clip", default=True
)
gamutMethod = ChoiceField[str](
doc="If doRemapGamut is True this determines the method",
default="inpaint",
allowed={
"mapping": "Use a mapping function",
"inpaint": "Use surrounding pixels to determine likely value",
},
)
recenterNoise = Field[float](
doc="Recenter the noise away from zero. Supplied value is in units of sigma",
optional=True,
default=None,
)
noiseSearchThreshold = Field[float](
doc=(
"Flux threshold below which most flux will be considered noise, used to estimate noise properties"
),
default=10,
)
def setDefaults(self):
self.channelConfig["i"] = ChannelRGBConfig(r=1, g=0, b=0)
self.channelConfig["r"] = ChannelRGBConfig(r=0, g=1, b=0)
self.channelConfig["g"] = ChannelRGBConfig(r=0, g=0, b=1)
return super().setDefaults()
class PrettyPictureTask(PipelineTask):
_DefaultName = "prettyPictureTask" ConfigClass = PrettyPictureConfig config: ConfigClass def _find_normal_stats(self, array):
| lsst.pipe.tasks.prettyPictureMaker._task.image : `NDArray` |
M = arr.shape[0]
N = arr.shape[1]
# Function to compute slices for a given dimension size and number of divisions
def get_slices(total_size, num_divisions):
base = total_size // num_divisions
remainder = total_size % num_divisions
slices = []
start = 0
for i in range(num_divisions):
end = start + base
if i < remainder:
end += 1
slices.append((start, end))
start = end
return slices
# Get row and column slices
row_slices = get_slices(M, R)
col_slices = get_slices(N, C)
# Generate all possible tile combinations of row and column slices
tiles = []
for rs in row_slices:
r_start, r_end = rs
for cs in col_slices:
c_start, c_end = cs
tile_slice = (slice(r_start, r_end), slice(c_start, c_end))
tiles.append(tile_slice)
return tiles
def fixBackground(self, image):
| lsst.pipe.tasks.prettyPictureMaker._task.inputCoadd : `Exposure` |
# Find the median value in the image, which is likely to be
# close to average background. Note this doesn't work well
# in fields with high density or diffuse flux.
maxLikely = np.median(image, axis=None)
# find all the pixels that are fainter than this
# and find the std. This is just used as an initialization
# parameter and doesn't need to be accurate.
mask = image < maxLikely
initial_std = (image[mask] - maxLikely).std()
# Don't do anything if there are no pixels to check
if np.any(mask):
# use a minimizer to determine best mu and sigma for a Gaussian
# given only samples below the mean of the Gaussian.
_, sigma_hat = halfnorm.fit(np.abs(image[mask] - maxLikely))
mu_hat = maxLikely
else:
mu_hat, sigma_hat = (maxLikely, 2 * initial_std)
# create a new masking threshold that is the determined
# mean plus std from the fit
threshhold = mu_hat + sigma_hat
image_mask = image < threshhold
# create python slices that tile the image.
tiles = self._tile_slices(image, 25, 25)
yloc = []
xloc = []
values = []
# for each box find the middle position and the median background
# value in the window.
for xslice, yslice in tiles:
ypos = (yslice.stop - yslice.start) / 2 + yslice.start
xpos = (xslice.stop - xslice.start) / 2 + xslice.start
yloc.append(ypos)
xloc.append(xpos)
window = image[yslice, xslice][image_mask[yslice, xslice]]
if window.size > 0:
value = np.median(window)
else:
value = 0
values.append(value)
positions = np.meshgrid(np.arange(image.shape[0]), np.arange(image.shape[1]))
# create an interpolant for the background and interpolate over the image.
inter = RBFInterpolator(
np.vstack((yloc, xloc)).T, values, kernel="thin_plate_spline", degree=4, smoothing=0.05
)
backgrounds = inter(np.array(positions)[::-1].reshape(2, -1).T).reshape(image.shape)
return backgrounds
def run(self, inputCoadd: Exposure):
# Extract negative values efficiently
values_noise = array[array < self.config.noiseSearchThreshold]
# find the mode
center = mode(np.round(values_noise, 2)).mode
# extract the negative values
values_neg = array[array < center]
# Return infinity if no negative values found
if values_neg.size == 0:
return 0, np.inf
try:
# Fit half-normal distribution to absolute negative values
mu, sigma = halfnorm.fit(np.abs(values_neg))
except (ValueError, RuntimeError):
# Handle fitting failures (e.g., constant data, optimization issues)
return 0, np.inf
return center, sigma
def _match_sigmas_and_recenter(self, *arrays, factor=1):
| lsst.pipe.tasks.prettyPictureMaker._task.R : `int` |
| lsst.pipe.tasks.prettyPictureMaker._task.results : `Struct` of `Mapping` of `str` to `ExposureF` |
| lsst.pipe.tasks.prettyPictureMaker._task.sigma_ratio = min_sig / sigma |