def inigaus_fbdsm(self, isl, thr, beam, img): """ initial guess for gaussians like in fbdsm """ from math import sqrt from const import fwsig 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 = thr 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) if len(inipeak) == 0: av, stdnew, maxv, maxp, minv, minp = func.arrstatmask(im, mask) inipeak = [maxv] iniposn = [maxp] nmulsrc1 = len(iniposn) domore = True while domore: domore = False av, stdnew, maxv, maxp, minv, minp = func.arrstatmask(im1, mask) if stdnew > isl.rms and maxv >= thr and maxv >= isl.mean + 2.0 * isl.rms: domore = True x1, y1 = N.array(iniposn).transpose() dumr = N.sqrt((maxp[0] - x1) * (maxp[0] - x1) + (maxp[1] - y1) * (maxp[1] - y1)) distbm = dumr / sqrt(beam[0] * beam[1] * fwsig * fwsig) if N.any((distbm < 0.5) + (dumr < 2.2)): domore = False if domore: iniposn.append(N.array(maxp)) inipeak.append(maxv) im1 = func.mclean(im1, maxp, beam) inipeak = N.array(inipeak) iniposn = N.array(iniposn) ind = list(N.argsort(inipeak)) ind.reverse() inipeak = inipeak[ind] iniposn = iniposn[ind] gaul = [] for i in range(len(inipeak)): g = (float(inipeak[i]), int(iniposn[i][0]), int( iniposn[i][1])) + beam gaul.append(g) return gaul, nmulsrc1, len(inipeak)
def inigaus_fbdsm(self, isl, thr, beam, img): """ initial guess for gaussians like in fbdsm """ from math import sqrt from const import fwsig 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 = thr 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) if len(inipeak) == 0: av, stdnew, maxv, maxp, minv, minp = func.arrstatmask(im, mask) inipeak = [maxv]; iniposn = [maxp] nmulsrc1 = len(iniposn) domore = True while domore: domore = False av, stdnew, maxv, maxp, minv, minp = func.arrstatmask(im1, mask) if stdnew > isl.rms and maxv >= thr and maxv >= isl.mean+2.0*isl.rms: domore = True x1, y1 = N.array(iniposn).transpose() dumr = N.sqrt((maxp[0]-x1)*(maxp[0]-x1)+(maxp[1]-y1)*(maxp[1]-y1)) distbm = dumr/sqrt(beam[0]*beam[1]*fwsig*fwsig) if N.any((distbm < 0.5) + (dumr < 2.2)): domore = False if domore: iniposn.append(N.array(maxp)); inipeak.append(maxv) im1 = func.mclean(im1, maxp, beam) inipeak = N.array(inipeak); iniposn = N.array(iniposn) ind = list(N.argsort(inipeak)); ind.reverse() inipeak = inipeak[ind] iniposn = iniposn[ind] gaul = [] for i in range(len(inipeak)): g = (float(inipeak[i]), int(iniposn[i][0]), int(iniposn[i][1])) + beam gaul.append(g) return gaul, nmulsrc1, len(inipeak)
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
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 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