Example #1
0
    def test_noisy_background(self):
        #Use a fixed random state seed, so unit-test is reproducible:
        rstate = numpy.random.RandomState(42)
        pixel_noise = 0.5
        self.mygauss += rstate.normal(scale=pixel_noise,
                                      size=len(self.mygauss.ravel())).reshape(
                                          self.mygauss.shape)
        self.fit = fitgaussian(self.mygauss, self.moments)
        self.longMessage = True  #Show assertion fail values + given message

        # First, let's check we've converged to a reasonable fit in the
        # presence of noise:
        # print
        for param in FIT_PARAMS:
            # print param, getattr(self,param), self.fit[param]
            self.assertAlmostEqual(
                getattr(self, param),
                self.fit[param],
                places=1,
                msg=param + " misfit (bad random noise seed?)",
            )

        # Now we run the full error-profiling routine and check the chi-sq
        # calculations:
        self.fit_w_errs, _ = source_profile_and_errors(
            data=self.mygauss,
            threshold=0.,
            noise=pixel_noise,
            beam=(self.semimajor, self.semiminor, self.theta),
        )

        npix = len(self.mygauss.ravel())
        # print "CHISQ", npix, self.fit_w_errs.chisq

        # NB: this is the calculation for reduced chisq in presence of
        # independent pixels, i.e. uncorrelated noise.
        # For real data, we try to take the noise-correlation into account.
        # print "Reduced chisq", self.fit_w_errs.chisq / npix
        self.assertTrue(0.9 < self.fit_w_errs.chisq / npix < 1.1)
Example #2
0
    def test_noisy_background(self):
        #Use a fixed random state seed, so unit-test is reproducible:
        rstate = numpy.random.RandomState(42)
        pixel_noise = 0.5
        self.mygauss += rstate.normal(scale = pixel_noise,
                  size=len(self.mygauss.ravel())).reshape(self.mygauss.shape)
        self.fit = fitgaussian(self.mygauss, self.moments)
        self.longMessage = True #Show assertion fail values + given message

        # First, let's check we've converged to a reasonable fit in the
        # presence of noise:
        # print
        for param in FIT_PARAMS:
            # print param, getattr(self,param), self.fit[param]
            self.assertAlmostEqual(getattr(self,param), self.fit[param],
                               places=1,
                               msg = param +" misfit (bad random noise seed?)",
                               )

        # Now we run the full error-profiling routine and check the chi-sq
        # calculations:
        self.fit_w_errs, _ = source_profile_and_errors(
            data = self.mygauss,
            threshold=0.,
            noise=pixel_noise,
            beam = (self.semimajor, self.semiminor, self.theta),
            )


        npix = len(self.mygauss.ravel())
        # print "CHISQ", npix, self.fit_w_errs.chisq

        # NB: this is the calculation for reduced chisq in presence of
        # independent pixels, i.e. uncorrelated noise.
        # For real data, we try to take the noise-correlation into account.
        # print "Reduced chisq", self.fit_w_errs.chisq / npix
        self.assertTrue( 0.9 < self.fit_w_errs.chisq / npix < 1.1)
Example #3
0
File: image.py Project: mkuiack/tkp
    def fit_to_point(self, x, y, boxsize, threshold, fixed):
        """Fit an elliptical Gaussian to a specified point on the image.

        The fit is carried on a square section of the image, of length
        *boxsize* & centred at pixel coordinates *x*, *y*. Any data
        below *threshold* * rmsmap is not used for fitting. If *fixed*
        is set to ``position``, then the pixel coordinates are fixed
        in the fit.

        Returns an instance of :class:`tkp.sourcefinder.extract.Detection`.
        """
        if ((
                # Recent NumPy
                hasattr(numpy.ma.core, "MaskedConstant") and
                isinstance(self.rmsmap, numpy.ma.core.MaskedConstant)
            ) or (
                # Old NumPy
                numpy.ma.is_masked(self.rmsmap[x, y])
        )):
            logger.error("Background is masked: cannot fit")
            return None

        chunk = ImageData.box_slice_about_pixel(x, y, boxsize/2.0)
        if threshold is not None:
            # We'll mask out anything below threshold*self.rmsmap from the fit.
            labels, num = self.labels.setdefault( #Dictionary mapping threshold -> islands map
                threshold,
                ndimage.label(
                    self.clip.setdefault( #Dictionary mapping threshold -> mask
                        threshold,
                        numpy.where(
                            self.data_bgsubbed > threshold * self.rmsmap, 1, 0
                            )
                        )
                    )
                )


            mylabel = labels[x, y]
            if mylabel == 0:  # 'Background'
                raise ValueError("Fit region is below specified threshold, fit aborted.")
            mask = numpy.where(labels[chunk] == mylabel, 0, 1)
            fitme = numpy.ma.array(self.data_bgsubbed[chunk], mask=mask)
            if len(fitme.compressed()) < 1:
                raise IndexError("Fit region too close to edge or too small")
        else:
            fitme = self.data_bgsubbed[chunk]
            if fitme.size < 1:
                raise IndexError("Fit region too close to edge or too small")

        if not len(fitme.compressed()):
            logger.error("All data is masked: cannot fit")
            return None

        # set argument for fixed parameters based on input string
        if fixed == 'position':
            fixed = {'xbar': boxsize/2.0, 'ybar': boxsize/2.0}
        elif fixed == 'position+shape':
            fixed = {'xbar': boxsize/2.0, 'ybar': boxsize/2.0,
                     'semimajor': self.beam[0],
                     'semiminor': self.beam[1],
                     'theta': self.beam[2]}
        elif fixed == None:
            fixed = {}
        else:
            raise TypeError("Unkown fixed parameter")

        if threshold is not None:
            threshold_at_pixel = threshold * self.rmsmap[x, y]
        else:
            threshold_at_pixel = None

        try:
            measurement, residuals = extract.source_profile_and_errors(
                fitme,
                threshold_at_pixel,
                self.rmsmap[x, y],
                self.beam,
                fixed=fixed
            )
        except ValueError:
            # Fit failed to converge
            # Moments are not applicable when holding parameters fixed
            logger.error("Gaussian fit failed at %f, %f", x, y)
            return None

        try:
            assert(abs(measurement['xbar']) < boxsize)
            assert(abs(measurement['ybar']) < boxsize)
        except AssertionError:
            logger.warn('Fit falls outside of box.')

        measurement['xbar'] += x-boxsize/2.0
        measurement['ybar'] += y-boxsize/2.0
        measurement.sig = (fitme / self.rmsmap[chunk]).max()

        return extract.Detection(measurement, self)
Example #4
0
    def fit_to_point(self, x, y, boxsize, threshold, fixed):
        """Fit an elliptical Gaussian to a specified point on the image.

        The fit is carried on a square section of the image, of length
        *boxsize* & centred at pixel coordinates *x*, *y*. Any data
        below *threshold* * rmsmap is not used for fitting. If *fixed*
        is set to ``position``, then the pixel coordinates are fixed
        in the fit.

        Returns an instance of :class:`tkp.sourcefinder.extract.Detection`.
        """

        logger.debug("Force-fitting pixel location ({},{})".format(x, y))
        # First, check that x and y are actually valid semi-positive integers.
        # Otherwise,
        # If they are too high (positive), then indexing will fail
        # BUT, if they are negative, then we get wrap-around indexing
        # and the fit continues at the wrong position!
        if (x < 0 or x >self.xdim
            or y < 0 or y >self.ydim ):
            logger.warning("Dropping forced fit at ({},{}), "
                           "pixel position outside image".format(x,y)
            )
            return None

        # Next, check if any of the central pixels (in a 3x3 box about the
        # fitted pixel position) have been Masked
        # (e.g. if NaNs, or close to image edge) - reject if so.
        central_pixels_slice = ImageData.box_slice_about_pixel(x, y, 1)
        if self.data.mask[central_pixels_slice].any():
            logger.warning(
                "Dropping forced fit at ({},{}), "
                   "Masked pixel in central fitting region".format(x,y))
            return None

        if ((
                # Recent NumPy
                hasattr(numpy.ma.core, "MaskedConstant") and
                isinstance(self.rmsmap, numpy.ma.core.MaskedConstant)
            ) or (
                # Old NumPy
                numpy.ma.is_masked(self.rmsmap[int(x), int(y)])
        )):
            logger.error("Background is masked: cannot fit")
            return None

        chunk = ImageData.box_slice_about_pixel(x, y, boxsize/2.0)
        if threshold is not None:
            # We'll mask out anything below threshold*self.rmsmap from the fit.
            labels, num = self.labels.setdefault( #Dictionary mapping threshold -> islands map
                threshold,
                ndimage.label(
                    self.clip.setdefault( #Dictionary mapping threshold -> mask
                        threshold,
                        numpy.where(
                            self.data_bgsubbed > threshold * self.rmsmap, 1, 0
                            )
                        )
                    )
                )

            mylabel = labels[int(x), int(y)]
            if mylabel == 0:  # 'Background'
                raise ValueError("Fit region is below specified threshold, fit aborted.")
            mask = numpy.where(labels[chunk] == mylabel, 0, 1)
            fitme = numpy.ma.array(self.data_bgsubbed[chunk], mask=mask)
            if len(fitme.compressed()) < 1:
                raise IndexError("Fit region too close to edge or too small")
        else:
            fitme = self.data_bgsubbed[chunk]
            if fitme.size < 1:
                raise IndexError("Fit region too close to edge or too small")

        if not len(fitme.compressed()):
            logger.error("All data is masked: cannot fit")
            return None

        # set argument for fixed parameters based on input string
        if fixed == 'position':
            fixed = {'xbar': boxsize/2.0, 'ybar': boxsize/2.0}
        elif fixed == 'position+shape':
            fixed = {'xbar': boxsize/2.0, 'ybar': boxsize/2.0,
                     'semimajor': self.beam[0],
                     'semiminor': self.beam[1],
                     'theta': self.beam[2]}
        elif fixed == None:
            fixed = {}
        else:
            raise TypeError("Unkown fixed parameter")

        if threshold is not None:
            threshold_at_pixel = threshold * self.rmsmap[int(x), int(y)]
        else:
            threshold_at_pixel = None

        try:
            measurement, residuals = extract.source_profile_and_errors(
                fitme,
                threshold_at_pixel,
                self.rmsmap[int(x), int(y)],
                self.beam,
                fixed=fixed
            )
        except ValueError:
            # Fit failed to converge
            # Moments are not applicable when holding parameters fixed
            logger.error("Gaussian fit failed at %f, %f", x, y)
            return None

        try:
            assert(abs(measurement['xbar']) < boxsize)
            assert(abs(measurement['ybar']) < boxsize)
        except AssertionError:
            logger.warn('Fit falls outside of box.')

        measurement['xbar'] += x-boxsize/2.0
        measurement['ybar'] += y-boxsize/2.0
        measurement.sig = (fitme / self.rmsmap[chunk]).max()

        return extract.Detection(measurement, self)
Example #5
0
    def fit_to_point(self, x, y, boxsize, threshold, fixed):
        """Fit an elliptical Gaussian to a specified point on the image.

        The fit is carried on a square section of the image, of length
        *boxsize* & centred at pixel coordinates *x*, *y*. Any data
        below *threshold* * rmsmap is not used for fitting. If *fixed*
        is set to ``position``, then the pixel coordinates are fixed
        in the fit.

        Returns an instance of :class:`tkp.sourcefinder.extract.Detection`.
        """
        if ((
                # Recent NumPy
                hasattr(numpy.ma.core, "MaskedConstant")
                and isinstance(self.rmsmap, numpy.ma.core.MaskedConstant)) or (
                    # Old NumPy
                    numpy.ma.is_masked(self.rmsmap[x, y]))):
            logger.error("Background is masked: cannot fit")
            return None

        chunk = ImageData.box_slice_about_pixel(x, y, boxsize / 2.0)
        if threshold is not None:
            # We'll mask out anything below threshold*self.rmsmap from the fit.
            labels, num = self.labels.setdefault(  #Dictionary mapping threshold -> islands map
                threshold,
                ndimage.label(
                    self.clip.
                    setdefault(  #Dictionary mapping threshold -> mask
                        threshold,
                        numpy.where(
                            self.data_bgsubbed > threshold * self.rmsmap, 1,
                            0))))

            mylabel = labels[x, y]
            if mylabel == 0:  # 'Background'
                raise ValueError(
                    "Fit region is below specified threshold, fit aborted.")
            mask = numpy.where(labels[chunk] == mylabel, 0, 1)
            fitme = numpy.ma.array(self.data_bgsubbed[chunk], mask=mask)
            if len(fitme.compressed()) < 1:
                raise IndexError("Fit region too close to edge or too small")
        else:
            fitme = self.data_bgsubbed[chunk]
            if fitme.size < 1:
                raise IndexError("Fit region too close to edge or too small")

        if not len(fitme.compressed()):
            logger.error("All data is masked: cannot fit")
            return None

        # set argument for fixed parameters based on input string
        if fixed == 'position':
            fixed = {'xbar': boxsize / 2.0, 'ybar': boxsize / 2.0}
        elif fixed == 'position+shape':
            fixed = {
                'xbar': boxsize / 2.0,
                'ybar': boxsize / 2.0,
                'semimajor': self.beam[0],
                'semiminor': self.beam[1],
                'theta': self.beam[2]
            }
        elif fixed == None:
            fixed = {}
        else:
            raise TypeError("Unkown fixed parameter")

        if threshold is not None:
            threshold_at_pixel = threshold * self.rmsmap[x, y]
        else:
            threshold_at_pixel = None

        try:
            measurement, residuals = extract.source_profile_and_errors(
                fitme,
                threshold_at_pixel,
                self.rmsmap[x, y],
                self.beam,
                fixed=fixed)
        except ValueError:
            # Fit failed to converge
            # Moments are not applicable when holding parameters fixed
            logger.error("Gaussian fit failed at %f, %f", x, y)
            return None

        try:
            assert (abs(measurement['xbar']) < boxsize)
            assert (abs(measurement['ybar']) < boxsize)
        except AssertionError:
            logger.warn('Fit falls outside of box.')

        measurement['xbar'] += x - boxsize / 2.0
        measurement['ybar'] += y - boxsize / 2.0
        measurement.sig = (fitme / self.rmsmap[chunk]).max()

        return extract.Detection(measurement, self)
Example #6
0
    def fit_to_point(self, x, y, boxsize, threshold, fixed):
        """Fit an elliptical Gaussian to a specified point on the image.

        The fit is carried on a square section of the image, of length
        *boxsize* & centred at pixel coordinates *x*, *y*. Any data
        below *threshold* * rmsmap is not used for fitting. If *fixed*
        is set to ``position``, then the pixel coordinates are fixed
        in the fit.

        Returns an instance of :class:`tkp.sourcefinder.extract.Detection`.
        """

        logger.debug("Force-fitting pixel location ({},{})".format(x, y))
        # First, check that x and y are actually valid semi-positive integers.
        # Otherwise,
        # If they are too high (positive), then indexing will fail
        # BUT, if they are negative, then we get wrap-around indexing
        # and the fit continues at the wrong position!
        if (x < 0 or x > self.xdim or y < 0 or y > self.ydim):
            logger.warning("Dropping forced fit at ({},{}), "
                           "pixel position outside image".format(x, y))
            return None

        # Next, check if any of the central pixels (in a 3x3 box about the
        # fitted pixel position) have been Masked
        # (e.g. if NaNs, or close to image edge) - reject if so.
        central_pixels_slice = ImageData.box_slice_about_pixel(x, y, 1)
        if self.data.mask[central_pixels_slice].any():
            logger.warning("Dropping forced fit at ({},{}), "
                           "Masked pixel in central fitting region".format(
                               x, y))
            return None

        if ((
                # Recent NumPy
                hasattr(numpy.ma.core, "MaskedConstant")
                and isinstance(self.rmsmap, numpy.ma.core.MaskedConstant)) or (
                    # Old NumPy
                    numpy.ma.is_masked(self.rmsmap[int(x), int(y)]))):
            logger.error("Background is masked: cannot fit")
            return None

        chunk = ImageData.box_slice_about_pixel(x, y, boxsize / 2.0)
        if threshold is not None:
            # We'll mask out anything below threshold*self.rmsmap from the fit.
            labels, num = self.labels.setdefault(  #Dictionary mapping threshold -> islands map
                threshold,
                ndimage.label(
                    self.clip.
                    setdefault(  #Dictionary mapping threshold -> mask
                        threshold,
                        numpy.where(
                            self.data_bgsubbed > threshold * self.rmsmap, 1,
                            0))))

            mylabel = labels[int(x), int(y)]
            if mylabel == 0:  # 'Background'
                raise ValueError(
                    "Fit region is below specified threshold, fit aborted.")
            mask = numpy.where(labels[chunk] == mylabel, 0, 1)
            fitme = numpy.ma.array(self.data_bgsubbed[chunk], mask=mask)
            if len(fitme.compressed()) < 1:
                raise IndexError("Fit region too close to edge or too small")
        else:
            fitme = self.data_bgsubbed[chunk]
            if fitme.size < 1:
                raise IndexError("Fit region too close to edge or too small")

        if not len(fitme.compressed()):
            logger.error("All data is masked: cannot fit")
            return None

        # set argument for fixed parameters based on input string
        if fixed == 'position':
            fixed = {'xbar': boxsize / 2.0, 'ybar': boxsize / 2.0}
        elif fixed == 'position+shape':
            fixed = {
                'xbar': boxsize / 2.0,
                'ybar': boxsize / 2.0,
                'semimajor': self.beam[0],
                'semiminor': self.beam[1],
                'theta': self.beam[2]
            }
        elif fixed == None:
            fixed = {}
        else:
            raise TypeError("Unkown fixed parameter")

        if threshold is not None:
            threshold_at_pixel = threshold * self.rmsmap[int(x), int(y)]
        else:
            threshold_at_pixel = None

        try:
            measurement, residuals = extract.source_profile_and_errors(
                fitme,
                threshold_at_pixel,
                self.rmsmap[int(x), int(y)],
                self.beam,
                fixed=fixed)
        except ValueError:
            # Fit failed to converge
            # Moments are not applicable when holding parameters fixed
            logger.error("Gaussian fit failed at %f, %f", x, y)
            return None

        try:
            assert (abs(measurement['xbar']) < boxsize)
            assert (abs(measurement['ybar']) < boxsize)
        except AssertionError:
            logger.warn('Fit falls outside of box.')

        measurement['xbar'] += x - boxsize / 2.0
        measurement['ybar'] += y - boxsize / 2.0
        measurement.sig = (fitme / self.rmsmap[chunk]).max()

        return extract.Detection(measurement, self)