Пример #1
0
 def _update_bounding_polygon(self):
     polygons = [im.polygon for im in self._images]
     if len(polygons) == 0:
         self._polygon = SphericalPolygon([])
         self._radec = []
     else:
         self._polygon = SphericalPolygon.multi_union(polygons)
         self._radec = list(self._polygon.to_radec())
Пример #2
0
 def update_bounding_polygon(self):
     """ Recompute bounding polygons of the member images.
     """
     polygons = [im.polygon for im in self._images]
     if len(polygons) == 0:
         self._polygon = SphericalPolygon([])
     else:
         self._polygon = SphericalPolygon.multi_union(polygons)
Пример #3
0
    def set_members(self, mlist, polygon):
        if mlist is None:
            member_list = []
        elif isinstance(mlist, list):
            member_list = mlist
            if [1 for m in mlist if not isinstance(m, SkyLineMember)]:
                raise ValueError("The \'mlist\' argument must be either "\
                                 "a single \'SkyLineMember\' object or a " \
                                 "Python list of \'SkyLineMember\' objects.")
        elif isinstance(mlist, SkyLineMember):
            member_list = [mlist]
        else:
            raise ValueError("The \'mlist\' argument must be either "\
                             "a single \'SkyLineMember\' object or a " \
                             "Python list of \'SkyLineMember\' objects.")

        self._members = []

        # Not using set to preserve order
        n = len(member_list)
        if n == 0:
            if polygon is None:
                self.polygon = SphericalPolygon([])
            else:
                self.polygon = deepcopy(polygon)
            self._id = ''
            self._is_mf_mosaic = False
        elif n == 1:
            assert isinstance(member_list[0], SkyLineMember)
            if polygon is None:
                self.polygon = deepcopy(member_list[0].polygon)
            else:
                self.polygon = deepcopy(polygon)
            self._id = member_list[0].id
            self._members.append(member_list[0])
            self._is_mf_mosaic = False
        else:
            assert isinstance(member_list[0], SkyLineMember)
            if polygon is None:
                mpol = deepcopy(member_list[0].polygon)
            else:
                mpol = deepcopy(polygon)
            self._members.append(member_list[0])

            for m in member_list[1:]:
                # Report corrupted members list instead of skipping
                assert isinstance(m, SkyLineMember)

                if m not in self._members:
                    self._members.append(m)
                    if polygon is None:
                        mpol = mpol.union(m.polygon)

            self.polygon = mpol
            self._update_mosaic_flag_id()
Пример #4
0
    def __init__(self,
                 image,
                 wcs_fwd,
                 wcs_inv,
                 pix_area=1.0,
                 convf=1.0,
                 mask=None,
                 id=None,
                 skystat=None,
                 stepsize=None,
                 meta=None):
        """ Initializes the SkyImage object.

        Parameters
        ----------
        image : numpy.ndarray
            A 2D array of image data.

        wcs_fwd : function
            "forward" pixel-to-world transformation function.

        wcs_inv : function
            "inverse" world-to-pixel transformation function.

        pix_area : float, optional
            Average pixel's sky area.

        convf : float, optional
            Conversion factor that when multiplied to `image` data converts
            the data to "uniform" (across multiple images) surface
            brightness units.

            .. note::

              The functionality to support this conversion is not yet
              implemented and at this moment `convf` is ignored.

        mask : numpy.ndarray
            A 2D array that indicates
            what pixels in the input `image` should be used for sky
            computations (``1``) and which pixels should **not** be used
            for sky computations (``0``).

        id : anything
            The value of this parameter is simple stored within the `SkyImage`
            object. While it can be of any type, it is prefereble that `id` be
            of a type with nice string representation.

        skystat : callable, None, optional
            A callable object that takes a either a 2D image (2D
            `numpy.ndarray`) or a list of pixel values (a Nx1 array) and
            returns a tuple of two values: some statistics (e.g., mean,
            median, etc.) and number of pixels/values from the input image
            used in computing that statistics.

            When `skystat` is not set, `SkyImage` will use
            :py:class:`~jwst_pipeline.skymatch.skystatistics.SkyStats` object
            to perform sky statistics on image data.

        stepsize : int, None, optional
            Spacing between vertices of the image's bounding polygon. Default
            value of `None` creates bounding polygons with four vertices
            corresponding to the corners of the image.

        meta : dict, None, optional
            A dictionary of various items to be stored within the `SkyImage`
            object.

        """
        self.image = image
        self.convf = convf
        self.meta = meta
        self._id = id
        self._pix_area = pix_area

        # WCS
        self.wcs_fwd = wcs_fwd
        self.wcs_inv = wcs_inv

        # initial sky value:
        self._sky = 0.0

        # check that mask has the same shape as image:
        if mask is None:
            self.mask = None

        else:
            if image is None:
                raise ValueError("'mask' must be None when 'image' is None")

            self.mask = np.asanyarray(mask, dtype=np.bool)

            if self.mask.shape != image.shape:
                raise ValueError("'mask' must have the same shape as 'image'.")

        # create spherical polygon bounding the image
        if image is None or wcs_fwd is None or wcs_inv is None:
            self._radec = [(np.array([]), np.array([]))]
            self._polygon = SphericalPolygon([])
            self._poly_area = 0.0

        else:
            self.calc_bounding_polygon(stepsize)

        # set sky statistics function (NOTE: it must return statistics and
        # the number of pixels used after clipping)
        if skystat is None:
            self.set_builtin_skystat()
        else:
            self.skystat = skystat
Пример #5
0
    def calc_sky(self, overlap=None, delta=True):
        """
        Compute sky background value.

        Parameters
        ----------
        overlap : SkyImage, SkyGroup, SphericalPolygon, list of tuples, \
None, optional
            Another `SkyImage`, `SkyGroup`,
            :py:class:`stsci.sphere.polygons.SphericalPolygon`, or
            a list of tuples of (RA, DEC) of vertices of a spherical
            polygon. This parameter is used to indicate that sky statistics
            should computed only in the region of intersection of *this*
            image with the polygon indicated by `overlap`. When `overlap` is
            `None`, sky statistics will be computed over the entire image.

        delta : bool, optional
            Should this function return absolute sky value or the difference
            between the computed value and the value of the sky stored in the
            `sky` property.

        Returns
        -------
        skyval : float, None
            Computed sky value (absolute or relative to the `sky` attribute).
            If there are no valid data to perform this computations (e.g.,
            because this image does not overlap with the image indicated by
            `overlap`), `skyval` will be set to `None`.

        npix : int
            Number of pixels used to compute sky statistics.

        polyarea : float
            Area (in srad) of the polygon that bounds data used to compute
            sky statistics.

        """
        if overlap is None:

            if self.mask is None:
                data = self.image
            else:
                data = self.image[self.mask]

            polyarea = self.poly_area

        else:
            fill_mask = np.zeros(self.image.shape, dtype=bool)

            if isinstance(overlap, SkyImage):
                intersection = self.intersection(overlap)
                polyarea = np.fabs(intersection.area())
                radec = list(intersection.to_radec())

            elif isinstance(overlap, SkyGroup):
                radec = []
                polyarea = 0.0
                for im in overlap:
                    intersection = self.intersection(im)
                    polyarea1 = np.fabs(intersection.area())
                    if polyarea1 == 0.0:
                        continue
                    polyarea += polyarea1
                    radec += list(intersection.to_radec())

            elif isinstance(overlap, SphericalPolygon):
                radec = []
                polyarea = 0.0
                for p in overlap._polygons:
                    intersection = self.intersection(SphericalPolygon([p]))
                    polyarea1 = np.fabs(intersection.area())
                    if polyarea1 == 0.0:
                        continue
                    polyarea += polyarea1
                    radec += list(intersection.to_radec())

            else:  # assume a list of (ra, dec) tuples:
                radec = []
                polyarea = 0.0
                for r, d in overlap:
                    poly = SphericalPolygon.from_radec(r, d)
                    polyarea1 = np.fabs(poly.area())
                    if polyarea1 == 0.0 or len(r) < 4:
                        continue
                    polyarea += polyarea1
                    radec.append(self.intersection(poly).to_radec())

            if polyarea == 0.0:
                return (None, 0, 0.0)

            for ra, dec in radec:
                if len(ra) < 4:
                    continue

                # set pixels in 'fill_mask' that are inside a polygon to True:
                x, y = self.wcs_inv(ra, dec, 0)
                poly_vert = list(zip(*[x, y]))

                polygon = region.Polygon(True, poly_vert)
                fill_mask = polygon.scan(fill_mask)

            if self.mask is not None:
                fill_mask &= self.mask

            data = self.image[fill_mask]

            if data.size < 1:
                return (None, 0, 0.0)

        # Calculate sky
        try:

            skyval, npix = self._skystat(data)

        except ValueError:

            return (None, 0, 0.0)

        if delta:
            skyval -= self._sky

        return skyval, npix, polyarea