def NOAADUST(ch4,ch5): numerator = NDDataArray.subtract(ch5, ch4) denominator = NDDataArray.add(ch4, ch5) dust = NDDataArray.divide(numerator, denominator) plt.imshow(dust,cmap="hot") plt.show() return dust
def NDVI(): import time import matplotlib.pyplot as plt import matplotlib.image as mpimg from astropy.nddata import NDDataArray print("This programm will lead you through creating a NDVI map from images") print("It works under assumption that you input two images into it: A Red band image and Near infrared image") print("The images must be monochrome, cloudless and it would be best if they had a ocean mask applied.") print("If they contain clouds/waterbodies, those will also be falsely ranged on scale.") print("NIR is Band 4, R is Band 3 or broadband VIS") # pathNIR=input("Please input the path to near infrared image: ") # pathR=input("Please input the path to red image: ") print("Please select a color pallete you want to use. Available palletes:") print("Greens Greys hot seismic") cmapN = input() r = mpimg.imread('C:/Users/Karol/Desktop/NIR.png') nir = mpimg.imread('C:/Users/Karol/Desktop/R.png') numerator = NDDataArray.subtract(nir, r) denominator = NDDataArray.add(nir, r) ndvi = NDDataArray.divide(numerator, denominator) plt.imshow(ndvi, cmap=cmapN) plt.colorbar() plt.show()
def log10(self): '''Computes the base-10 log of the image data values''' # Grab the data if posible if not self.has_dimensionless_units: raise TypeError( 'Can only apply `log10` function to dimensionless quantities') selfData = self.data outData = np.log10(selfData) # Propagate uncertainty if it exists if self.uncertainty is not None: selfUncert = self.uncertainty outUncert = StdDevUncertainty(selfUncert / (selfData * np.log(10))) else: outUncert = None # Compute the base-10 log and store the propagated uncertainty outImg = self.copy() outImg._BaseImage__fullData = NDDataArray( outData, uncertainty=outUncert, unit=u.dimensionless_unscaled, wcs=self._BaseImage__fullData.wcs) return outImg
def sqrt(self): '''Computes the square root of the image data values''' # Grab the data selfData = self.data outData = np.sqrt(selfData) # Propagate uncertainty if it exists if self.uncertainty is not None: selfUncert = self.uncertainty outUncert = StdDevUncertainty(selfUncert / (2 * outData)) else: outUncert = None # Attempt to take the square root of the units try: outUnit = np.sqrt(u.Quantity(1, self.unit)).unit except: outUnit = u.dimensionless_unscaled # Compute the sqare root and store the propagated uncertainty outImg = self.copy() outImg._BaseImage__fullData = NDDataArray( outData, uncertainty=outUncert, unit=outUnit, wcs=self._BaseImage__fullData.wcs) return outImg
def arctan(self): '''Computes the arctan of the image data values''' # Check if the image is a dimensionless quantity if not self.has_dimensionless_units: raise TypeError( 'Can only apply `arctan` function to dimensionless quantities') # Grab the data selfData = self.data # Propagate uncertainty if it exists if self.uncertainty is not None: selfUncert = self.uncertainty outUncert = StdDevUncertainty(selfUncert / (1.0 + selfData**2)) else: outUncert = None # Compute the arctan and store the propagated uncertainty outImg = self.copy() outImg._BaseImage__fullData = NDDataArray( np.arccos(selfData), uncertainty=outUncert, unit=u.rad, wcs=self._BaseImage__fullData.wcs) return outImg
def tan(self): '''Computes the tangent of the image data values''' # Check if the image has angle units if not self.has_angle_units: raise TypeError( 'Can only apply `tan` function to quantities with angle units') selfRadData = (self.data * self.unit).to(u.rad) selfData = selfRadData.value # Propagate uncertainty if it exists if self.uncertainty is not None: selfRadUncert = (self.uncertainty * self.unit).to(u.rad) selfUncert = selfRadUncert.value outUncert = StdDevUncertainty(selfUncert / (np.cos(selfData)**2)) else: outUncert = None # Compute the sine and store the propagated uncertainty outImg = self.copy() outImg._BaseImage__fullData = NDDataArray( np.tan(selfData), uncertainty=outUncert, unit=u.dimensionless_unscaled, wcs=self.wcs) return outImg
def __init__(self, *args, **kwargs): # Invoke the parent class constructor super(RawImage, self).__init__(*args, **kwargs) # Indicate that the array has not yet been overscan corrected self.__overscanCorrected = False # If either prescan or overscan areas were defined, then ensure the # `data` attribute does not include those regions if (self.prescanArray is not None) or (self.overscanArray is not None): # Copy the full data array data = self.data.copy() # Overwrite the array so that it doesn't include the precscan data self._BaseImage__fullData = NDDataArray( data[:, self.prescanWidth:-self.overscanWidth], uncertainty=self._BaseImage__fullData.uncertainty, unit=self._BaseImage__fullData.unit, wcs=self._BaseImage__fullData.wcs ) # If an overscan region was defined, then do the overscan correction if (self.overscanArray is not None) and (not self.overscanCorrected): self._apply_overscan_correction() # Raw images with no units should be assumed to have ADU units if self.has_dimensionless_units: # Overwrite the array and give it ADU units self._BaseImage__fullData = NDDataArray( self._BaseImage__fullData.data, uncertainty=self._BaseImage__fullData.uncertainty, unit='adu', wcs=self._BaseImage__fullData.wcs ) # Attempt to add the ADU unit to the image header try: unitKey = self.headerKeywordDict['UNIT'] self._BaseImage__header[unitKey] = '{0:FITS}'.format(self.unit) except: pass
def pad(self, pad_width, mode, **kwargs): """ Pads the image arrays and updates the header and astrometry. Parameters ---------- pad_width: sequence, array_like, int Number of values padded to the edges of each axis. ((before_1, after_1), ... (before_N, after_N)) unique pad widths for each axis. ((before, after),) yields same before and after pad for each axis. (pad,) or int is a shortcut for before = after = pad width for all axes. The `pad_width` value in this method is identical to the `pad_width` value in the numpy.pad function. mode: str or function Sets the method by which the edges of the image are padded. This argument is directly passed along to the numpy.pad function, so see numpy.pad documentation for more information. Other parameters ---------------- All keywords allowed for numpy.pad are also permitted for this method. See the numpy.pad documentation for a complete listing of keyword arguments and their permitted values. Returns ------- outImg: `ReducedScience` Padded image with shape increased according to pad_width. """ # AstroImages are ALWAYS 2D (at most!) if len(pad_width) > 2: raise ValueError( 'Cannot use a`pad_width` value with more than 2-dimensions.') # Make a copy of the image to return to the user outImg = self.copy() # Pad the primary array outData = np.pad(self.data, pad_width, mode, **kwargs) if self._BaseImage__fullData.uncertainty is not None: outUncert = np.pad(self.uncertainty, pad_width, mode, **kwargs) outUncert = StdDevUncertainty(outUncert) else: outUncert = None # Update the header information if possible outHeader = self.header.copy() # Parse the pad_width parameter if len(pad_width) > 1: # If separate x and y paddings were specified, check them yPad, xPad = pad_width # Grab only theh left-padding values if len(xPad) > 1: xPad = xPad[0] if len(yPad) > 1: yPad = yPad[0] else: xPad, yPad = pad_width, pad_width # Update image size outHeader['NAXIS1'] = self.shape[1] outHeader['NAXIS2'] = self.shape[0] # If the header has a valid WCS, then update that info, too. if self.has_wcs: if self.wcs.has_celestial: # Now apply the actual updates to the header outHeader['CRPIX1'] = self.header['CRPIX1'] + xPad outHeader['CRPIX2'] = self.header['CRPIX2'] + yPad # Retrieve the new WCS from the updated header outWCS = WCS(outHeader) else: outWCS = None # And store the updated header in the self object outImg._BaseImage__header = outHeader # Finally replace the _BaseImage__fullData attribute outImg._BaseImage__fullData = NDDataArray(outData, uncertainty=outUncert, unit=self.unit, wcs=outWCS) return outImg
def crop(self, lowPix, highPix): # TODO use the self.wcs.wcs.sub() method to recompute the right wcs # for a cropped image. """ Crops the image to the specified pixel locations. Parameters ---------- lowPix : tuple The starting point of the crop along each axis. highPix : tuple The stopping point of the crop along each axis. Returns ------- outImg: `ReducedScience` A copy of the image cropped to the specified locations with updated header and astrometry. """ # Decompose the crop endpoints bt, lf = lowPix tp, rt = highPix for p in (bt, tp, lf, rt): if not issubclass(type(p), (int, np.int16, np.int32, np.int64)): TypeError('All arguments must be integer values') # Check that the crop values are reasonable ny, nx = self.shape if ((lf < 0) or (rt > nx) or (bt < 0) or (tp > ny) or (rt < lf) or (tp < bt)): raise ValueError( 'The requested crop values are outside the image.') # Make a copy of the array and header outData = self.data.copy() # Perform the actual croping outData = outData[bt:tp, lf:rt] # Repeat the process for the sigma array if it exists if self.uncertainty is not None: outUncert = self.uncertainty[bt:tp, lf:rt] outUncert = StdDevUncertainty(outUncert) else: outUncert = None # Copy the image header outHead = self.header.copy() # Update the header keywords # First update the NAXIS keywords outHead['NAXIS1'] = tp - bt outHead['NAXIS2'] = rt - lf # Next update the CRPIX keywords if 'CRPIX1' in outHead: outHead['CRPIX1'] = outHead['CRPIX1'] - lf if 'CRPIX2' in outHead: outHead['CRPIX2'] = outHead['CRPIX2'] - bt # Reread the WCS from the output header if it has a wcs if self.has_wcs: if self.wcs.has_celestial: outWCS = WCS(outHead) else: outWCS = None # Copy the image and update its data outImg = self.copy() outImg._BaseImage__fullData = NDDataArray(outData, uncertainty=outUncert, unit=self.unit, wcs=outWCS) # Update the header, too. outImg.header = outHead return outImg
def _apply_overscan_correction(self): """Internal "private" method to apply overscan correction""" # Test if an overscan has been defined. If not, then just return if self.overscanArray is None: raise AttributeError('There is no overscan in this image.') # Exit early if the overscan correction has already been applied if self.overscanCorrected: return try: # Try to use sklearn for regularized linear regression from sklearn.preprocessing import PolynomialFeatures from sklearn.pipeline import make_pipeline from sklearn.linear_model import Lasso regularizedLinearRegression = True except: # Otherwise simply use a 3rd order polynomial and hope for the best. regularizedLinearRegression = False # Compute the median row behavior of prescan/overscan # medianPrescanCol = np.median(self.prescanArray, axis=1) medianOverscanCol = np.median(self.overscanArray, axis=1) if regularizedLinearRegression: # Generate an estimator using up to 9th degree polynomial degree = 12 alpha = 5e-3 # Generate sapmling values X = np.arange(medianOverscanCol.size)[:, np.newaxis] y = medianOverscanCol[:, np.newaxis] # Build an estimator using the LASSO procedure est = make_pipeline(PolynomialFeatures(degree), Lasso(alpha=alpha)) with warnings.catch_warnings(): # Ignore the warnings from this method... warnings.simplefilter("ignore") # Peform the estimation est.fit(X, y) # Get the fitted overscan column fittedOverscanCol = est.predict(X) else: # If sklearn is not installed, then just do 3rd order polynomial x = np.arange(medianOverscanCol.size) y = medianOverscanCol overscanPolynom = np.polyfit(x, y, 3) fittedOverscanCol = np.polyval(overscanPolynom, x) # Extend the overscan sampling along the x-axis overscanCol = fittedOverscanCol[:, np.newaxis] overscanArr = overscanCol.repeat(self.shape[1], 1) # Subtract the overscan shape from the array and store it correctedArr = self.data.copy() - overscanArr # Build an NDDataArray instance to store the corrected array outFullData = NDDataArray( correctedArr, uncertainty=self._BaseImage__fullData.uncertainty, unit=self._BaseImage__fullData.unit, wcs=self._BaseImage__fullData.wcs ) # Store the corrected data in the hidden "fullData" attribute self._BaseImage__fullData = outFullData # Set the flag to indicate that the overscan was successfully removed. self.__overscanCorrected = True
def run(self, clobber=False, silent=False): """ Invokes the astrometry.net engine and solves the image astrometry. Parameters ---------- clobber : bool, optional, default: False If True, then whatever WCS may be stored in the header will be deleted and overwritten with a new solution. silent : bool, optional, default: False If True, then the output of the `solve-field` executable will be suppressed. (not yet working!) Returns ------- outImg : ReducedScience A copy of the original image with the best fitting astrometric solution stored in the `header` and `wcs` properties. If the astrometric solution was not successful, then this will simply be the original image. success : bool A flag to indicate whether the astrometric solution was successful. A True value indicates success and a False value indicates failure. """ # Check if a solution exists and we're not supposed to overwrite it. if self.image.has_wcs and not clobber: warnings.warn( 'Astrometry for file {0:s} already solved... skipping.'.format( os.path.basename(str(self.image.filename)))) # Return the original image and declare success outImg = self.image success = True return outImg, success # Check if astrometry.net is installed on this system if not self._test_for_astrometry_dot_net(): # Otherwise report an error! raise OSError('Astrometry.net is not installed on this system.') # Determine the name of the file on which to perform operations fileToSolve, temporaryFile = self._parse_on_disk_filename() # Convert that filename to a astrometry.net friendly name and get other # parameters for running the solver on this machine. tmp = self._get_executable_parameters(fileToSolve) prefix, astrometryCompatibleFilename, suffix, shellCommand = tmp # Combine the parameters into a singe command to be run in a shell command = self._build_executable_string(prefix, astrometryCompatibleFilename, suffix) # Use the subprocess module to run the `solve-field` executable self._run_executable_solver(command, shellCommand, silent=silent) # Check if the expected output files are there and extract astrometry wcs, success, tmpFilePaths = self._read_astrometric_solution_from_disk( ) if success: # If there was a WCS to be read, then... # Make a copy of the image to be returned outImg = self.image.copy() # Clear out the old astrometry and insert new astrometry outImg.astrometry_to_header(wcs) # Build the appropriate output uncertainty if outImg._BaseImage__fullData.uncertainty is not None: outUncert = StdDevUncertainty(outImg.uncertainty) else: outUncert = None # Place the same WCS in the output image __fullData attribute outImg._BaseImage__fullData = NDDataArray(outImg.data, uncertainty=outUncert, unit=outImg.unit, wcs=wcs) else: # If there was no WCS, then return original image and a False # success value outImg = self.image # Delete the temporary files now that the WCS has been extracted self._cleanup_temporary_files(tmpFilePaths, fileToSolve, temporaryFile) # Return the results to the user return outImg, success
#!/usr/bin/env python # This is a minimum failing example for NDDataArray raising an AttributeError # if the instance is used as the operand of multiply() or # divide() and is then used as the operator. # # - Marc Pound Tue Jul 16 15:43:51 EDT 2019 # [email protected] # github.com/mpound import traceback from astropy.nddata import NDDataArray, StdDevUncertainty from copy import deepcopy n1 = NDDataArray(data=3., uncertainty=StdDevUncertainty(4.)) n2 = NDDataArray(data=4., uncertainty=StdDevUncertainty(3.)) n3 = NDDataArray(data=5., uncertainty=StdDevUncertainty(2.)) n4 = deepcopy(n2) #ok print("n1.multiply(n2)...OK") n1.multiply(n2) #ok print("n3.multiply(n1)...OK") n3.multiply(n1) # will raise AttributeError try: print("Reuse operand as operator : n2.divide(n1)...") n2.divide(n1) except AttributeError as ex:
def __mod__(self, other): """Computes the modulus of the data against the provided value""" # Grab the data if posible if issubclass(type(other), BaseImage): # Modulus another astroimage instance otherData = other.convert_units_to(self.unit).data # Grab the uncertainty of the other image if possible if other.has_uncertainty: otherUncert = other.uncertainty else: otherUncert = 0.0 elif issubclass(type(other), u.Quantity): # Modulus a Quantity instance # Attempt to force these into the same units try: otherData = other.to(self.unit) except: raise # Assume zero uncertainty otherUncert = 0.0 elif (self.has_dimensionless_units and issubclass(type(other), (int, np.int8, np.int16, np.int32, np.int64, float, np.float16, np.float32, np.float64))): # Modulus a unitless scalar quantity (if image is unitless) otherData = other # Assume zero uncertainty otherUncert = 0.0 else: # Incompatible types and/or units raise TypeError( 'Cannot take modulus of {0} with {1} units and {2}'.format( type(self).__name__, str(self.unit), type(other).__name__)) # Grab the uncertainty from the self instance if self.has_uncertainty: selfUncert = self.uncertainty else: selfUncert = 0.0 # Attempt the modulus outData = (self.data * self.unit) % otherData outUncert = np.sqrt(selfUncert**2 + otherUncert**2) # Double check that SOME kind of uncertainty exists here, and # wrap it appropriately. if np.all(outUncert == 0): outUncert = None else: outUncert = StdDevUncertainty(outUncert) # Construct the output image outImg = self.copy() try: outImg._BaseImage__fullData = NDDataArray(outData, uncertainty=outUncert, unit=outImg.unit, wcs=outImg.wcs) except: import pdb pdb.set_trace() # Return the added image return outImg
def arctan2(self, other): '''Computes the 'smart' arctan of the ratio of two images''' # Grab the data if posible if not self.has_dimensionless_units: raise TypeError( 'Can only apply `arctan` function to dimensionless quantities') if issubclass(type(other), BaseImage): # Handle BaseImage (or subclass) instance if not other.has_dimensionless_units: raise TypeError( 'Can only apply `arctan` function to dimensionless quantities' ) otherData = other.data # Grab the uncertainty of the other image if possible if other.uncertainty is not None: otherUncert = other.uncertainty else: otherUncert = 0.0 elif issubclass(type(other), u.Quantity): # Handle Quantity instance if not other.has_dimensionless_units: raise TypeError( 'Can only apply `arctan` function to dimensionless quantities' ) otherData = other.value # Assume zero uncertainty otherUncert = 0.0 elif issubclass(type(other), (int, np.int8, np.int16, np.int32, np.int64, float, np.float16, np.float32, np.float64)): # Add a unitless scalar quantity (if image is unitless) otherData = other # Assume zero uncertainty otherUncert = 0.0 else: # Incompatible types and/or units raise TypeError( 'Cannot compute arctan {0} with {1} units and {2}'.format( type(self).__name__, str(self.unit), type(other).__name__)) # Grab the uncertainty of this image if self.uncertainty is not None: selfUncert = self.uncertainty else: selfUncert = 0.0 # Grab the data selfData = self.data # Compute the smart arctan2(x,y) outData = np.arctan2(selfData, otherData) # Check if the uncertainty is "zero" uncertExists = not (np.all(selfUncert == 0) and np.all(otherUncert == 0)) if uncertExists: # Compute the propagated uncertainty # d/dx (arctan2(x,y)) = +x/(x^2 + y^2) # d/dy (arctan2(x,y)) = -y/(x^2 + y^2) d_arctan_dx = +selfData / (selfData**2 + otherData**2) d_arctan_dy = -otherData / (selfData**2 + otherData**2) outUncert = StdDevUncertainty( np.sqrt((d_arctan_dx * selfUncert)**2 + (d_arctan_dy * otherUncert)**2)) else: outUncert = None # Copy the image and store the output outImg = self.copy() outImg._BaseImage__fullData = NDDataArray( outData, uncertainty=outUncert, unit=u.rad, wcs=self._BaseImage__fullData.wcs) return outImg
def _rebin_wcs(self, outShape): """ Applies a rebinning to the WCS parameters in the header. Parameters ---------- outShape : tuple of ints The new shape for the rebinned image. This must be an integer factor of the shape of the original image, although the integer factor does not need to be the same along each axis. Returns ------- outImg : `astroimage.reduced.ReducedScience` (or subclass) The rebinned image instance. """ # Extract the shape and rebinning properties ny1, nx1 = self.shape ny, nx = outShape dxdy = np.array([nx1 / nx, ny1 / ny]) # Copy the image outImg = self.copy() # Catch the case where there is no WCS to rebin if not self.has_wcs: return outImg # Now treat the WCS for images which have astrometry. # Recompute the CRPIX and place them in the header CRPIX1, CRPIX2 = self.wcs.wcs.crpix / dxdy outImg.header['CRPIX1'] = CRPIX1 outImg.header['CRPIX2'] = CRPIX2 # Grab the CD matrix if self.wcs.wcs.has_cd(): # Grab the cd matrix and modify it by the rebinning factor cd = dxdy * self.wcs.wcs.cd elif self.wcs.wcs.has_pc(): # Convert the pc matrix into a cd matrix cd = dxdy * self.wcs.wcs.cdelt * self.wcs.wcs.pc # Delete the PC matrix so that it can be replaced with a CD matrix del outImg.header['PC*'] else: raise ValueError('`wcs` does not include proper astrometry') # Loop through the CD values and replace them with updated values for i, row in enumerate(cd): for j, cdij in enumerate(row): key = 'CD' + '_'.join([str(i + 1), str(j + 1)]) outImg.header[key] = cdij # TODO: Verify that the SIP polynomial treatment is correct # (This may require some trial and error) # Loop through all possible coefficients, starting at the 2nd order # values, JUST above the linear (CD matrix) relations. for AB in ['A', 'B']: ABorderKey = '_'.join([AB, 'ORDER']) # Check if there is a distortion polynomial to handle. if ABorderKey in outImg.header: highestOrder = outImg.header[ABorderKey] # Loop through each order (2nd, 3rd, 4th, etc...) for o in range(2, highestOrder + 1): # Loop through each of the horizontal axis order values for i in range(o + 1): # Compute the vertical axis order value for THIS order j = o - i # Compute the correction factor given the rebinning # amount along each independent axis. ABcorrFact = (dxdy[0]**i) * (dxdy[1]**j) # Construct the key in which the SIP coeff is stored ABkey = '_'.join([AB, str(i), str(j)]) # Update the SIP coefficient outImg.header[ABkey] = ABcorrFact * self.header[ABkey] # Repeat this for the inverse transformation (AP_i_j, BP_i_j). APBP = AB + 'P' APBPorderKey = '_'.join([APBP, 'ORDER']) if APBPorderKey in outImg.header: highestOrder = outImg.header[APBPorderKey] # Start at FIRST order this time... for o in range(1, highestOrder + 1): for i in range(o + 1): j = o - i # Skip the zeroth order (simply provided by CRVAL) if i == 0 and j == 0: continue # Compute the correction factor and apply it. APBPcorrFact = (dxdy[0]**(-i)) * (dxdy[1]**(-j)) APBPkey = '_'.join([APBP, str(i), str(j)]) outImg.header[ APBPkey] = APBPcorrFact * self.header[APBPkey] # Store the updated WCS and return the image to the user outImg._BaseImage__fullData = NDDataArray( outImg.data, uncertainty=StdDevUncertainty(outImg.uncertainty), unit=outImg.unit, wcs=WCS(outImg.header)) return outImg
def rebin(self, outShape, total=False): """ Rebins the image to have a specified shape. Parameters ---------- outShape : tuple of ints The new shape for the rebinned image. This must be an integer factor of the shape of the original image, although the integer factor does not need to be the same along each axis. total : bool, optional, default: False If set to true, then returned array is total of the binned pixels rather than the average. Returns ------- outImg : `astroimage.reduced.ReducedScience` (or subclass) The rebinned image instance. """ # Grab the shape of the initial array ny0, nx0 = self.shape ny, nx = outShape # TODO: Catch the case of upsampling along one axis but downsampling # along the other. This should not be possible! # Test for improper result shape goodX = ((nx0 % nx) == 0) or ((nx % nx0) == 0) goodY = ((ny0 % ny) == 0) or ((ny % ny0) == 0) if not (goodX and goodY): raise ValueError( 'Result dimensions must be integer factor of original dimensions' ) # Make a copy of the image to manipulate and return to the user outImg = self.copy() # First test for the trivial case if (nx0 == nx) and (ny0 == ny): return outImg # Compute the pixel ratios of upsampling and down sampling xratio, yratio = np.float(nx) / np.float(nx0), np.float(ny) / np.float( ny0) pixRatio = np.float(xratio * yratio) aspect = yratio / xratio #Measures change in aspect ratio. if ((nx0 % nx) == 0) and ((ny0 % ny) == 0): # Handle integer downsampling # Get the new shape for the array and compute the rebinning shape sh = (ny, ny0 // ny, nx, nx0 // nx) # Computed weighted rebinning rebinData = (self.data.reshape(sh).sum(-1).sum(1)) # Check if total flux conservation was requested. # If not, then multiply by the pixel size ratio. if not total: rebinData *= pixRatio elif ((nx % nx0) == 0) and ((ny % ny0) == 0): # Handle integer upsampling rebinData = np.kron(self.data, np.ones((ny // ny0, nx // nx0))) # Check if total flux conservation was requested. # If it was, then divide by the pixel size ratio. if total: rebinData /= pixRatio # Compute the output uncertainty if self._BaseImage__fullData.uncertainty is not None: selfVariance = (self.uncertainty)**2 if ((nx0 % nx) == 0) and ((ny0 % ny) == 0): # Handle integer downsampling rebinVariance = selfVariance.reshape(sh).sum(-1).sum(1) # Check if total flux conservation was requested. # If not, then multiply by the pixel size ratio. if total: pass if not total: rebinVariance *= (pixRatio**2) elif ((nx % nx0) == 0) and ((ny % ny0) == 0): # Handle integer upsampling rebinVariance = np.kron(selfVariance, np.ones((ny // ny0, nx // nx0))) # Check if total flux conservation was requested. # If not, then divide by the pixel size ratio. if total: rebinVariance /= pixRatio if not total: rebinVariance *= pixRatio # Convert the uncertainty into the correct class for NDDataArray rebinUncert = StdDevUncertainty(np.sqrt(rebinVariance)) else: # Handle the no-uncertainty situation rebinUncert = None # Now apply header updates to the WCS parameters (BEFORE the current # image shape gets distored by replacing the __fullData value.) outImg = outImg._rebin_wcs(outShape) # Now apply the header updates to BSCALE and BZERO keywords if total: raise NotImplementedError( 'Need to implement "_rebin_bscale_bzero" method') outImg = outImg._rebin_bscale_bzero(outShape) # Construct the output NDDataArray rebinFullData = NDDataArray(rebinData, uncertainty=rebinUncert, unit=self._BaseImage__fullData.unit, wcs=outImg.wcs) # Store the rebinned FullData outImg._BaseImage__fullData = rebinFullData # Update the header values outHead = self.header.copy() outHead['NAXIS1'] = nx outHead['NAXIS2'] = ny # Store the header in the output image outImg._BaseImage__header = outHead # Update the binning attribute to match the new array outImg._BaseImage__binning = (outImg.binning[0] / xratio, outImg.binning[1] / yratio) # Return the updated image object return outImg
def inpaint_nans(self, mask=False): """ Locates and replaces any NaN values in the image. Parameters ---------- mask : numpy.ndarray or bool, optional, default: False A numpy array indicating the location of pixels to be inpainted. Any pixels with a True value will be inpainted. Returns ------- outImg : astroimage.BaseImage subclass An image instance with the masked or NaN pixels repaired. """ # Check if mask is the right type if not issubclass(type(mask), (bool, np.ndarray)): raise TypeError('`mask` must be an numpy.ndarray') # Check if mask is the right shape if issubclass(type(mask), np.ndarray): if mask.shape != self.image.shape: raise ValueError( '`mask` must have the same shape as the image to be inpainted' ) # Prepare the data array for inpainting maskedData, proceed = self._prepare_array_for_inpainting( self.image.data, mask=mask) if not proceed: # If nothing to do, then just return to the user. return self.image print('Inpainting masked and NaN pixels.') # Inpaint the data array outData = self._inpaint_array(maskedData) # Handle the uncertainty array if it exists if self.image.uncertainty is not None: # Prepare the uncertainty array for inpainting maskedUncert, proceed = self._prepare_array_for_inpainting( self.image.uncertainty, mask=mask) # Inpaint the uncertainty array (using addition in quadrature) outUncert = np.sqrt(self._inpaint_array(maskedUncert**2)) # Wrap the uncertainty in the StdDevUncertainty class outUncert = StdDevUncertainty(outUncert) else: outUncert = None # Construct the output image outImg = self.image.copy() outImg._BaseImage__fullData = NDDataArray(outData, uncertainty=outUncert, unit=self.image.unit, wcs=self.image.wcs) return outImg