Skip to content

Commit 594625b

Browse files
authored
Merge pull request #147 from lsst-camera-dh/LSSTTD-1606_superbias_subtraction_w_rowcol
Lssttd 1606 superbias subtraction w rowcol
2 parents d0b0643 + 9c039b1 commit 594625b

4 files changed

Lines changed: 113 additions & 62 deletions

File tree

python/lsst/eotest/image_utils.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,11 @@ def unbias_and_trim(im, overscan, imaging=None, dxmin=5, dxmax=2, bias_method='r
500500
if bias_method == 'rowcol':
501501
serial_overscan = kwargs['serial_overscan']
502502
parallel_overscan = kwargs['parallel_overscan']
503-
im -= bias_image_rowcol(im, serial_overscan, parallel_overscan)
503+
parallel_bbox = lsst.geom.Box2I(
504+
lsst.geom.Point2I(0, parallel_overscan.getMin().y),
505+
parallel_overscan.getMax())
506+
im -= bias_image_rowcol(im, serial_overscan=serial_overscan,
507+
parallel_overscan=parallel_bbox)
504508
else:
505509
im -= bias_image(im, overscan, dxmin=dxmin, dxmax=dxmax,
506510
bias_method=bias_method, **kwargs)

python/lsst/eotest/sensor/MaskedCCD.py

Lines changed: 83 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,14 @@ def __init__(self, imfile, mask_files=(), bias_frame=None,
6060
self.setAllMasks()
6161
self.bias_frame = None
6262
self.ccd_pcas = None
63-
if bias_frame == 'rowcol':
63+
self.bias_method = None
64+
if isinstance(bias_frame, (tuple, list)) and bias_frame[0] == 'rowcol':
6465
# Use parallel+serial overscan model to do bias subtraction.
65-
self.bias_frame = 'rowcol'
66+
# The second element of bias_frame should be the superbias file
67+
# for this CCD.
68+
self.bias_method = 'rowcol'
69+
self.bias_frame = (MaskedCCD(bias_frame[1], all_amps=all_amps)
70+
if bias_frame[1] is not None else None)
6671
elif bias_frame is not None:
6772
if isinstance(bias_frame, MaskedCCD):
6873
self.bias_frame = bias_frame
@@ -169,35 +174,43 @@ def write_bias_subtracted_MEF(self, outfile, gains=None, overwrite=True):
169174

170175

171176
def bias_image_using_overscan(self, amp, overscan=None, **kwargs):
172-
"""
173-
Generate a bias image containing offset values calculated from
174-
bias(), bias_row(), bias_func() or bias_spline(). The default bias method
175-
is set to bias_row() in image_utils.py. Keyword arguments can be passed
176-
depending on which bias method is used.
177+
"""Generate a bias image containing offset values calculated from
178+
bias(), bias_row(), bias_func() or bias_spline(). The default
179+
bias method is set to bias_row() in image_utils.py. Keyword
180+
arguments can be passed depending on which bias method is
181+
used.
177182
178183
Keyword Arguments:
179-
fit_order: The order of the polynomial. This only needs to be specified when
180-
using the 'func' method. The default is: 1.
181-
k: The degree of the spline fit. This only needs to be specified when using
182-
the 'spline' method. The default is: 3.
183-
s: The amount of smoothing to be applied to the fit. This only needs to be
184-
specified when using the 'spline' method. The default is: 18000.
185-
t: The number of knots. If None, finds the number of knots to use for a given
186-
smoothing factor, s. This only needs to be specified when using the 'spline'
187-
method. The default is: None.
184+
fit_order: The order of the polynomial. This only needs to be
185+
specified when using the 'func' method. The default is: 1.
186+
k: The degree of the spline fit. This only needs to be specified
187+
when using the 'spline' method. The default is: 3.
188+
s: The amount of smoothing to be applied to the fit. This only needs
189+
to be specified when using the 'spline' method.
190+
The default is: 18000.
191+
t: The number of knots. If None, finds the number of knots to use
192+
for a given smoothing factor, s. This only needs to be specified
193+
when using the 'spline' method. The default is: None.
188194
"""
189195
if overscan is None:
190196
overscan = self.amp_geom.serial_overscan
191197
try:
192198
if 'bias_method' in kwargs:
193199
if kwargs['bias_method'] == 'rowcol':
194-
serial_overscan = self.amp_geom.serial_overscan
200+
serial_overscan = self.amp_geom.serial_overscan
195201
parallel_overscan = self.amp_geom.parallel_overscan
196-
parallel_bbox = lsst.geom.Box2I(lsst.geom.Point2I(0, \
197-
parallel_overscan.getMin().y), parallel_overscan.getMax())
198-
return imutils.bias_image_rowcol(self._deep_copy(amp), \
199-
serial_overscan=serial_overscan, parallel_overscan=parallel_bbox, **kwargs)
200-
return imutils.bias_image(self._deep_copy(amp), overscan=overscan, **kwargs)
202+
parallel_bbox = lsst.geom.Box2I(
203+
lsst.geom.Point2I(0, parallel_overscan.getMin().y),
204+
parallel_overscan.getMax())
205+
bias_image = imutils.bias_image_rowcol(
206+
self._deep_copy(amp),
207+
serial_overscan=serial_overscan,
208+
parallel_overscan=parallel_bbox, **kwargs)
209+
if self.bias_frame is not None:
210+
bias_image += self.bias_frame[amp].getImage()
211+
return bias_image
212+
return imutils.bias_image(self._deep_copy(amp), overscan=overscan,
213+
**kwargs)
201214
except pexExcept.RuntimeError as eobj:
202215
raise MaskedCCDBiasImageException("DM stack error generating bias "
203216
+ "image from overscan region:\n"
@@ -207,25 +220,33 @@ def _deep_copy(self, amp):
207220
return self[amp].Factory(self[amp], deep=True)
208221

209222
def bias_image(self, amp, overscan=None, **kwargs):
210-
"""
211-
Use separately stored metadata to determine file-specified
223+
"""Use separately stored metadata to determine file-specified
212224
overscan region. If bias_frame is not given, then calculate
213-
the bias image using bias(), bias_row(), bias_func() or bias_spline().
214-
The default bias method is set to bias_row() in image_utils.py.
215-
Keyword arguments can be passed depending on which bias method is used.
225+
the bias image using bias(), bias_row(), bias_func() or
226+
bias_spline(). The default bias method is set to bias_row()
227+
in image_utils.py. Keyword arguments can be passed depending
228+
on which bias method is used.
216229
217230
Keyword Arguments:
218-
fit_order: The order of the polynomial. This only needs to be specified when
219-
using the 'func' method. The default is: 1.
220-
k: The degree of the spline fit. This only needs to be specified when using
221-
the 'spline' method. The default is: 3.
222-
s: The amount of smoothing to be applied to the fit. This only needs to be
223-
specified when using the 'spline' method. The default is: 18000.
224-
t: The number of knots. If None, finds the number of knots to use for a given
225-
smoothing factor, s. This only needs to be specified when using the 'spline'
226-
method. The default is: None.
231+
232+
fit_order: The order of the polynomial. This only needs to be
233+
specified when using the 'func' method. The default is: 1.
234+
235+
k: The degree of the spline fit. This only needs to be
236+
specified when using the 'spline' method. The default is:
237+
3.
238+
239+
s: The amount of smoothing to be applied to the fit. This only
240+
needs to be specified when using the 'spline' method. The
241+
default is: 18000.
242+
243+
t: The number of knots. If None, finds the number of knots to
244+
use for a given smoothing factor, s. This only needs to be
245+
specified when using the 'spline' method. The default is:
246+
None.
247+
227248
"""
228-
if self.bias_frame != 'rowcol' and self.bias_frame is not None:
249+
if self.bias_method != 'rowcol' and self.bias_frame is not None:
229250
#
230251
# Use bias frame, if available, instead of overscan region
231252
#
@@ -237,27 +258,36 @@ def bias_image(self, amp, overscan=None, **kwargs):
237258
def bias_subtracted_image(self, amp, overscan=None,
238259
max_pca_reduced_chisq=None,
239260
**kwargs):
240-
"""
241-
Subtract a bias image to correct for the offset. A bias correction is also
242-
applied if a base_frame is passed. The bias image with the offset values is
243-
generated using either of the bias(), bias_row(), bias_func() or bias_spline()
244-
methods from image_utils.py. The default bias method is set to bias_row().
245-
Keyword arguments can be passed depending on which bias method is used.
261+
"""Subtract a bias image to correct for the offset. A bias
262+
correction is also applied if a base_frame is passed. The bias
263+
image with the offset values is generated using either of the
264+
bias(), bias_row(), bias_func() or bias_spline() methods from
265+
image_utils.py. The default bias method is set to bias_row().
266+
Keyword arguments can be passed depending on which bias method
267+
is used.
246268
247269
Keyword Arguments:
248-
fit_order: The order of the polynomial. This only needs to be specified when
249-
using the 'func' method. The default is: 1.
250-
k: The degree of the spline fit. This only needs to be specified when using
251-
the 'spline' method. The default is: 3.
252-
s: The amount of smoothing to be applied to the fit. This only needs to be
253-
specified when using the 'spline' method. The default is: 18000.
254-
t: The number of knots. If None, finds the number of knots to use for a given
255-
smoothing factor, s. This only needs to be specified when using the 'spline'
256-
method. The default is: None.
270+
271+
fit_order: The order of the polynomial. This only needs to be
272+
specified when using the 'func' method. The default is: 1.
273+
274+
k: The degree of the spline fit. This only needs to be
275+
specified when using the 'spline' method. The default is:
276+
3.
277+
278+
s: The amount of smoothing to be applied to the fit. This only
279+
needs to be specified when using the 'spline' method. The
280+
default is: 18000.
281+
282+
t: The number of knots. If None, finds the number of knots to
283+
use for a given smoothing factor, s. This only needs to be
284+
specified when using the 'spline' method. The default is:
285+
None.
286+
257287
"""
258288
# Make a local copy to process and return.
259289
my_image = self._deep_copy(amp)
260-
if self.bias_frame == 'rowcol':
290+
if self.bias_method == 'rowcol':
261291
# This overrides any bias_method options.
262292
my_image -= self.bias_image(amp, bias_method='rowcol')
263293
elif self.bias_frame is not None:

python/lsst/eotest/sensor/brightPixelsTask.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def run(self, sensor_id, dark_files, mask_files, gains, bias_frame=None,
5555
imutils.dm_hdu(amp))
5656
medfile = os.path.join(self.config.output_dir,
5757
'%s_median_dark_bp.fits' % sensor_id)
58-
if not isinstance(bias_frame, str):
58+
if not isinstance(bias_frame, str) and bias_frame[0] != 'rowcol':
5959
# Assume `bias_frame` is a tuple containing the
6060
# CCD_bias_PCA filenames so do a bias correction on the
6161
# median image using that model so that the FITS file

python/lsst/eotest/sensor/cteTask.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import lsst.afw.math as afwMath
1717
import lsst.pex.config as pexConfig
1818
import lsst.pipe.base as pipeBase
19+
import lsst.geom
1920

2021
def pca_bias_subtracted_image(image, bias_frame, amp):
2122
my_image = image.Factory(image, deep=True)
@@ -44,19 +45,31 @@ def superflat(files, bias_frame=None, outfile='superflat.fits', bitpix=None,
4445
and median-ing them together.
4546
"""
4647
use_pca_bias = os.environ.get('LCATR_USE_PCA_BIAS_FIT', 'True') == 'True'
47-
# Get overscan region.
48+
use_rowcol = False
49+
# Get overscan regions.
4850
amp_geom = makeAmplifierGeometry(files[0])
49-
overscan = amp_geom.serial_overscan
51+
serial_overscan = amp_geom.serial_overscan
52+
parallel_overscan = amp_geom.parallel_overscan
53+
parallel_overscan = lsst.geom.Box2I(
54+
lsst.geom.Point2I(0, parallel_overscan.getMin().y),
55+
parallel_overscan.getMax())
56+
superbias = None
5057
output_images = dict()
58+
if isinstance(bias_frame, (tuple, list)) and bias_frame[0] == 'rowcol':
59+
use_rowcol = True
60+
if bias_frame[1] is not None:
61+
superbias = fits.open(bias_frame[1])
5162
for amp in imutils.allAmps(files[0]):
5263
images = []
5364
for infile in files:
5465
image = afwImage.ImageF(infile, imutils.dm_hdu(amp))
5566
if bias_subtract:
56-
if bias_frame == 'rowcol':
67+
if use_rowcol:
5768
image -= imutils\
58-
.bias_image_rowcol(image, amp_geom.serial_overscan,
59-
amp_geom.parallel_overscan)
69+
.bias_image_rowcol(image, serial_overscan,
70+
parallel_overscan)
71+
if superbias is not None:
72+
image.array -= superbias[amp].data
6073
elif bias_frame:
6174
if use_pca_bias:
6275
image = pca_bias_subtracted_image(image, bias_frame,
@@ -65,15 +78,19 @@ def superflat(files, bias_frame=None, outfile='superflat.fits', bitpix=None,
6578
bias_image = afwImage.ImageF(bias_frame,
6679
imutils.dm_hdu(amp))
6780
image = bias_subtracted_image(image, bias_image,
68-
overscan, bias_method)
81+
serial_overscan,
82+
bias_method)
6983
else:
70-
image -= imutils.bias_image(im=image, overscan=overscan,
84+
image -= imutils.bias_image(im=image,
85+
overscan=serial_overscan,
7186
bias_method=bias_method)
7287
images.append(image)
7388
if lsst.afw.__version__.startswith('12.0'):
7489
images = afwImage.vectorImageF(images)
7590
output_images[amp] = afwMath.statisticsStack(images, afwMath.MEDIAN)
7691
imutils.writeFits(output_images, outfile, files[0])
92+
if superbias is not None:
93+
superbias.close()
7794
return outfile
7895

7996

0 commit comments

Comments
 (0)