drizzle 1.15.3__cp311-cp311-win32.whl → 2.0.0__cp311-cp311-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of drizzle might be problematic. Click here for more details.

drizzle/drizzle.py DELETED
@@ -1,569 +0,0 @@
1
- """
2
- The `drizzle` module defines the `Drizzle` class, for combining input
3
- images into a single output image using the drizzle algorithm.
4
- """
5
- import os
6
- import os.path
7
-
8
- import numpy as np
9
- from astropy import wcs
10
- from astropy.io import fits
11
-
12
- from . import util
13
- from . import doblot
14
- from . import dodrizzle
15
-
16
-
17
- class Drizzle(object):
18
- """
19
- Combine images using the drizzle algorithm
20
- """
21
- def __init__(self, infile="", outwcs=None,
22
- wt_scl="exptime", pixfrac=1.0, kernel="square",
23
- fillval="INDEF"):
24
- """
25
- Create a new Drizzle output object and set the drizzle parameters.
26
-
27
- All parameters are optional, but either infile or outwcs must be supplied.
28
- If infile initializes the object from a file written after a
29
- previous run of drizzle. Results from the previous run will be combined
30
- with new results. The value passed in outwcs will be ignored. If infile is
31
- not set, outwcs will be used to initilize a new run of drizzle.
32
-
33
- Parameters
34
- ----------
35
-
36
- infile : str, optional
37
- A fits file containing results from a previous run. The three
38
- extensions SCI, WHT, and CTX contain the combined image, total counts
39
- and image id bitmap, repectively. The WCS of the combined image is
40
- also read from the SCI extension.
41
-
42
- outwcs : wcs, optional
43
- The world coordinate system (WCS) of the combined image. This
44
- parameter must be present if no input file is given and is ignored if
45
- one is.
46
-
47
- wt_scl : str, optional
48
- How each input image should be scaled. The choices are `exptime`
49
- which scales each image by its exposure time, `expsq` which scales
50
- each image by the exposure time squared, or an empty string, which
51
- allows each input image to be scaled individually.
52
-
53
- pixfrac : float, optional
54
- The fraction of a pixel that the pixel flux is confined to. The
55
- default value of 1 has the pixel flux evenly spread across the image.
56
- A value of 0.5 confines it to half a pixel in the linear dimension,
57
- so the flux is confined to a quarter of the pixel area when the square
58
- kernel is used.
59
-
60
- kernel : str, optional
61
- The name of the kernel used to combine the inputs. The choice of
62
- kernel controls the distribution of flux over the kernel. The kernel
63
- names are: "square", "turbo", "point", "gaussian", "lanczos2",
64
- and "lanczos3".
65
-
66
- .. warning::
67
- The "gaussian" and "lanczos2/3" kernels **DO NOT** conserve flux.
68
-
69
- fillval : str, otional
70
- The value a pixel is set to in the output if the input image does
71
- not overlap it. The default value of INDEF does not set a value.
72
- """
73
-
74
- # Initialize the object fields
75
-
76
- self.outsci = None
77
- self.outwht = None
78
- self.outcon = None
79
-
80
- self.outexptime = 0.0
81
- self.uniqid = 0
82
-
83
- self.outwcs = outwcs
84
- self.wt_scl = wt_scl
85
- self.kernel = kernel
86
- self.fillval = fillval
87
- self.pixfrac = float(pixfrac)
88
-
89
- self.sciext = "SCI"
90
- self.whtext = "WHT"
91
- self.ctxext = "CTX"
92
-
93
- out_units = "cps"
94
-
95
- if not util.is_blank(infile):
96
- if os.path.exists(infile):
97
- handle = fits.open(infile)
98
-
99
- # Read parameters from image header
100
- self.outexptime = util.get_keyword(handle, "DRIZEXPT", default=0.0)
101
- self.uniqid = util.get_keyword(handle, "NDRIZIM", default=0)
102
-
103
- self.sciext = util.get_keyword(handle, "DRIZOUDA", default="SCI")
104
- self.whtext = util.get_keyword(handle, "DRIZOUWE", default="WHT")
105
- self.ctxext = util.get_keyword(handle, "DRIZOUCO", default="CTX")
106
-
107
- self.wt_scl = util.get_keyword(handle, "DRIZWTSC", default=wt_scl)
108
- self.kernel = util.get_keyword(handle, "DRIZKERN", default=kernel)
109
- self.fillval = util.get_keyword(handle, "DRIZFVAL", default=fillval)
110
- self.pixfrac = float(util.get_keyword(handle,
111
- "DRIZPIXF", default=pixfrac))
112
-
113
- out_units = util.get_keyword(handle, "DRIZOUUN", default="cps")
114
-
115
- try:
116
- hdu = handle[self.sciext]
117
- self.outsci = hdu.data.copy().astype(np.float32)
118
- self.outwcs = wcs.WCS(hdu.header, fobj=handle)
119
- except KeyError:
120
- pass
121
-
122
- try:
123
- hdu = handle[self.whtext]
124
- self.outwht = hdu.data.copy().astype(np.float32)
125
- except KeyError:
126
- pass
127
-
128
- try:
129
- hdu = handle[self.ctxext]
130
- self.outcon = hdu.data.copy().astype(np.int32)
131
- if self.outcon.ndim == 2:
132
- self.outcon = np.reshape(self.outcon, (1,
133
- self.outcon.shape[0],
134
- self.outcon.shape[1]))
135
-
136
- elif self.outcon.ndim == 3:
137
- pass
138
-
139
- else:
140
- msg = ("Drizzle context image has wrong dimensions: " +
141
- infile)
142
- raise ValueError(msg)
143
-
144
- except KeyError:
145
- pass
146
-
147
- handle.close()
148
-
149
- # Check field values
150
-
151
- if self.outwcs:
152
- util.set_pscale(self.outwcs)
153
- else:
154
- raise ValueError("Either an existing file or wcs must be supplied to Drizzle")
155
-
156
- if util.is_blank(self.wt_scl):
157
- self.wt_scl = ''
158
- elif self.wt_scl != "exptime" and self.wt_scl != "expsq":
159
- raise ValueError("Illegal value for wt_scl: %s" % out_units)
160
-
161
- if out_units == "counts":
162
- np.divide(self.outsci, self.outexptime, self.outsci)
163
- elif out_units != "cps":
164
- raise ValueError("Illegal value for wt_scl: %s" % out_units)
165
-
166
- # Initialize images if not read from a file
167
- outwcs_naxis1, outwcs_naxis2 = self.outwcs.pixel_shape
168
- if self.outsci is None:
169
- self.outsci = np.zeros(self.outwcs.pixel_shape[::-1],
170
- dtype=np.float32)
171
-
172
- if self.outwht is None:
173
- self.outwht = np.zeros(self.outwcs.pixel_shape[::-1],
174
- dtype=np.float32)
175
- if self.outcon is None:
176
- self.outcon = np.zeros((1, outwcs_naxis2, outwcs_naxis1),
177
- dtype=np.int32)
178
-
179
- def add_fits_file(self, infile, inweight="",
180
- xmin=0, xmax=0, ymin=0, ymax=0,
181
- unitkey="", expkey="", wt_scl=1.0):
182
- """
183
- Combine a fits file with the output drizzled image.
184
-
185
- Parameters
186
- ----------
187
-
188
- infile : str
189
- The name of the fits file, possibly including an extension.
190
-
191
- inweight : str, otional
192
- The name of a file containing a pixel by pixel weighting
193
- of the input data. If it is not set, an array will be generated
194
- where all values are set to one.
195
-
196
- xmin : float, otional
197
- This and the following three parameters set a bounding rectangle
198
- on the output image. Only pixels on the output image inside this
199
- rectangle will have their flux updated. Xmin sets the minimum value
200
- of the x dimension. The x dimension is the dimension that varies
201
- quickest on the image. If the value is zero or less, no minimum will
202
- be set in the x dimension. All four parameters are zero based,
203
- counting starts at zero.
204
-
205
- xmax : float, otional
206
- Sets the maximum value of the x dimension on the bounding box
207
- of the ouput image. If the value is zero or less, no maximum will
208
- be set in the x dimension.
209
-
210
- ymin : float, optional
211
- Sets the minimum value in the y dimension on the bounding box. The
212
- y dimension varies less rapidly than the x and represents the line
213
- index on the output image. If the value is zero or less, no minimum
214
- will be set in the y dimension.
215
-
216
- ymax : float, optional
217
- Sets the maximum value in the y dimension. If the value is zero or
218
- less, no maximum will be set in the y dimension.
219
-
220
- unitkey : string, optional
221
- The name of the header keyword containing the image units. The
222
- units can either be "counts" or "cps" (counts per second.) If it is
223
- left blank, the value is assumed to be "cps." If the value is counts,
224
- before using the input image it is scaled by dividing it by the
225
- exposure time.
226
-
227
- expkey : string, optional
228
- The name of the header keyword containing the exposure time. The
229
- exposure time is used to scale the image if the units are counts and
230
- to scale the image weighting if the drizzle was initialized with
231
- wt_scl equal to "exptime" or "expsq." If the value of this parameter
232
- is blank, the exposure time is set to one, implying no scaling.
233
-
234
- wt_scl : float, optional
235
- If drizzle was initialized with wt_scl left blank, this value will
236
- set a scaling factor for the pixel weighting. If drizzle was
237
- initialized with wt_scl set to "exptime" or "expsq", the exposure time
238
- will be used to set the weight scaling and the value of this parameter
239
- will be ignored.
240
- """
241
-
242
- insci = None
243
- inwht = None
244
-
245
- if not util.is_blank(infile):
246
- fileroot, extn = util.parse_filename(infile)
247
-
248
- if os.path.exists(fileroot):
249
- handle = fits.open(fileroot)
250
- hdu = util.get_extn(handle, extn=extn)
251
-
252
- if hdu is not None:
253
- insci = hdu.data
254
- inwcs = wcs.WCS(header=hdu.header)
255
- insci = hdu.data.copy()
256
- handle.close()
257
-
258
- if insci is None:
259
- raise ValueError("Drizzle cannot find input file: %s" % infile)
260
-
261
- if not util.is_blank(inweight):
262
- fileroot, extn = util.parse_filename(inweight)
263
-
264
- if os.path.exists(fileroot):
265
- handle = fits.open(fileroot)
266
- hdu = util.get_extn(handle, extn=extn)
267
-
268
- if hdu is not None:
269
- inwht = hdu.data.copy()
270
- handle.close()
271
-
272
- in_units = util.get_keyword(fileroot, unitkey, "cps")
273
- expin = util.get_keyword(fileroot, expkey, 1.0)
274
-
275
- self.add_image(insci, inwcs, inwht=inwht,
276
- xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax,
277
- expin=expin, in_units=in_units, wt_scl=wt_scl)
278
-
279
- def add_image(self, insci, inwcs, inwht=None,
280
- xmin=0, xmax=0, ymin=0, ymax=0,
281
- expin=1.0, in_units="cps", wt_scl=1.0):
282
- """
283
- Combine an input image with the output drizzled image.
284
-
285
- Instead of reading the parameters from a fits file, you can set
286
- them by calling this lower level method. `Add_fits_file` calls
287
- this method after doing its setup.
288
-
289
- Parameters
290
- ----------
291
-
292
- insci : array
293
- A 2d numpy array containing the input image to be drizzled.
294
- it is an error to not supply an image.
295
-
296
- inwcs : wcs
297
- The world coordinate system of the input image. This is
298
- used to convert the pixels to the output coordinate system.
299
-
300
- inwht : array, optional
301
- A 2d numpy array containing the pixel by pixel weighting.
302
- Must have the same dimenstions as insci. If none is supplied,
303
- the weghting is set to one.
304
-
305
- xmin : float, optional
306
- This and the following three parameters set a bounding rectangle
307
- on the output image. Only pixels on the output image inside this
308
- rectangle will have their flux updated. Xmin sets the minimum value
309
- of the x dimension. The x dimension is the dimension that varies
310
- quickest on the image. If the value is zero or less, no minimum will
311
- be set in the x dimension. All four parameters are zero based,
312
- counting starts at zero.
313
-
314
- xmax : float, optional
315
- Sets the maximum value of the x dimension on the bounding box
316
- of the ouput image. If the value is zero or less, no maximum will
317
- be set in the x dimension.
318
-
319
- ymin : float, optional
320
- Sets the minimum value in the y dimension on the bounding box. The
321
- y dimension varies less rapidly than the x and represents the line
322
- index on the output image. If the value is zero or less, no minimum
323
- will be set in the y dimension.
324
-
325
- ymax : float, optional
326
- Sets the maximum value in the y dimension. If the value is zero or
327
- less, no maximum will be set in the y dimension.
328
-
329
- expin : float, optional
330
- The exposure time of the input image, a positive number. The
331
- exposure time is used to scale the image if the units are counts and
332
- to scale the image weighting if the drizzle was initialized with
333
- wt_scl equal to "exptime" or "expsq."
334
-
335
- in_units : str, optional
336
- The units of the input image. The units can either be "counts"
337
- or "cps" (counts per second.) If the value is counts, before using
338
- the input image it is scaled by dividing it by the exposure time.
339
-
340
- wt_scl : float, optional
341
- If drizzle was initialized with wt_scl left blank, this value will
342
- set a scaling factor for the pixel weighting. If drizzle was
343
- initialized with wt_scl set to "exptime" or "expsq", the exposure time
344
- will be used to set the weight scaling and the value of this parameter
345
- will be ignored.
346
- """
347
-
348
- insci = insci.astype(np.float32)
349
- util.set_pscale(inwcs)
350
-
351
- if inwht is None:
352
- inwht = np.ones(insci.shape, dtype=insci.dtype)
353
- else:
354
- inwht = inwht.astype(np.float32)
355
-
356
- if self.wt_scl == "exptime":
357
- wt_scl = expin
358
- elif self.wt_scl == "expsq":
359
- wt_scl = expin * expin
360
-
361
- self.increment_id()
362
- self.outexptime += expin
363
-
364
- dodrizzle.dodrizzle(insci, inwcs, inwht, self.outwcs,
365
- self.outsci, self.outwht, self.outcon,
366
- expin, in_units, wt_scl,
367
- wcslin_pscale=inwcs.pscale, uniqid=self.uniqid,
368
- xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax,
369
- pixfrac=self.pixfrac, kernel=self.kernel,
370
- fillval=self.fillval)
371
-
372
- def blot_fits_file(self, infile, interp='poly5', sinscl=1.0):
373
- """
374
- Resample the output using another image's world coordinate system.
375
-
376
- Parameters
377
- ----------
378
-
379
- infile : str
380
- The name of the fits file containing the world coordinate
381
- system that the output file will be resampled to. The name may
382
- possibly include an extension.
383
-
384
- interp : str, optional
385
- The type of interpolation used in the resampling. The
386
- possible values are "nearest" (nearest neighbor interpolation),
387
- "linear" (bilinear interpolation), "poly3" (cubic polynomial
388
- interpolation), "poly5" (quintic polynomial interpolation),
389
- "sinc" (sinc interpolation), "lan3" (3rd order Lanczos
390
- interpolation), and "lan5" (5th order Lanczos interpolation).
391
-
392
- sincscl : float, optional
393
- The scaling factor for sinc interpolation.
394
- """
395
- blotwcs = None
396
-
397
- fileroot, extn = util.parse_filename(infile)
398
-
399
- if os.path.exists(fileroot):
400
- handle = fits.open(fileroot)
401
- hdu = util.get_extn(handle, extn=extn)
402
-
403
- if hdu is not None:
404
- blotwcs = wcs.WCS(header=hdu.header)
405
- handle.close()
406
-
407
- if not blotwcs:
408
- raise ValueError("Drizzle did not get a blot reference image")
409
-
410
- self.blot_image(blotwcs, interp=interp, sinscl=sinscl)
411
-
412
- def blot_image(self, blotwcs, interp='poly5', sinscl=1.0):
413
- """
414
- Resample the output image using an input world coordinate system.
415
-
416
- Parameters
417
- ----------
418
-
419
- blotwcs : wcs
420
- The world coordinate system to resample on.
421
-
422
- interp : str, optional
423
- The type of interpolation used in the resampling. The
424
- possible values are "nearest" (nearest neighbor interpolation),
425
- "linear" (bilinear interpolation), "poly3" (cubic polynomial
426
- interpolation), "poly5" (quintic polynomial interpolation),
427
- "sinc" (sinc interpolation), "lan3" (3rd order Lanczos
428
- interpolation), and "lan5" (5th order Lanczos interpolation).
429
-
430
- sincscl : float, optional
431
- The scaling factor for sinc interpolation.
432
- """
433
-
434
- util.set_pscale(blotwcs)
435
- self.outsci = doblot.doblot(self.outsci, self.outwcs, blotwcs,
436
- 1.0, interp=interp, sinscl=sinscl)
437
-
438
- self.outwcs = blotwcs
439
-
440
- def increment_id(self):
441
- """
442
- Increment the id count and add a plane to the context image if needed
443
-
444
- Drizzle tracks which input images contribute to the output image
445
- by setting a bit in the corresponding pixel in the context image.
446
- The uniqid indicates which bit. So it must be incremented each time
447
- a new image is added. Each plane in the context image can hold 32 bits,
448
- so after each 32 images, a new plane is added to the context.
449
- """
450
-
451
- # Compute what plane of the context image this input would
452
- # correspond to:
453
- planeid = int(self.uniqid / 32)
454
-
455
- # Add a new plane to the context image if planeid overflows
456
-
457
- if self.outcon.shape[0] == planeid:
458
- plane = np.zeros_like(self.outcon[0])
459
- self.outcon = np.append(self.outcon, [plane], axis=0)
460
-
461
- # Increment the id
462
- self.uniqid += 1
463
-
464
- def write(self, outfile, out_units="cps", outheader=None):
465
- """
466
- Write the output from a set of drizzled images to a file.
467
-
468
- The output file will contain three extensions. The "SCI" extension
469
- contains the resulting image. The "WHT" extension contains the
470
- combined weights. The "CTX" extension is a bit map. The nth bit
471
- is set to one if the nth input image contributed non-zero flux
472
- to the output image. The "CTX" image is three dimensionsional
473
- to account for the possibility that there are more than 32 input
474
- images.
475
-
476
- Parameters
477
- ----------
478
-
479
- outfile : str
480
- The name of the output file. If the file already exists,
481
- the old file is deleted after writing the new file.
482
-
483
- out_units : str, optional
484
- The units of the output image, either `counts` or `cps`
485
- (counts per second.) If the units are counts, the resulting
486
- image will be multiplied by the computed exposure time.
487
-
488
- outheader : header, optional
489
- A fits header containing cards to be added to the primary
490
- header of the output image.
491
- """
492
-
493
- if out_units != "counts" and out_units != "cps":
494
- raise ValueError("Illegal value for out_units: %s" % str(out_units))
495
-
496
- # Write the WCS to the output image
497
-
498
- handle = self.outwcs.to_fits()
499
- phdu = handle[0]
500
-
501
- # Write the class fields to the primary header
502
- phdu.header['DRIZOUDA'] = \
503
- (self.sciext, 'Drizzle, output data image')
504
- phdu.header['DRIZOUWE'] = \
505
- (self.whtext, 'Drizzle, output weighting image')
506
- phdu.header['DRIZOUCO'] = \
507
- (self.ctxext, 'Drizzle, output context image')
508
- phdu.header['DRIZWTSC'] = \
509
- (self.wt_scl, 'Drizzle, weighting factor for input image')
510
- phdu.header['DRIZKERN'] = \
511
- (self.kernel, 'Drizzle, form of weight distribution kernel')
512
- phdu.header['DRIZPIXF'] = \
513
- (self.pixfrac, 'Drizzle, linear size of drop')
514
- phdu.header['DRIZFVAL'] = \
515
- (self.fillval, 'Drizzle, fill value for zero weight output pix')
516
- phdu.header['DRIZOUUN'] = \
517
- (out_units, 'Drizzle, units of output image - counts or cps')
518
-
519
- # Update header keyword NDRIZIM to keep track of how many images have
520
- # been combined in this product so far
521
- phdu.header['NDRIZIM'] = (self.uniqid, 'Drizzle, number of images')
522
-
523
- # Update header of output image with exptime used to scale the output data
524
- # if out_units is not counts, this will simply be a value of 1.0
525
- # the keyword 'exptime' will always contain the total exposure time
526
- # of all input image regardless of the output units
527
-
528
- phdu.header['EXPTIME'] = \
529
- (self.outexptime, 'Drizzle, total exposure time')
530
-
531
- outexptime = 1.0
532
- if out_units == 'counts':
533
- np.multiply(self.outsci, self.outexptime, self.outsci)
534
- outexptime = self.outexptime
535
- phdu.header['DRIZEXPT'] = (outexptime, 'Drizzle, exposure time scaling factor')
536
-
537
- # Copy the optional header to the primary header
538
-
539
- if outheader:
540
- phdu.header.extend(outheader, unique=True)
541
-
542
- # Add three extensions containing, the drizzled output image,
543
- # the total counts, and the context bitmap, in that order
544
-
545
- extheader = self.outwcs.to_header()
546
-
547
- ehdu = fits.ImageHDU()
548
- ehdu.data = self.outsci
549
- ehdu.header['EXTNAME'] = (self.sciext, 'Extension name')
550
- ehdu.header['EXTVER'] = (1, 'Extension version')
551
- ehdu.header.extend(extheader, unique=True)
552
- handle.append(ehdu)
553
-
554
- whdu = fits.ImageHDU()
555
- whdu.data = self.outwht
556
- whdu.header['EXTNAME'] = (self.whtext, 'Extension name')
557
- whdu.header['EXTVER'] = (1, 'Extension version')
558
- whdu.header.extend(extheader, unique=True)
559
- handle.append(whdu)
560
-
561
- xhdu = fits.ImageHDU()
562
- xhdu.data = self.outcon
563
- xhdu.header['EXTNAME'] = (self.ctxext, 'Extension name')
564
- xhdu.header['EXTVER'] = (1, 'Extension version')
565
- xhdu.header.extend(extheader, unique=True)
566
- handle.append(xhdu)
567
-
568
- handle.writeto(outfile, overwrite=True)
569
- handle.close()