def shapelet_getroot(xfn, yfn, xco, xcen, ycen): """ This finds the root for finding the shapelet centre. If there are multiple roots, takes that which closest to the 'centre', taken as the intensity barycentre. This is the python version of getroot.f of anaamika.""" import functions as func root = None npoint = len(xfn) error = 0 if npoint == 0: error = 1 elif yfn.max() * yfn.min() >= 0.: error = 1 minint = 0 minintold = 0 for i in range(1, npoint): if yfn[i - 1] * yfn[i] < 0.: if minintold == 0: # so take nearest to centre if abs(yfn[i - 1]) < abs(yfn[i]): minint = i - 1 else: minint = i else: dnew = func.dist_2pt([xco, xfn[i]], [xcen, ycen]) dold = func.dist_2pt([xco, xfn[minintold]], [xcen, ycen]) if dnew <= dold: minint = i else: minint = minintold minintold = minint if minint < 1 or minint > npoint: error = 1 if error != 1: low = minint - min(2, minint) #-1) up = minint + min(2, npoint - 1 - minint) # python array indexing rubbish nfit = up - low + 1 xfit = xfn[low:low + nfit] yfit = yfn[low:low + nfit] sig = N.ones(nfit) smask = N.zeros(nfit, dtype=bool) xx = [i for i in range(low, low + nfit)] [c, m], errors = func.fit_mask_1d(xfit, yfit, sig, smask, func.poly, do_err=False, order=1) root = -c / m if root < xfn[low] or root > xfn[up]: error = 1 return root, error
def shapelet_getroot(xfn, yfn, xco, xcen, ycen): """ This finds the root for finding the shapelet centre. If there are multiple roots, takes that which closest to the 'centre', taken as the intensity barycentre. This is the python version of getroot.f of anaamika.""" import functions as func root = None npoint = len(xfn) error = 0 if npoint == 0: error = 1 elif yfn.max() * yfn.min() >= 0.0: error = 1 minint = 0 minintold = 0 for i in range(1, npoint): if yfn[i - 1] * yfn[i] < 0.0: if minintold == 0: # so take nearest to centre if abs(yfn[i - 1]) < abs(yfn[i]): minint = i - 1 else: minint = i else: dnew = func.dist_2pt([xco, xfn[i]], [xcen, ycen]) dold = func.dist_2pt([xco, xfn[minintold]], [xcen, ycen]) if dnew <= dold: minint = i else: minint = minintold minintold = minint if minint < 1 or minint > npoint: error = 1 if error != 1: low = minint - min(2, minint) # -1) up = minint + min(2, npoint - 1 - minint) # python array indexing rubbish nfit = up - low + 1 xfit = xfn[low : low + nfit] yfit = yfn[low : low + nfit] sig = N.ones(nfit) smask = N.zeros(nfit, dtype=bool) xx = [i for i in range(low, low + nfit)] [c, m], errors = func.fit_mask_1d(xfit, yfit, sig, smask, func.poly, do_err=False, order=1) root = -c / m if root < xfn[low] or root > xfn[up]: error = 1 return root, error
def edit_vorogenlist(self, vorogenP, frac): """ Edit primary voronoi generator list. Each tile has a tile centre and can have more than one generator to be averaged. tile_list is a list of arrays, indexed by the tile number and each array is an array of numbers in the ngen list which are the generators in that tile. xtile, ytile and snrtile are arrays of length number_of_tiles and have x,y,snr of each tile. Group together generators if closer than a fraction of dist to third closest.""" xgen, ygen, snrgen = vorogenP flag = N.zeros(len(xgen)) coord=N.array([xgen,ygen]).transpose() tile_list = [] tile_coord = []; tile_snr = [] for i in range(len(xgen)): dist = N.array(map(lambda t: func.dist_2pt(coord[i], t), coord)) indi = N.argsort(dist) sortdist = dist[indi] if sortdist[1] < frac * sortdist[2]: # first is the element itself if flag[indi[1]] + flag[i] == 0: # not already deleted from other pair tile_list.append([i, indi[1]]) tile_coord.append((coord[i]*snrgen[i]+coord[indi[1]]*snrgen[indi[1]])/(snrgen[i]+snrgen[indi[1]])) tile_snr.append(snrgen[i]+snrgen[indi[1]]) flag[i] = 1 flag[indi[1]] = 1 else: if len(dist) > 3: if sortdist[1]+sortdist[2] < 2.0*frac*sortdist[3]: # for 3 close-by sources in1=indi[1] in2=indi[2] if flag[in1]+flag[in2]+flag[i] == 0: # not already deleted from others tile_list.append([i, in1, in2]) tile_coord.append((coord[i]*snrgen[i]+coord[in1]*snrgen[in1]+coord[in2]*snrgen[in2]) \ /(snrgen[i]+snrgen[in1]+snrgen[in2])) tile_snr.append(snrgen[i]+snrgen[in1]+snrgen[in2]) flag[i] = 1 flag[in1] = 1 flag[in2] = 1 else: tile_list.append([i]) tile_coord.append(coord[i]) tile_snr.append(snrgen[i]) # Assign any leftover generators for i in range(len(xgen)): if flag[i] == 0: tile_list.append([i]) tile_coord.append(coord[i]) tile_snr.append(snrgen[i]) return tile_list, tile_coord, tile_snr
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