Esempio n. 1
0
        def belongs(self, img, isl):
            import functions as func
                                                # get centroid of island (as integer)
            mom = func.momanalmask_gaus(isl.image, isl.mask_active, 0, 1.0, False)
            cen = N.array(mom[1:3]) + isl.origin
            icen = (int(round(cen[0])), int(round(cen[1])))
            belong = False
                                                # check if lies within any island of self
            for i, pyrisl in enumerate(self.islands):
              if N.sum([pyrisl.bbox[j].start <= cen[j] < pyrisl.bbox[j].stop for j in range(2)]) == 2:
                pix = tuple([cen[j] - pyrisl.origin[j] for j in range(2)])
                if not pyrisl.mask_active[pix]:
                  belong = True

            return belong
Esempio n. 2
0
    def inigaus_nobeam(self, isl, thr, beam, img):
        """ To get initial guesses when the source sizes are very different
        from the beam, and can also be elongated. Mainly in the context of
        a-trous transform images. Need to arrive at a good guess of the sizes
        and hence need to partition the image around the maxima first. Tried the
        IFT watershed algo but with markers, it segments the island only around
        the minima and not the whole island. Cant find a good weighting scheme
        for tesselation either. Hence will try this :

        Calculate number of maxima. If one, then take moment as initial
        guess. If more than one, then moment of whole island is one of the
        guesses if mom1 is within n pixels of one of the maxima. Else dont take
        whole island moment. Instead, find minima on lines connecting all maxima
        and use geometric mean of all minima of a peak as the size of that peak.
        """
        from math import sqrt
        from const import fwsig
        import scipy.ndimage as nd
        import functions as func

        im = isl.image-isl.islmean
        if img.opts.ini_method == 'curvature':
            im_pos = -1.0 * func.make_curvature_map(isl.image-isl.islmean)
            thr_pos = 0.0
        else:
            im_pos = im
            thr_pos = -1e9
        mask = isl.mask_active
        av = img.clipped_mean
        inipeak, iniposn, im1 = func.get_maxima(im, mask, thr_pos, isl.shape, beam, im_pos=im_pos)
        npeak = len(iniposn)
        gaul = []

        av, stdnew, maxv, maxp, minv, minp = func.arrstatmask(im, mask)
        mom = func.momanalmask_gaus(isl.image-isl.islmean, isl.mask_active, 0, 1.0, True)
        if npeak <= 1:
          g = (float(maxv), int(round(mom[1])), int(round(mom[2])), mom[3]/fwsig, \
                                  mom[4]/fwsig, mom[5])
          gaul.append(g)

        if npeak > 1:                   # markers start from 1=background, watershed starts from 1=background
          watershed, markers = func.watershed(im, mask=isl.mask_active)
          nshed = N.max(markers)-1      # excluding background
          xm, ym = N.transpose([N.where(markers==i) for i in range(1,nshed+2)])[0]
          coords = [c for c in N.transpose([xm,ym])[1:]]
          alldists = [func.dist_2pt(c1, c2) for c1 in coords for c2 in coords if N.any(c1!=c2)]  # has double
          meandist = N.mean(alldists)    # mean dist between all pairs of markers
          compact = []; invmask = []
          for ished in range(nshed):
            shedmask = N.where(watershed==ished+2, False, True) + isl.mask_active # good unmasked pixels = 0
            imm = nd.binary_dilation(~shedmask, N.ones((3,3), int))
            xbad, ybad = N.where((imm==1)*(im>im[xm[ished+1], ym[ished+1]]))
            imm[xbad, ybad] = 0
            invmask.append(imm); x, y = N.where(imm); xcen, ycen = N.mean(x), N.mean(y) # good pixels are now = 1
            dist = func.dist_2pt([xcen, ycen], [xm[ished+1], ym[ished+1]])
            if dist < max(3.0, meandist/4.0):
              compact.append(True)  # if not compact, break source + diffuse
            else:
              compact.append(False)
          if not N.all(compact):
           avsize = []
           ind = N.where(compact)[0]
           for i in ind: avsize.append(N.sum(invmask[i]))
           avsize = sqrt(N.mean(N.array(avsize)))
           for i in range(len(compact)):
             if not compact[i]:                         # make them all compact
               newmask = N.zeros(imm.shape, bool)
               newmask[max(0,xm[i+1]-avsize/2):min(im.shape[0],xm[i+1]+avsize/2), \
                       max(0,ym[i+1]-avsize/2):min(im.shape[1],ym[i+1]+avsize/2)] = True
               invmask[i] = invmask[i]*newmask
          resid = N.zeros(im.shape, dtype=N.float32)                    # approx fit all compact ones
          for i in range(nshed):
            mask1 = ~invmask[i]
            size = sqrt(N.sum(invmask))/fwsig
            xf, yf = coords[i][0], coords[i][1]
            p_ini = [im[xf, yf], xf, yf, size, size, 0.0]
            x, y = N.indices(im.shape)
            p, success = func.fit_gaus2d(im*invmask[i], p_ini, x, y)
            resid = resid + func.gaus_2d(p, x, y)
            gaul.append(p)
          resid = im - resid
          if not N.all(compact):                        # just add one gaussian to fit whole unmasked island
            maxv = N.max(resid)                         # assuming resid has only diffuse emission. can be false
            x, y = N.where(~isl.mask_active); xcen = N.mean(x); ycen = N.mean(y)
            invm = ~isl.mask_active
            #bound = invm - nd.grey_erosion(invm, footprint = N.ones((3,3), int)) # better to use bound for ellipse fitting
            mom = func.momanalmask_gaus(invm, N.zeros(invm.shape, dtype=N.int16), 0, 1.0, True)
            g = (maxv, xcen, ycen, mom[3]/fwsig, mom[4]/fwsig, mom[5]-90.)
            gaul.append(g)
            coords.append([xcen, ycen])

        return gaul
Esempio n. 3
0
    def fit_island(self, isl, opts, img, ngmax=None, ffimg=None, ini_gausfit=None):
        """Fit island with a set of 2D gaussians.

        Parameters:
        isl: island
        opts: Opts structure of the image
        beam: beam parameters which are used as an initial guess for
              gaussian shape

        Returns:
        Function returns 2 lists with parameters of good and flagged
        gaussians. Gaussian parameters are updated to be image-relative.

        Note: "fitok" indicates whether fit converged
               and one or more flagged Gaussians indicate
               that significant residuals remain (peak > thr).
        """
        from _cbdsm import MGFunction
        import functions as func
        from const import fwsig

        if ffimg == None:
            fit_image = isl.image-isl.islmean
        else:
            fit_image = isl.image-isl.islmean-ffimg
        fcn = MGFunction(fit_image, isl.mask_active, 1)
        # For fitting, use img.beam instead of img.pixel_beam, as we want
        # to pick up the wavelet beam (img.pixel_beam is not changed for
        # wavelet images, but img.beam is)
        beam = N.array(img.beam2pix(img.beam))
        beam = (beam[0]/fwsig, beam[1]/fwsig, beam[2]+90.0) # change angle from +y-axis to +x-axis and FWHM to sigma

        if abs(beam[0]/beam[1]) < 1.1:
            beam = (1.1*beam[0], beam[1], beam[2])

        thr1 = isl.mean + opts.thresh_isl*isl.rms
        thr2 = isl.mean + img.thresh_pix*isl.rms
        thr0 = thr1
        verbose = opts.verbose_fitting
        g3_only = opts.fix_to_beam
        peak = fcn.find_peak()[0]
        dof = isl.size_active
        shape = isl.shape
        isl_image = isl.image - isl.islmean
        size = isl.size_active/img.pixel_beamarea()*2.0
        gaul = []
        iter = 0
        ng1 = 0
        if ini_gausfit == None:
            ini_gausfit = opts.ini_gausfit

        if ini_gausfit not in ['default', 'simple', 'nobeam']:
            ini_gausfit = 'default'
        if ini_gausfit == 'simple' and ngmax == None:
          ngmax = 25
        if ini_gausfit == 'default' or opts.fix_to_beam:
          gaul, ng1, ngmax = self.inigaus_fbdsm(isl, thr0, beam, img)
        if ini_gausfit == 'nobeam' and not opts.fix_to_beam:
          gaul = self.inigaus_nobeam(isl, thr0, beam, img)
          ng1 = len(gaul); ngmax = ng1+2
        while iter < 5:
            iter += 1
            fitok = self.fit_iter(gaul, ng1, fcn, dof, beam, thr0, iter, ini_gausfit, ngmax, verbose, g3_only)
            gaul, fgaul = self.flag_gaussians(fcn.parameters, opts,
                                              beam, thr0, peak, shape, isl.mask_active,
                                              isl.image, size)
            ng1 = len(gaul)
            if fitok and len(fgaul) == 0:
                break
        if (not fitok or len(gaul) == 0) and ini_gausfit != 'simple':
            # If fits using default or nobeam methods did not work,
            # try using simple instead
            gaul = []
            iter = 0
            ng1 = 0
            ngmax = 25
            while iter < 5:
               iter += 1
               fitok = self.fit_iter(gaul, ng1, fcn, dof, beam, thr0, iter, 'simple', ngmax, verbose, g3_only)
               gaul, fgaul = self.flag_gaussians(fcn.parameters, opts,
                                                 beam, thr0, peak, shape, isl.mask_active,
                                                 isl.image, size)
               ng1 = len(gaul)
               if fitok and len(fgaul) == 0:
                   break
        sm_isl = nd.binary_dilation(isl.mask_active)
        if (not fitok or len(gaul) == 0) and N.sum(~sm_isl) >= img.minpix_isl:
            # If fitting still fails, shrink the island a little and try again
            fcn = MGFunction(fit_image, nd.binary_dilation(isl.mask_active), 1)
            gaul = []
            iter = 0
            ng1 = 0
            ngmax = 25
            while iter < 5:
               iter += 1
               fitok = self.fit_iter(gaul, ng1, fcn, dof, beam, thr0, iter, 'simple', ngmax, verbose, g3_only)
               gaul, fgaul = self.flag_gaussians(fcn.parameters, opts,
                                                 beam, thr0, peak, shape, isl.mask_active,
                                                 isl.image, size)
               ng1 = len(gaul)
               if fitok and len(fgaul) == 0:
                   break
        lg_isl = nd.binary_erosion(isl.mask_active)
        if (not fitok or len(gaul) == 0) and N.sum(~lg_isl) >= img.minpix_isl:
            # If fitting still fails, expand the island a little and try again
            fcn = MGFunction(fit_image, nd.binary_erosion(isl.mask_active), 1)
            gaul = []
            iter = 0
            ng1 = 0
            ngmax = 25
            while iter < 5:
               iter += 1
               fitok = self.fit_iter(gaul, ng1, fcn, dof, beam, thr0, iter, 'simple', ngmax, verbose, g3_only)
               gaul, fgaul = self.flag_gaussians(fcn.parameters, opts,
                                                 beam, thr0, peak, shape, isl.mask_active,
                                                 isl.image, size)
               ng1 = len(gaul)
               if fitok and len(fgaul) == 0:
                   break

        if not fitok or len(gaul) == 0:
            # If all else fails, try to use moment analysis
            inisl = N.where(~isl.mask_active)
            mask_id = N.zeros(isl.image.shape, dtype=N.int32) - 1
            mask_id[inisl] = isl.island_id
            try:
                pixel_beamarea = img.pixel_beamarea()
                mompara = func.momanalmask_gaus(fit_image, mask_id, isl.island_id, pixel_beamarea, True)
                mompara[5] += 90.0
                if not N.isnan(mompara[1]) and not N.isnan(mompara[2]):
                    x1 = N.int(N.floor(mompara[1]))
                    y1 = N.int(N.floor(mompara[2]))
                    xind = slice(x1, x1+2, 1); yind = slice(y1, y1+2, 1)
                    t=(mompara[1]-x1)/(x1+1-x1)
                    u=(mompara[2]-y1)/(y1+1-y1)
                    s_peak=(1.0-t)*(1.0-u)*fit_image[x1,y1]+t*(1.0-u)*fit_image[x1+1,y1]+ \
                         t*u*fit_image[x1+1,y1+1]+(1.0-t)*u*fit_image[x1,y1+1]
                    mompara[0] = s_peak
                    par = [mompara.tolist()]
                    par[3] /= fwsig
                    par[4] /= fwsig
                    gaul, fgaul = self.flag_gaussians(par, opts,
                                                      beam, thr0, peak, shape, isl.mask_active,
                                                      isl.image, size)
            except:
                pass

        ### return whatever we got
        isl.mg_fcn = fcn
        gaul  = [self.fixup_gaussian(isl, g) for g in gaul]
        fgaul = [(flag, self.fixup_gaussian(isl, g))
                                       for flag, g in fgaul]

        if verbose:
            print 'Number of good Gaussians: %i' % (len(gaul),)
            print 'Number of flagged Gaussians: %i' % (len(fgaul),)
        return gaul, fgaul
Esempio n. 4
0
    def process_Multiple(self, img, g_sublist, mask, src_index, isrc, subim,
                         isl, delc, subn, subm):
        """ Same as gaul_to_source.f. isrc is same as k in the fortran version. """
        from math import pi, sqrt
        from const import fwsig
        from scipy import ndimage
        import functions as func

        mylog = mylogger.logging.getLogger("PyBDSM." + img.log + "Gaul2Srl  ")
        dum = img.beam[0] * img.beam[1]
        cdeltsq = img.wcs_obj.acdelt[0] * img.wcs_obj.acdelt[1]
        bmar_p = 2.0 * pi * dum / (cdeltsq * fwsig * fwsig)

        # try
        subim_src = self.make_subim(subn, subm, g_sublist, delc)
        mompara = func.momanalmask_gaus(subim_src, mask, isrc, bmar_p, True)
        # initial peak posn and value
        maxv = N.max(subim_src)
        maxx, maxy = N.unravel_index(N.argmax(subim_src), subim_src.shape)
        # fit gaussian around this posn
        blc = N.zeros(2)
        trc = N.zeros(2)
        n, m = subim_src.shape[0:2]
        bm_pix = N.array([
            img.pixel_beam()[0] * fwsig,
            img.pixel_beam()[1] * fwsig,
            img.pixel_beam()[2]
        ])
        ssubimsize = max(N.int(N.round(N.max(bm_pix[0:2]) * 2)) + 1, 5)
        blc[0] = max(0, maxx - (ssubimsize - 1) / 2)
        blc[1] = max(0, maxy - (ssubimsize - 1) / 2)
        trc[0] = min(n, maxx + (ssubimsize - 1) / 2)
        trc[1] = min(m, maxy + (ssubimsize - 1) / 2)
        s_imsize = trc - blc + 1

        p_ini = [maxv, (s_imsize[0]-1)/2.0*1.1, (s_imsize[1]-1)/2.0*1.1, bm_pix[0]/fwsig*1.3, \
                 bm_pix[1]/fwsig*1.1, bm_pix[2]*2]
        data = subim_src[blc[0]:blc[0] + s_imsize[0],
                         blc[1]:blc[1] + s_imsize[1]]
        smask = mask[blc[0]:blc[0] + s_imsize[0], blc[1]:blc[1] + s_imsize[1]]
        rmask = N.where(smask == isrc, False, True)
        x_ax, y_ax = N.indices(data.shape)

        if N.sum(~rmask) >= 6:
            para, ierr = func.fit_gaus2d(data, p_ini, x_ax, y_ax, rmask)
            if (0.0<para[1]<s_imsize[0]) and (0.0<para[2]<s_imsize[1]) and \
              para[3]<s_imsize[0] and para[4]<s_imsize[1]:
                maxpeak = para[0]
            else:
                maxpeak = maxv
            posn = para[1:3] - (0.5 * N.sum(s_imsize) - 1) / 2.0 + N.array(
                [maxx, maxy]) - 1 + delc
        else:
            maxpeak = maxv
            posn = N.unravel_index(N.argmax(data * ~rmask),
                                   data.shape) + N.array(delc) + blc

        # calculate peak by bilinear interpolation around centroid
        # First check that moment analysis gave a valid position. If not, use
        # posn from gaussian fit instead.
        if N.isnan(mompara[1]):
            mompara[1] = posn[0] - delc[0]
        x1 = N.int(N.floor(mompara[1]))
        if N.isnan(mompara[2]):
            mompara[2] = posn[1] - delc[1]
        y1 = N.int(N.floor(mompara[2]))
        xind = slice(x1, x1 + 2, 1)
        yind = slice(y1, y1 + 2, 1)
        if img.opts.flag_smallsrc and (
                N.sum(mask[xind, yind] == N.ones((2, 2)) * isrc) != 4):
            mylog.debug('Island = ' + str(isl.island_id))
            mylog.debug('Mask = ' + repr(mask[xind, yind]) +
                        'xind, yind, x1, y1 = ' + repr(xind) + ' ' +
                        repr(yind) + ' ' + repr(x1) + ' ' + repr(y1))
        t = (mompara[1] - x1) / (x1 + 1 - x1)  # in case u change it later
        u = (mompara[2] - y1) / (y1 + 1 - y1)
        s_peak=(1.0-t)*(1.0-u)*subim_src[x1,y1]+t*(1.0-u)*subim_src[x1+1,y1]+ \
               t*u*subim_src[x1+1,y1+1]+(1.0-t)*u*subim_src[x1,y1+1]
        if (not img.opts.flag_smallsrc) and (
                N.sum(mask[xind, yind] == N.ones((2, 2)) * isrc) != 4):
            mylog.debug('Speak ' + repr(s_peak) + 'Mompara = ' + repr(mompara))
            mylog.debug('x1, y1 : ' + repr(x1) + ', ' + repr(y1))
            # import pylab as pl
            # pl.imshow(N.transpose(subim_src), origin='lower', interpolation='nearest')
            # pl.suptitle('Image of bad M source '+str(isl.island_id))
            # convert pixels to coords
        try:
            sra, sdec = img.pix2sky(
                [mompara[1] + delc[0], mompara[2] + delc[1]])
            mra, mdec = img.pix2sky(posn)
        except RuntimeError, err:
            # Invalid pixel wcs coordinate
            sra, sdec = 0.0, 0.0
            mra, mdec = 0.0, 0.0
Esempio n. 5
0
class Op_gaul2srl(Op):
    """
    Slightly modified from fortran.
    """
    def __call__(self, img):
        #  for each island, get the gaussians into a list and then send them to process
        #  src_index is source number, starting from 0
        mylog = mylogger.logging.getLogger("PyBDSM." + img.log + "Gaul2Srl")
        mylogger.userinfo(mylog, 'Grouping Gaussians into sources')
        img.aperture = img.opts.aperture
        if img.aperture is not None and img.aperture <= 0.0:
            mylog.warn('Specified aperture is <= 0. Skipping aperture fluxes.')
            img.aperture = None

        src_index = -1
        dsrc_index = 0
        sources = []
        dsources = []
        no_gaus_islands = []
        for iisl, isl in enumerate(img.islands):
            isl_sources = []
            isl_dsources = []
            g_list = []
            for g in isl.gaul:
                if g.flag == 0:
                    g_list.append(g)

            if len(g_list) > 0:
                if len(g_list) == 1:
                    src_index, source = self.process_single_gaussian(img,
                                                                     g_list,
                                                                     src_index,
                                                                     code='S')
                    sources.append(source)
                    isl_sources.append(source)
                else:
                    src_index, source = self.process_CM(
                        img, g_list, isl, src_index)
                    sources.extend(source)
                    isl_sources.extend(source)
            else:
                if not img.waveletimage:
                    dg = isl.dgaul[0]
                    no_gaus_islands.append(
                        (isl.island_id, dg.centre_pix[0], dg.centre_pix[1]))
                    # Put in the dummy Source as the source and use negative IDs
                    g_list = isl.dgaul
                    dsrc_index, dsource = self.process_single_gaussian(
                        img, g_list, dsrc_index, code='S')
                    dsources.append(dsource)
                    isl_dsources.append(dsource)

            isl.sources = isl_sources
            isl.dsources = isl_dsources
        img.sources = sources
        img.dsources = dsources
        img.nsrc = src_index + 1
        mylogger.userinfo(mylog, "Number of sources formed from Gaussians",
                          str(img.nsrc))
        if not img.waveletimage and not img._pi and len(
                no_gaus_islands) > 0 and not img.opts.quiet:
            message = 'All Gaussians were flagged for the following island'
            if len(no_gaus_islands) == 1:
                message += ':\n'
            else:
                message += 's:\n'
            for isl_id in no_gaus_islands:
                message += '    Island #%i (x=%i, y=%i)\n' % isl_id
            if len(no_gaus_islands) == 1:
                message += 'Please check this island. If it is a valid island and\n'
            else:
                message += 'Please check these islands. If they are valid islands and\n'
            if img.opts.atrous_do:
                message += 'should be fit, try adjusting the flagging options (use\n'\
                           'show_fit with "ch0_flagged=True" to see the flagged Gaussians).'
            else:
                message += 'should be fit, try adjusting the flagging options (use\n'\
                           'show_fit with "ch0_flagged=True" to see the flagged Gaussians)\n'\
                           'or enabling the wavelet module (with "atrous_do=True").'
            message += '\nTo include empty islands in output source catalogs, set\n'\
                        'incl_empty=True in the write_catalog task.'
            mylog.warning(message)

        img.completed_Ops.append('gaul2srl')

#################################################################################################

    def process_single_gaussian(self, img, g_list, src_index, code):
        """ Process single gaussian into a source, for both S and C type sources. g is just one
            Gaussian object (not a list)."""

        g = g_list[0]

        total_flux = [g.total_flux, g.total_fluxE]
        peak_flux_centroid = peak_flux_max = [g.peak_flux, g.peak_fluxE]
        posn_sky_centroid = posn_sky_max = [g.centre_sky, g.centre_skyE]
        size_sky = [g.size_sky, g.size_skyE]
        size_sky_uncorr = [g.size_sky_uncorr, g.size_skyE]
        deconv_size_sky = [g.deconv_size_sky, g.deconv_size_skyE]
        deconv_size_sky_uncorr = [g.deconv_size_sky_uncorr, g.deconv_size_skyE]
        bbox = img.islands[g.island_id].bbox
        ngaus = 1
        island_id = g.island_id
        if g.gaus_num < 0:
            gaussians = []
        else:
            gaussians = list([g])
        aper_flux = func.ch0_aperture_flux(img, g.centre_pix, img.aperture)

        source_prop = list([code, total_flux, peak_flux_centroid, peak_flux_max, aper_flux, posn_sky_centroid, \
             posn_sky_max, size_sky, size_sky_uncorr, deconv_size_sky, deconv_size_sky_uncorr, bbox, ngaus, island_id, gaussians])
        source = Source(img, source_prop)

        if g.gaussian_idx == -1:
            src_index -= 1
        else:
            src_index += 1
        g.source_id = src_index
        g.code = code
        source.source_id = src_index

        return src_index, source

##################################################################################################

    def process_CM(self, img, g_list, isl, src_index):
        """
        Bundle errors with the quantities.
        ngau = number of gaussians in island
        src_id = the source index array for every gaussian in island
        nsrc = final number of distinct sources in the island
        """

        ngau = len(g_list)  # same as cisl in callgaul2srl.f
        nsrc = ngau  # same as islct; initially make each gaussian as a source
        src_id = N.arange(nsrc)  # same as islnum in callgaul2srl.f

        boxx, boxy = isl.bbox
        subn = boxx.stop - boxx.start
        subm = boxy.stop - boxy.start
        delc = [boxx.start, boxy.start]
        subim = self.make_subim(subn, subm, g_list, delc)

        index = [(i, j) for i in range(ngau) for j in range(ngau) if j > i]
        for pair in index:
            same_island = self.in_same_island(pair, img, g_list, isl, subim,
                                              subn, subm, delc)
            if same_island:
                nsrc -= 1
                mmax, mmin = max(src_id[pair[0]],
                                 src_id[pair[1]]), min(src_id[pair[0]],
                                                       src_id[pair[1]])
                arr = N.where(src_id == mmax)[0]
                src_id[arr] = mmin
                # now reorder src_id so that it is contiguous
        for i in range(ngau):
            ind1 = N.where(src_id == i)[0]
            if len(ind1) == 0:
                arr = N.where(src_id > i)[0]
                if len(arr) > 0:
                    decr = N.min(src_id[arr]) - i
                    for j in arr:
                        src_id[j] -= decr
        nsrc = N.max(src_id) + 1
        # now do whats in sub_calc_para_source

        source_list = []
        for isrc in range(nsrc):
            posn = N.where(src_id == isrc)[0]
            g_sublist = []
            for i in posn:
                g_sublist.append(g_list[i])
            ngau_insrc = len(posn)
            # Do source type C
            if ngau_insrc == 1:
                src_index, source = self.process_single_gaussian(img,
                                                                 g_sublist,
                                                                 src_index,
                                                                 code='C')
            else:
                # make mask and subim. Invalid mask value is -1 since 0 is valid srcid
                mask = self.make_mask(isl, subn, subm, 1, isrc, g_sublist,
                                      delc)
                src_index, source = self.process_Multiple(img, g_sublist, mask, src_index, isrc, subim, \
                                    isl, delc, subn, subm)
            source_list.append(source)

        return src_index, source_list

##################################################################################################

    def in_same_island(self, pair, img, g_list, isl, subim, subn, subm, delc):
        """ Whether two gaussians belong to the same source or not. """
        import functions as func

        def same_island_min(pair, g_list, subim, delc, tol=0.5):
            """ If the minimum of the reconstructed fluxes along the line joining the peak positions
                is greater than thresh_isl times the rms_clip, they belong to different islands. """

            g1 = g_list[pair[0]]
            g2 = g_list[pair[1]]
            pix1 = N.array(g1.centre_pix)
            pix2 = N.array(g2.centre_pix)

            x1, y1 = N.floor(pix1) - delc
            x2, y2 = N.floor(pix2) - delc
            pix1 = N.array(
                N.unravel_index(N.argmax(subim[x1:x1 + 2, y1:y1 + 2]),
                                (2, 2))) + [x1, y1]
            pix2 = N.array(
                N.unravel_index(N.argmax(subim[x2:x2 + 2, y2:y2 + 2]),
                                (2, 2))) + [x2, y2]
            if pix1[1] >= subn: pix1[1] = pix1[1] - 1
            if pix2[1] >= subm: pix2[1] = pix2[1] - 1

            maxline = int(round(N.max(N.abs(pix1 - pix2) + 1)))
            flux1 = g1.peak_flux
            flux2 = g2.peak_flux
            # get pix values of the line
            pixdif = pix2 - pix1
            same_island_min = False
            same_island_cont = False
            if maxline == 1:
                same_island_min = True
                same_island_cont = True
            else:
                if abs(pixdif[0]) > abs(pixdif[1]):
                    xline = N.round(min(pix1[0], pix2[0]) + N.arange(maxline))
                    yline = N.round((pix1[1]-pix2[1])/(pix1[0]-pix2[0])* \
                           (min(pix1[0],pix2[0])+N.arange(maxline)-pix1[0])+pix1[1])
                else:
                    yline = N.round(min(pix1[1], pix2[1]) + N.arange(maxline))
                    xline = N.round((pix1[0]-pix2[0])/(pix1[1]-pix2[1])* \
                           (min(pix1[1],pix2[1])+N.arange(maxline)-pix1[1])+pix1[0])
                rpixval = N.zeros(maxline, dtype=N.float32)
                xbig = N.where(xline >= N.size(subim, 0))
                xline[xbig] = N.size(subim, 0) - 1
                ybig = N.where(yline >= N.size(subim, 1))
                yline[ybig] = N.size(subim, 1) - 1
                for i in range(maxline):
                    pixval = subim[xline[i], yline[i]]
                    rpixval[i] = pixval
                min_pixval = N.min(rpixval)
                minind_p = N.argmin(rpixval)
                maxind_p = N.argmax(rpixval)

                if minind_p in (0, maxline - 1) and maxind_p in (0,
                                                                 maxline - 1):
                    same_island_cont = True
                if min_pixval >= min(flux1, flux2):
                    same_island_min = True
                elif abs(min_pixval - min(flux1, flux2)
                         ) <= tol * isl.rms * img.opts.thresh_isl:
                    same_island_min = True

            return same_island_min, same_island_cont

        def same_island_dist(pair, g_list, tol=0.5):
            """ If the centres are seperated by a distance less than half the sum of their
                fwhms along the PA of the line joining them, they belong to the same island. """
            from math import sqrt

            g1 = g_list[pair[0]]
            g2 = g_list[pair[1]]
            pix1 = N.array(g1.centre_pix)
            pix2 = N.array(g2.centre_pix)
            gsize1 = g1.size_pix
            gsize2 = g2.size_pix

            fwhm1 = func.gdist_pa(pix1, pix2, gsize1)
            fwhm2 = func.gdist_pa(pix1, pix2, gsize2)
            dx = pix2[0] - pix1[0]
            dy = pix2[1] - pix1[1]
            dist = sqrt(dy * dy + dx * dx)

            if dist <= tol * (fwhm1 + fwhm2):
                same_island = True
            else:
                same_island = False

            return same_island

        if img.opts.group_by_isl:
            same_isl1_min = True
            same_isl1_cont = True
            same_isl2 = True
        else:
            if img.opts.group_method == 'curvature':
                subim = -1.0 * func.make_curvature_map(subim)
            tol = img.opts.group_tol
            same_isl1_min, same_isl1_cont = same_island_min(
                pair, g_list, subim, delc, tol)
            same_isl2 = same_island_dist(pair, g_list, tol / 2.0)

        g1 = g_list[pair[0]]

        same_island = (same_isl1_min and same_isl2) or same_isl1_cont

        return same_island

##################################################################################################

    def process_Multiple(self, img, g_sublist, mask, src_index, isrc, subim,
                         isl, delc, subn, subm):
        """ Same as gaul_to_source.f. isrc is same as k in the fortran version. """
        from math import pi, sqrt
        from const import fwsig
        from scipy import ndimage
        import functions as func

        mylog = mylogger.logging.getLogger("PyBDSM." + img.log + "Gaul2Srl  ")
        dum = img.beam[0] * img.beam[1]
        cdeltsq = img.wcs_obj.acdelt[0] * img.wcs_obj.acdelt[1]
        bmar_p = 2.0 * pi * dum / (cdeltsq * fwsig * fwsig)

        # try
        subim_src = self.make_subim(subn, subm, g_sublist, delc)
        mompara = func.momanalmask_gaus(subim_src, mask, isrc, bmar_p, True)
        # initial peak posn and value
        maxv = N.max(subim_src)
        maxx, maxy = N.unravel_index(N.argmax(subim_src), subim_src.shape)
        # fit gaussian around this posn
        blc = N.zeros(2)
        trc = N.zeros(2)
        n, m = subim_src.shape[0:2]
        bm_pix = N.array([
            img.pixel_beam()[0] * fwsig,
            img.pixel_beam()[1] * fwsig,
            img.pixel_beam()[2]
        ])
        ssubimsize = max(N.int(N.round(N.max(bm_pix[0:2]) * 2)) + 1, 5)
        blc[0] = max(0, maxx - (ssubimsize - 1) / 2)
        blc[1] = max(0, maxy - (ssubimsize - 1) / 2)
        trc[0] = min(n, maxx + (ssubimsize - 1) / 2)
        trc[1] = min(m, maxy + (ssubimsize - 1) / 2)
        s_imsize = trc - blc + 1

        p_ini = [maxv, (s_imsize[0]-1)/2.0*1.1, (s_imsize[1]-1)/2.0*1.1, bm_pix[0]/fwsig*1.3, \
                 bm_pix[1]/fwsig*1.1, bm_pix[2]*2]
        data = subim_src[blc[0]:blc[0] + s_imsize[0],
                         blc[1]:blc[1] + s_imsize[1]]
        smask = mask[blc[0]:blc[0] + s_imsize[0], blc[1]:blc[1] + s_imsize[1]]
        rmask = N.where(smask == isrc, False, True)
        x_ax, y_ax = N.indices(data.shape)

        if N.sum(~rmask) >= 6:
            para, ierr = func.fit_gaus2d(data, p_ini, x_ax, y_ax, rmask)
            if (0.0<para[1]<s_imsize[0]) and (0.0<para[2]<s_imsize[1]) and \
              para[3]<s_imsize[0] and para[4]<s_imsize[1]:
                maxpeak = para[0]
            else:
                maxpeak = maxv
            posn = para[1:3] - (0.5 * N.sum(s_imsize) - 1) / 2.0 + N.array(
                [maxx, maxy]) - 1 + delc
        else:
            maxpeak = maxv
            posn = N.unravel_index(N.argmax(data * ~rmask),
                                   data.shape) + N.array(delc) + blc

        # calculate peak by bilinear interpolation around centroid
        # First check that moment analysis gave a valid position. If not, use
        # posn from gaussian fit instead.
        if N.isnan(mompara[1]):
            mompara[1] = posn[0] - delc[0]
        x1 = N.int(N.floor(mompara[1]))
        if N.isnan(mompara[2]):
            mompara[2] = posn[1] - delc[1]
        y1 = N.int(N.floor(mompara[2]))
        xind = slice(x1, x1 + 2, 1)
        yind = slice(y1, y1 + 2, 1)
        if img.opts.flag_smallsrc and (
                N.sum(mask[xind, yind] == N.ones((2, 2)) * isrc) != 4):
            mylog.debug('Island = ' + str(isl.island_id))
            mylog.debug('Mask = ' + repr(mask[xind, yind]) +
                        'xind, yind, x1, y1 = ' + repr(xind) + ' ' +
                        repr(yind) + ' ' + repr(x1) + ' ' + repr(y1))
        t = (mompara[1] - x1) / (x1 + 1 - x1)  # in case u change it later
        u = (mompara[2] - y1) / (y1 + 1 - y1)
        s_peak=(1.0-t)*(1.0-u)*subim_src[x1,y1]+t*(1.0-u)*subim_src[x1+1,y1]+ \
               t*u*subim_src[x1+1,y1+1]+(1.0-t)*u*subim_src[x1,y1+1]
        if (not img.opts.flag_smallsrc) and (
                N.sum(mask[xind, yind] == N.ones((2, 2)) * isrc) != 4):
            mylog.debug('Speak ' + repr(s_peak) + 'Mompara = ' + repr(mompara))
            mylog.debug('x1, y1 : ' + repr(x1) + ', ' + repr(y1))
            # import pylab as pl
            # pl.imshow(N.transpose(subim_src), origin='lower', interpolation='nearest')
            # pl.suptitle('Image of bad M source '+str(isl.island_id))
            # convert pixels to coords
        try:
            sra, sdec = img.pix2sky(
                [mompara[1] + delc[0], mompara[2] + delc[1]])
            mra, mdec = img.pix2sky(posn)
        except RuntimeError, err:
            # Invalid pixel wcs coordinate
            sra, sdec = 0.0, 0.0
            mra, mdec = 0.0, 0.0

        # "deconvolve" the sizes
        gaus_c = [mompara[3], mompara[4], mompara[5]]
        gaus_bm = [bm_pix[0], bm_pix[1], bm_pix[2]]
        gaus_dc, err = func.deconv2(gaus_bm, gaus_c)
        deconv_size_sky = img.pix2gaus(
            gaus_dc, [mompara[1] + delc[0], mompara[2] + delc[1]])
        deconv_size_sky_uncorr = img.pix2gaus(
            gaus_dc, [mompara[1] + delc[0], mompara[2] + delc[1]],
            use_wcs=False)

        # update all objects etc
        tot = 0.0
        totE_sq = 0.0
        for g in g_sublist:
            tot += g.total_flux
            totE_sq += g.total_fluxE**2
        totE = sqrt(totE_sq)
        size_pix = [mompara[3], mompara[4], mompara[5]]
        size_sky = img.pix2gaus(size_pix,
                                [mompara[1] + delc[0], mompara[2] + delc[1]])
        size_sky_uncorr = img.pix2gaus(
            size_pix, [mompara[1] + delc[0], mompara[2] + delc[1]],
            use_wcs=False)

        # Estimate uncertainties in source size and position due to
        # errors in the constituent Gaussians using a Monte Carlo technique.
        # Sum with Condon (1997) errors in quadrature.
        plist = mompara.tolist() + [tot]
        plist[0] = s_peak
        plist[3] /= fwsig
        plist[4] /= fwsig
        errors = func.get_errors(img, plist, isl.rms)

        if img.opts.do_mc_errors:
            nMC = 20
            mompara0_MC = N.zeros(nMC, dtype=N.float32)
            mompara1_MC = N.zeros(nMC, dtype=N.float32)
            mompara2_MC = N.zeros(nMC, dtype=N.float32)
            mompara3_MC = N.zeros(nMC, dtype=N.float32)
            mompara4_MC = N.zeros(nMC, dtype=N.float32)
            mompara5_MC = N.zeros(nMC, dtype=N.float32)
            for i in range(nMC):
                # Reconstruct source from component Gaussians. Draw the Gaussian
                # parameters from random distributions given by their errors.
                subim_src_MC = self.make_subim(subn,
                                               subm,
                                               g_sublist,
                                               delc,
                                               mc=True)

                try:
                    mompara_MC = func.momanalmask_gaus(subim_src_MC, mask,
                                                       isrc, bmar_p, True)
                    mompara0_MC[i] = mompara_MC[0]
                    mompara1_MC[i] = mompara_MC[1]
                    mompara2_MC[i] = mompara_MC[2]
                    mompara3_MC[i] = mompara_MC[3]
                    mompara4_MC[i] = mompara_MC[4]
                    mompara5_MC[i] = mompara_MC[5]
                except:
                    mompara0_MC[i] = mompara[0]
                    mompara1_MC[i] = mompara[1]
                    mompara2_MC[i] = mompara[2]
                    mompara3_MC[i] = mompara[3]
                    mompara4_MC[i] = mompara[4]
                    mompara5_MC[i] = mompara[5]
            mompara0E = N.std(mompara0_MC)
            mompara1E = N.std(mompara1_MC)
            if mompara1E > 2.0 * mompara[1]:
                mompara1E = 2.0 * mompara[1]  # Don't let errors get too large
            mompara2E = N.std(mompara2_MC)
            if mompara2E > 2.0 * mompara[2]:
                mompara2E = 2.0 * mompara[2]  # Don't let errors get too large
            mompara3E = N.std(mompara3_MC)
            if mompara3E > 2.0 * mompara[3]:
                mompara3E = 2.0 * mompara[3]  # Don't let errors get too large
            mompara4E = N.std(mompara4_MC)
            if mompara4E > 2.0 * mompara[4]:
                mompara4E = 2.0 * mompara[4]  # Don't let errors get too large
            mompara5E = N.std(mompara5_MC)
            if mompara5E > 2.0 * mompara[5]:
                mompara5E = 2.0 * mompara[5]  # Don't let errors get too large
        else:
            mompara1E = 0.0
            mompara2E = 0.0
            mompara3E = 0.0
            mompara4E = 0.0
            mompara5E = 0.0

        # Now add MC errors in quadrature with Condon (1997) errors
        size_skyE = [
            sqrt(mompara3E**2 + errors[3]**2) * sqrt(cdeltsq),
            sqrt(mompara4E**2 + errors[4]**2) * sqrt(cdeltsq),
            sqrt(mompara5E**2 + errors[5]**2)
        ]
        sraE, sdecE = (sqrt(mompara1E**2 + errors[1]**2) * sqrt(cdeltsq),
                       sqrt(mompara2E**2 + errors[2]**2) * sqrt(cdeltsq))
        deconv_size_skyE = size_skyE  # set deconvolved errors to non-deconvolved ones

        # Find aperture flux
        if img.opts.aperture_posn == 'centroid':
            aper_pos = [mompara[1] + delc[0], mompara[2] + delc[1]]
        else:
            aper_pos = posn
        aper_flux, aper_fluxE = func.ch0_aperture_flux(img, aper_pos,
                                                       img.aperture)

        isl_id = isl.island_id
        source_prop = list([
            'M', [tot, totE], [s_peak, isl.rms], [maxpeak, isl.rms],
            [aper_flux, aper_fluxE], [[sra, sdec], [sraE, sdecE]],
            [[mra, mdec], [sraE, sdecE]], [size_sky, size_skyE],
            [size_sky_uncorr, size_skyE], [deconv_size_sky, deconv_size_skyE],
            [deconv_size_sky_uncorr, deconv_size_skyE], isl.bbox,
            len(g_sublist), isl_id, g_sublist
        ])
        source = Source(img, source_prop)

        src_index += 1
        for g in g_sublist:
            g.source_id = src_index
            g.code = 'M'
        source.source_id = src_index

        return src_index, source
Esempio n. 6
0
    def process_Multiple(self, img, g_sublist, mask, src_index, isrc, subim, isl, delc, subn, subm):
        """ Same as gaul_to_source.f. isrc is same as k in the fortran version. """
        from math import pi, sqrt
        from const import fwsig
        from scipy import ndimage
        import functions as func

        mylog = mylogger.logging.getLogger("PyBDSM."+img.log+"Gaul2Srl  ")
        dum = img.beam[0]*img.beam[1]
        cdeltsq = img.wcs_obj.acdelt[0]*img.wcs_obj.acdelt[1]
        bmar_p = 2.0*pi*dum/(cdeltsq*fwsig*fwsig)

                                        # try
        subim_src = self.make_subim(subn, subm, g_sublist, delc)
        mompara = func.momanalmask_gaus(subim_src, mask, isrc, bmar_p, True)
                                        # initial peak posn and value
        maxv = N.max(subim_src)
        maxx, maxy = N.unravel_index(N.argmax(subim_src), subim_src.shape)
                                        # fit gaussian around this posn
        blc = N.zeros(2); trc = N.zeros(2)
        n, m = subim_src.shape[0:2]
        bm_pix = N.array([img.pixel_beam()[0]*fwsig, img.pixel_beam()[1]*fwsig, img.pixel_beam()[2]])
        ssubimsize = max(N.int(N.round(N.max(bm_pix[0:2])*2))+1, 5)
        blc[0] = max(0, maxx-(ssubimsize-1)/2); blc[1] = max(0, maxy-(ssubimsize-1)/2)
        trc[0] = min(n, maxx+(ssubimsize-1)/2); trc[1] = min(m, maxy+(ssubimsize-1)/2)
        s_imsize = trc - blc + 1

        p_ini = [maxv, (s_imsize[0]-1)/2.0*1.1, (s_imsize[1]-1)/2.0*1.1, bm_pix[0]/fwsig*1.3, \
                 bm_pix[1]/fwsig*1.1, bm_pix[2]*2]
        data = subim_src[blc[0]:blc[0]+s_imsize[0], blc[1]:blc[1]+s_imsize[1]]
        smask = mask[blc[0]:blc[0]+s_imsize[0], blc[1]:blc[1]+s_imsize[1]]
        rmask = N.where(smask==isrc, False, True)
        x_ax, y_ax = N.indices(data.shape)

        if N.sum(~rmask) >=6:
          para, ierr = func.fit_gaus2d(data, p_ini, x_ax, y_ax, rmask)
          if (0.0<para[1]<s_imsize[0]) and (0.0<para[2]<s_imsize[1]) and \
            para[3]<s_imsize[0] and para[4]<s_imsize[1]:
            maxpeak = para[0]
          else:
            maxpeak = maxv
          posn = para[1:3]-(0.5*N.sum(s_imsize)-1)/2.0+N.array([maxx, maxy])-1+delc
        else:
          maxpeak = maxv
          posn = N.unravel_index(N.argmax(data*~rmask), data.shape)+N.array(delc) +blc

        # calculate peak by bilinear interpolation around centroid
        # First check that moment analysis gave a valid position. If not, use
        # posn from gaussian fit instead.
        if N.isnan(mompara[1]):
            mompara[1] = posn[0] - delc[0]
        x1 = N.int(N.floor(mompara[1]))
        if N.isnan(mompara[2]):
            mompara[2] = posn[1] - delc[1]
        y1 = N.int(N.floor(mompara[2]))
        xind = slice(x1, x1+2, 1); yind = slice(y1, y1+2, 1)
        if img.opts.flag_smallsrc and (N.sum(mask[xind, yind]==N.ones((2,2))*isrc) != 4):
            mylog.debug('Island = '+str(isl.island_id))
            mylog.debug('Mask = '+repr(mask[xind, yind])+'xind, yind, x1, y1 = '+repr(xind)+' '+repr(yind)+' '+repr(x1)+' '+repr(y1))
        t=(mompara[1]-x1)/(x1+1-x1)  # in case u change it later
        u=(mompara[2]-y1)/(y1+1-y1)
        s_peak=(1.0-t)*(1.0-u)*subim_src[x1,y1]+t*(1.0-u)*subim_src[x1+1,y1]+ \
               t*u*subim_src[x1+1,y1+1]+(1.0-t)*u*subim_src[x1,y1+1]
        if (not img.opts.flag_smallsrc) and (N.sum(mask[xind, yind]==N.ones((2,2))*isrc) != 4):
            mylog.debug('Speak '+repr(s_peak)+'Mompara = '+repr(mompara))
            mylog.debug('x1, y1 : '+repr(x1)+', '+repr(y1))
            # import pylab as pl
            # pl.imshow(N.transpose(subim_src), origin='lower', interpolation='nearest')
            # pl.suptitle('Image of bad M source '+str(isl.island_id))
                                        # convert pixels to coords
        try:
            sra, sdec = img.pix2sky([mompara[1]+delc[0], mompara[2]+delc[1]])
            mra, mdec = img.pix2sky(posn)
        except RuntimeError, err:
            # Invalid pixel wcs coordinate
            sra, sdec = 0.0, 0.0
            mra, mdec = 0.0, 0.0