def find_xy_peak(img, center=None, sigma=3.0): """ Find the center of the peak of offsets """ # find level of noise in histogram istats = imagestats.ImageStats(img, nclip=1, fields='stddev,mode,mean,max,min') if istats.stddev == 0.0: istats = imagestats.ImageStats(img, fields='stddev,mode,mean,max,min') imgsum = img.sum() # clip out all values below mean+3*sigma from histogram imgc = img[:, :].copy() imgc[imgc < istats.mode + istats.stddev * sigma] = 0.0 # identify position of peak yp0, xp0 = np.where(imgc == imgc.max()) # Perform bounds checking on slice from img ymin = max(0, int(yp0[0]) - 3) ymax = min(img.shape[0], int(yp0[0]) + 4) xmin = max(0, int(xp0[0]) - 3) xmax = min(img.shape[1], int(xp0[0]) + 4) # take sum of at most a 7x7 pixel box around peak xp_slice = (slice(ymin, ymax), slice(xmin, xmax)) yp, xp = center_of_mass(img[xp_slice]) if np.isnan(xp) or np.isnan(yp): xp = 0.0 yp = 0.0 flux = 0.0 zpqual = None else: xp += xp_slice[1].start yp += xp_slice[0].start # compute S/N criteria for this peak: flux/sqrt(mean of rest of array) flux = imgc[xp_slice].sum() delta_size = float(img.size - imgc[xp_slice].size) if delta_size == 0: delta_size = 1 delta_flux = float(imgsum - flux) if flux > imgc[xp_slice].max(): delta_flux = flux - imgc[xp_slice].max() else: delta_flux = flux zpqual = flux / np.sqrt(delta_flux / delta_size) if np.isnan(zpqual) or np.isinf(zpqual): zpqual = None if center is not None: xp -= center[0] yp -= center[1] flux = imgc[xp_slice].max() return xp, yp, flux, zpqual
def _computeSky(image, skypars, memmap=False): """ Compute the sky value for the data array passed to the function image is a fits object which contains the data and the header for one image extension skypars is passed in as paramDict """ #this object contains the returned values from the image stats routine _tmp = imagestats.ImageStats(image.data, fields=skypars['skystat'], lower=skypars['skylower'], upper=skypars['skyupper'], nclip=skypars['skyclip'], lsig=skypars['skylsigma'], usig=skypars['skyusigma'], binwidth=skypars['skywidth']) _skyValue = _extractSkyValue(_tmp, skypars['skystat'].lower()) log.info(" Computed sky value/pixel for %s: %s " % (image.rootname, _skyValue)) del _tmp return _skyValue
def getskysigma(filelist, usemode=False, nclip=3): """ Compute the median sky noise for the given image or list of images. The default uses the skysigma algorithm as stated in the drizzlepac manual (v1.0, 2012) instead of the one implemented in drizzlepac/catalogs.py. That is, we use 1.5 times the sigma-clipped standard deviation of the image. With usemode set to True, we instead use the square root of twice the mode. """ from stsci import imagestats from numpy import median, sqrt, abs if isinstance(filelist, str): filelist = [filelist] modelist, stddevlist = [], [] for file in filelist: hdulist = pyfits.open(file) extnamelist = [ext.name.upper() for ext in hdulist] if 'SCI' in extnamelist: iextlist = [ iext for iext in range(len(extnamelist)) if extnamelist[iext] == 'SCI' ] else: iextlist = [0] for iext in iextlist: ext = hdulist[iext] istats = imagestats.ImageStats(ext.data, nclip=nclip, fields='mode,stddev', binwidth=0.01) stddevlist.append(istats.stddev) modelist.append(abs(istats.mode)) if usemode: return (sqrt(2.0 * median(modelist))) return (1.5 * median(stddevlist))
def _compute_sigma(self): src_vals = self.source if np.any(np.isnan(self.source)): src_vals = self.source[np.where(np.isnan(self.source) == False)] istats = imagestats.ImageStats(src_vals, nclip=3, fields='mode,stddev', binwidth=0.01) sigma = np.sqrt(2.0 * np.abs(istats.mode)) return sigma
#create an empty array for bad pixel mask and donotuse mask arrshape = (5, 5) ipc = np.zeros(arrshape) ##Dark images section## #slopenoiseactive=slopenoise[4:2044,4:2044] #imstatslope = imagestats.ImageStats(slopenoiseactive,fields="npix,min,max,median,mean,stddev",binwidth=0.1,nclip=3) #imstatslope.printStats() #cdsnoiseactive=cdsnoise[4:2044,4:2044] #imstatcds = imagestats.ImageStats(cdsnoiseactive,fields="npix,min,max,median,mean,stddev",binwidth=0.1,nclip=3) #imstatcds.printStats() #darkcurractive=darkcurr[4:2044,4:2044] imstatdark = imagestats.ImageStats(darkcurr, fields="npix,min,max,median,mean,stddev", binwidth=0.1, nclip=3) imstatdark.printStats() #Get hot pixels not in void - need to add void mask sel below w = (np.where((voidmask != 1) & (hotflagged == 1) & (badflatflagged != 1) & (darkcurr > 1.0) & (darkcurr < 100.0))) print(darkcurr[w].size) yhotnotvoid = w[0] xhotnotvoid = w[1] #print (yhotnotvoid,xhotnotvoid) numhotnotvoid = yhotnotvoid.size #Get hot pixels in void - repeat above block w = (np.where((voidmask == 1) & (hotflagged == 1) & (badflatflagged != 1) & (darkcurr > 1.0) & (darkcurr < 100.0)))
def make_vector_plot(coordfile,columns=[1,2,3,4],data=None,figure_id=None, title=None, axes=None, every=1,labelsize=8, ylimit=None, limit=None, xlower=None, ylower=None, output=None, headl=4,headw=3, xsh=0.0,ysh=0.0,fit=None,scale=1.0,vector=True,textscale=5, append=False,linfit=False,rms=True, plotname=None): """ Convert a XYXYMATCH file into a vector plot or set of residuals plots. This function provides a single interface for generating either a vector plot of residuals or a set of 4 plots showing residuals. The data being plotted can also be adjusted for a linear fit on-the-fly. Parameters ---------- coordfile : string Name of file with matched sets of coordinates. This input file can be a file compatible for use with IRAF's geomap. columns : list [Default: [0,1,2,3]] Column numbers for the X,Y positions from each image data : list of arrays If specified, this can be used to input matched data directly title : string Title to be used for the generated plot axes : list List of X and Y min/max values to customize the plot axes every : int [Default: 1] Slice value for the data to be plotted limit : float Radial offset limit for selecting which sources are included in the plot labelsize : int [Default: 8] or str Font size to use for tick labels, either in font points or as a string understood by tick_params(). ylimit : float Limit to use for Y range of plots. xlower : float ylower : float Limit in X and/or Y offset for selecting which sources are included in the plot output : string Filename of output file for generated plot headl : int [Default: 4] Length of arrow head to be used in vector plot headw : int [Default: 3] Width of arrow head to be used in vector plot xsh : float ysh : float Shift in X and Y from linear fit to be applied to source positions from the first image scale : float Scale from linear fit to be applied to source positions from the first image fit : array Array of linear coefficients for rotation (and scale?) in X and Y from a linear fit to be applied to source positions from the first image vector : bool [Default: True] Specifies whether or not to generate a vector plot. If False, task will generate a set of 4 residuals plots instead textscale : int [Default: 5] Scale factor for text used for labelling the generated plot append : bool [Default: False] If True, will overplot new plot on any pre-existing plot linfit : bool [Default: False] If True, a linear fit to the residuals will be generated and added to the generated residuals plots rms : bool [Default: True] Specifies whether or not to report the RMS of the residuals as a label on the generated plot(s). plotname : str [Default: None] Write out plot to a file with this name if specified. """ from matplotlib import pyplot as plt if data is None: data = readcols(coordfile,cols=columns) xy1x = data[0] xy1y = data[1] xy2x = data[2] xy2y = data[3] numpts = xy1x.shape[0] if fit is not None: xy1x,xy1y = apply_db_fit(data,fit,xsh=xsh,ysh=ysh) fitstr = '-Fit applied' dx = xy2x - xy1x dy = xy2y - xy1y else: dx = xy2x - xy1x - xsh dy = xy2y - xy1y - ysh # apply scaling factor to deltas dx *= scale dy *= scale print('Total # points: ',len(dx)) if limit is not None: indx = (np.sqrt(dx**2 + dy**2) <= limit) dx = dx[indx].copy() dy = dy[indx].copy() xy1x = xy1x[indx].copy() xy1y = xy1y[indx].copy() if xlower is not None: xindx = (np.abs(dx) >= xlower) dx = dx[xindx].copy() dy = dy[xindx].copy() xy1x = xy1x[xindx].copy() xy1y = xy1y[xindx].copy() print('# of points after clipping: ',len(dx)) dr = np.sqrt(dx**2 + dy**2) max_vector = dr.max() if output is not None: write_xy_file(output,[xy1x,xy1y,dx,dy]) fig = plt.figure(num=figure_id) if not append: plt.clf() if vector: dxs = imagestats.ImageStats(dx.astype(np.float32)) dys = imagestats.ImageStats(dy.astype(np.float32)) minx = xy1x.min() maxx = xy1x.max() miny = xy1y.min() maxy = xy1y.max() xrange = maxx - minx yrange = maxy - miny qplot = plt.quiver(xy1x[::every],xy1y[::every],dx[::every],dy[::every],\ units='y',headwidth=headw,headlength=headl) key_dx = xrange*0.01 key_dy = yrange*(0.005*textscale) maxvec = max_vector/2. key_len = round((maxvec+0.005),2) plt.xlabel('DX: %.4f to %.4f +/- %.4f'%(dxs.min,dxs.max,dxs.stddev)) plt.ylabel('DY: %.4f to %.4f +/- %.4f'%(dys.min,dys.max,dys.stddev)) plt.title(r"$Vector\ plot\ of\ %d/%d\ residuals:\ %s$"%( xy1x.shape[0],numpts,title)) plt.quiverkey(qplot,minx+key_dx,miny-key_dy,key_len,"%0.2f pixels"%(key_len), coordinates='data',labelpos='E',labelcolor='Maroon',color='Maroon') else: plot_defs = [[xy1x,dx,"X (pixels)","DX (pixels)"],\ [xy1y,dx,"Y (pixels)","DX (pixels)"],\ [xy1x,dy,"X (pixels)","DY (pixels)"],\ [xy1y,dy,"Y (pixels)","DY (pixels)"]] if axes is None: # Compute a global set of axis limits for all plots minx = xy1x.min() maxx = xy1x.max() miny = dx.min() maxy = dx.max() if xy1y.min() < minx: minx = xy1y.min() if xy1y.max() > maxx: maxx = xy1y.max() if dy.min() < miny: miny = dy.min() if dy.max() > maxy: maxy = dy.max() else: minx = axes[0][0] maxx = axes[0][1] miny = axes[1][0] maxy = axes[1][1] if ylimit is not None: miny = -1*ylimit maxy = ylimit xrange = maxx - minx yrange = maxy - miny rms_labelled=False if title is None: fig.suptitle("Residuals [%d/%d]"%(xy1x.shape[0],numpts),ha='center',fontsize=labelsize+6) else: # This definition of the title supports math symbols in the title fig.suptitle(r"$"+title+"$",ha='center', fontsize=labelsize+6) for pnum, p in enumerate(plot_defs): pn = pnum+1 ax = fig.add_subplot(2,2,pn) plt.plot(p[0],p[1],'b.',label='RMS(X) = %.4f, RMS(Y) = %.4f'%(dx.std(),dy.std())) lx=[ int((p[0].min()-500)/500) * 500,int((p[0].max()+500)/500) * 500] plt.plot([lx[0],lx[1]],[0.0,0.0],'k',linewidth=3) plt.axis([minx,maxx,miny,maxy]) if rms and not rms_labelled: leg_handles, leg_labels = ax.get_legend_handles_labels() fig.legend(leg_handles, leg_labels, loc='center left', fontsize='small', frameon=False, bbox_to_anchor=(0.33, 0.51), borderaxespad=0) rms_labelled = True ax.tick_params(labelsize=labelsize) # Fine-tune figure; hide x ticks for top plots and y ticks for right plots if pn <= 2: plt.setp(ax.get_xticklabels(), visible=False) else: ax.set_xlabel(plot_defs[pnum][2]) if pn%2 == 0: plt.setp(ax.get_yticklabels(), visible=False) else: ax.set_ylabel(plot_defs[pnum][3]) if linfit: lxr = int((lx[-1] - lx[0])/100) lyr = int((p[1].max() - p[1].min())/100) A = np.vstack([p[0],np.ones(len(p[0]))]).T m,c = np.linalg.lstsq(A,p[1])[0] yr = [m*lx[0]+c,lx[-1]*m+c] plt.plot([lx[0],lx[-1]],yr,'r') plt.text(lx[0]+lxr,p[1].max()+lyr,"%0.5g*x + %0.5g [%0.5g,%0.5g]"%(m,c,yr[0],yr[1]),color='r') plt.draw() if plotname: suffix = plotname[-4:] if '.' not in suffix: output += '.png' format = 'png' else: if suffix[1:] in ['png','pdf','ps','eps','svg']: format=suffix[1:] plt.savefig(plotname,format=format)
meanpcfile = os.path.join(noisedir, outfileroot + 'meandarkzero.fits') medianpcfile = meanpcfile.replace('meandarkzero', 'mediandarkzero') stdpcfile = meanpcfile.replace('meandarkzero', 'sigmadarkzero') fits.writeto(meanpcfile, clippedslope3dpcmean, header, overwrite=True) fits.writeto(medianpcfile, clippedslope3dpcmedian, header, overwrite=True) fits.writeto(stdpcfile, clippedslope3dpcstd, header, overwrite=True) #optionally output stats for dark current and slope noise if outputstats == True: print('PC offsets: ', offsetclippedslope1d) print('Std dev of PC offsets: ', np.std(offsetclippedslope1d)) i = imagestats.ImageStats(clippedslope3dmean[4:2044, 4:2044], fields="npix,min,max,median,mean,stddev", nclip=3, lsig=3.0, usig=3.0, binwidth=0.1) print(meanfile) i.printStats() i = imagestats.ImageStats(clippedslope3dmedian[4:2044, 4:2044], fields="npix,min,max,median,mean,stddev", nclip=3, lsig=3.0, usig=3.0, binwidth=0.1) print(medianfile) i.printStats() i = imagestats.ImageStats(clippedslope3dstd[4:2044, 4:2044], fields="npix,min,max,median,mean,stddev", nclip=3,
def _subtract_sky(self, ext_info, flag=-1.0e10): """Perform a classical background subtraction.""" # Derive the name of all aXe products for a given image axe_names = config_util.get_axe_names(self.grisim, ext_info) msk_image_sc = axe_names['MSK'] + '[SCI]' # check for a previous background subtraction with fits.open(self.grisim, mode='update') as grism_file: if 'AXEPRBCK' in grism_file[ext_info['fits_ext']].header: # warn that this is the second time _log.info("WARNING: Image %25s seems to be already background " "subtracted!".format(self.grisim)) # Compute the ratio of the grism SCI image to the background image sci_data = grism_file['SCI', ext_info['ext_version']].data sci_header = grism_file['SCI', ext_info['ext_version']].header npix = int(sci_header["NAXIS1"]) * int(sci_header["NAXIS2"]) bck_data = fits.getdata(self.master_bck) ratio_data = sci_data / bck_data # Flag pixels in the ratio image based on the grism image DQ array grism_dq_data = grism_file['DQ', ext_info['ext_version']].data ratio_data[grism_dq_data > 0.5] = flag # Flag pixels in the ratio image based on the grism image MSK file msk_file = fits.open( config_util.getOUTPUT(msk_image_sc.split("[")[0]), 'readonly') msk_data = msk_file['SCI'].data msk_file.close() ratio_data[msk_data < -900000] = flag # Flag pixels in the background image based on the grism image DQ # and MSK file bck_data[grism_dq_data > 0.5] = flag bck_data[msk_data < -900000] = flag # Compute stats for the ratio image stats = imagestats.ImageStats(ratio_data[ratio_data > flag], fields='midpt,stddev,npix', lower=None, upper=None, nclip=3, lsig=3.0, usig=3.0, binwidth=0.01) # Compute stats for the background image bstats = imagestats.ImageStats(bck_data[bck_data > flag], fields='midpt,stddev,npix', lower=None, upper=None, nclip=3, lsig=3.0, usig=3.0, binwidth=0.01) # Subtract the scaled background from the grism image # Reload a clean version of background bck_data = fits.getdata(self.master_bck) grism_file['SCI', ext_info['ext_version']].data -= bck_data * stats.midpt grism_header = grism_file['SCI', ext_info['ext_version']].header # write some header iformation grism_header['SKY_SCAL'] = (float( stats.midpt), 'scaling value for the master background') grism_header['SKY_MAST'] = (float( bstats.midpt), 'average value of the master background') grism_header['SKY_IMG'] = (self.master_bck, 'name of the master background image') grism_header['F_SKYPIX'] = (float(stats.npix) / float(npix), 'fraction of pixels used for scaling') grism_header['AXEPRBCK'] = ( 'Done', 'flag that background subtraction was done') return 0
def _subtract_sky(self, ext_info): """ Make a classical background subtraction """ import os, shutil from pyraf import iraf from iraf import stsdas from astropy.io import fits as pyfits import stsci.imagestats as imagestats # get the axe names axe_names = axeutils.get_axe_names(self.grisim, ext_info) msk_image_sc = axe_names['MSK'] + '[SCI]' # check for a previous background subtraction fits_img = pyfits.open(axeutils.getIMAGE(self.grisim), 'readonly') fits_head = fits_img[ext_info['fits_ext']].header npix = int(fits_head['NAXIS1']) * int(fits_head['NAXIS1']) if 'AXEPRBCK' in fits_head: # warn that this is the second time print( 'WARNING: Image %25s seems to be already background subtracted!' % axeutils.getIMAGE(self.grisim)) # close the fits fits_img.close() # Compute the ratio of the grism SCI image to the background image sci_file = pyfits.open(axeutils.getIMAGE(self.grisim), 'readonly') sci_data = sci_file['SCI', ext_info['ext_version']].data bck_file = pyfits.open(axeutils.getCONF(self.master_bck), 'readonly') bck_data = bck_file[0].data sci_data /= bck_data # Flag pixels in the ratio image based on the grism image DQ array dq_data = sci_file['DQ', ext_info['ext_version']].data sci_data[dq_data > 0.5] = -1.0e10 # Flag pixels in the ratio image based on the grism image MSK file msk_file = pyfits.open(axeutils.getOUTPUT(msk_image_sc.split("[")[0]), 'readonly') msk_data = msk_file['SCI'].data sci_data[msk_data < -900000] = -1.0e10 # Flag pixels in the background image based on the grism image DQ # and MSK file bck_data[dq_data > 0.5] = -1.0e10 bck_data[msk_data < -900000] = -1.0e10 # Compute stats for the ratio image stats = imagestats.ImageStats(sci_data[sci_data > -1.0e9], fields='midpt,stddev,npix', lower=None, upper=None, nclip=3, lsig=3.0, usig=3.0, binwidth=0.01) flt_ave = stats.midpt flt_std = stats.stddev flt_npx = stats.npix frac_pix = float(flt_npx) / float(npix) # Compute stats for the background image stats = imagestats.ImageStats(bck_data[bck_data > -1.0e9], fields='midpt,stddev,npix', lower=None, upper=None, nclip=3, lsig=3.0, usig=3.0, binwidth=0.01) mst_ave = stats.midpt mst_std = stats.stddev mst_npx = stats.npix sci_file.close() bck_file.close() msk_file.close() # Subtract the scaled background from the grism image sci_file = pyfits.open(axeutils.getIMAGE(self.grisim), 'update') bck_file = pyfits.open(axeutils.getCONF(self.master_bck), 'readonly') sci_file['SCI', ext_info['ext_version']].data -= flt_ave * bck_file[0].data sci_file.close() bck_file.close() # open the fits image ands isolate the correct extension grism_img = pyfits.open(axeutils.getIMAGE(self.grisim), 'update') grism_header = grism_img[ext_info['fits_ext']].header # write some header iformation grism_header['SKY_SCAL'] = (float(flt_ave), 'scaling value for the master background') grism_header['SKY_MAST'] = (float(mst_ave), 'average value of the master background') grism_header['SKY_IMG'] = (self.master_bck, 'name of the master background image') grism_header['F_SKYPIX'] = (frac_pix, 'fraction of pixels used for scaling') grism_header['AXEPRBCK'] = ( 'Done', 'flag that background subtraction was done') # save the image grism_img.close() return 0
print(lines1, lines2) positions = [] shift = [] for k in np.ndenumerate(lines2): #get both indicies for the two cubes being aligned j = int(lines1[k[0]]) i = int(k[-1]) #more sanity checks print(i) print(j) #sum over the spectral range of each line to first get image of the entire nebular line #Then find the mean pixel value of each resulting image mean1 = imagestats.ImageStats(np.sum(data1[j - 5:j + 5, :, :], axis=0), nclip=0).mean mean2 = imagestats.ImageStats(np.sum(data2[i - 5:i + 5, :, :], axis=0), nclip=0).mean #subtract the mean from the image image1 = np.sum(data1[j - 5:j + 5, :, :], axis=0) - mean1 image2 = np.sum(data2[i - 5:i + 5, :, :], axis=0) - mean2 #Now subsample each pixel to 5x5 subpixels to better increase accuracy of alignment. scalefactor = 5. image1 = ndimage.zoom(image1, scalefactor, order=3) image2 = ndimage.zoom(image2, scalefactor, order=3) #Correlate the subsampled images to find where they line up best corr = ndimage.correlate(image1, image2, mode='constant') corrout = fits.PrimaryHDU(corr) corrout.writeto("corr" + str(i) + ".fits", overwrite=True)