Esempio n. 1
0
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
Esempio n. 2
0
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()
Esempio n. 3
0
    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
Esempio n. 4
0
    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
Esempio n. 5
0
    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
Esempio n. 6
0
    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
Esempio n. 7
0
    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
Esempio n. 8
0
    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
Esempio n. 9
0
    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
Esempio n. 10
0
    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
Esempio n. 11
0
    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
Esempio n. 12
0
#!/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:
Esempio n. 13
0
    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
Esempio n. 14
0
    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
Esempio n. 15
0
    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
Esempio n. 16
0
    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
Esempio n. 17
0
    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