示例#1
0
def manual_bg(data):
    #directly from photutils example
    mean, median, std = sigma_clipped_stats(data, sigma=3.0, iters=5)
    threshold = median + (std * 2.)
    segm_img = detect_sources(data, threshold, npixels=5)
    #%% morphological
    mask = segm_img.data.astype(bool)
    strel = ones((3,3))
    dilated = binary_dilation(mask,strel)
    mean, median, std = sigma_clipped_stats(data, sigma=3.0, mask=dilated)
    #%% use mean or median for background? Let's do what sextractor does
    if (mean - median) / std > 0.3:
        bgval = median
    else:
        bgval = mean
    #%% background subtract
    dinf = iinfo(data.dtype)

    imgmask = masked_where(~dilated,100+data).clip(0,dinf.max).astype(data.dtype)
    datashift=(data-bgval).clip(0,dinf.max).astype(data.dtype)
#%%
    fg,axs = subplots(2,2)
    ax = axs[0,0]
    hi=ax.imshow(data,interpolation='none',cmap='gray')
    ax.imshow(imgmask,interpolation='none',cmap='gray')
    ax.set_title('original image with stars highlighted')
    fg.colorbar(hi,ax=ax)
    ax.grid(False)

    ax=axs[0,1]
    ax.imshow(dilated,interpolation='none')
    ax.set_title('dilated')
    ax.grid(False)

    ax = axs[1,0]
    hi=ax.imshow(datashift,interpolation='none',cmap='gray')
    ax.set_title('background subtracted image {:.3f}'.format(bgval))
    fg.colorbar(hi,ax=ax)
    ax.grid(False)

    fg.tight_layout()

    return datashift
def manual_bg(data):
    #directly from photutils example
    mean, median, std = sigma_clipped_stats(data, sigma=3.0, iters=5)
    threshold = median + (std * 2.)
    segm_img = detect_sources(data, threshold, npixels=5)
    #%% morphological
    mask = segm_img.data.astype(bool)
    strel = ones((3,3))
    dilated = binary_dilation(mask,strel)
    mean, median, std = sigma_clipped_stats(data, sigma=3.0, mask=dilated)
    #%% use mean or median for background? Let's do what sextractor does
    if (mean - median) / std > 0.3:
        bgval = median
    else:
        bgval = mean
    #%% background subtract
    dinf = iinfo(data.dtype)

    imgmask = masked_where(~dilated,100+data).clip(0,dinf.max).astype(data.dtype)
    datashift=(data-bgval).clip(0,dinf.max).astype(data.dtype)
#%%
    fg,axs = subplots(2,2)
    ax = axs[0,0]
    hi=ax.imshow(data,interpolation='none',cmap='gray')
    ax.imshow(imgmask,interpolation='none',cmap='gray')
    ax.set_title('original image with stars highlighted')
    fg.colorbar(hi,ax=ax)
    ax.grid(False)

    ax=axs[0,1]
    ax.imshow(dilated,interpolation='none')
    ax.set_title('dilated')
    ax.grid(False)

    ax = axs[1,0]
    hi=ax.imshow(datashift,interpolation='none',cmap='gray')
    ax.set_title('background subtracted image {:.3f}'.format(bgval))
    fg.colorbar(hi,ax=ax)
    ax.grid(False)

    fg.tight_layout()

    return datashift
示例#3
0
def source_find(img,ota,inst):
    """
    This function will find sources on an OTA
    using the detect_sources module from photutils.
    This will return of csv file of the sources found
    with the x,y,Ra,Dec,source_sum,max_value, and
    elongation of the source. The elongation parameter is
    semimajor_axis / semiminor_axis. This output is needed
    for the source_xy function.
    """
    image = odi.reprojpath+'reproj_'+ota+'.'+str(img[16:])
    QR_raw = odi.fits.open(image)
    hdu_ota = QR_raw[0]

    if inst == 'podi':
        pvlist = hdu_ota.header['PV*']
        for pv in pvlist:
            tpv = 'T'+pv
            hdu_ota.header.rename_keyword(pv, tpv, force=False)
    w = odi.WCS(hdu_ota.header)
    #w.wcs.ctype = ["RA---TPV", "DEC--TPV"]
    bg_mean,bg_median,bg_std = odi.mask_ota(img,ota,reproj=True)
    threshold = bg_median + (bg_std * 5.)
    print bg_mean,bg_median,bg_std
    segm_img = detect_sources(hdu_ota.data, threshold, npixels=20)
    source_props = source_properties(hdu_ota.data,segm_img,wcs=w)

    columns = ['id', 'xcentroid', 'ycentroid', 'ra_icrs_centroid',
	       'dec_icrs_centroid','source_sum','max_value','elongation']
    source_tbl = properties_table(source_props,columns=columns)
    source_tbl_df = source_tbl.to_pandas()

    outputfile = odi.sourcepath+'source_'+ota+'.'+str(img[16:-5])+'.csv'

    source_tbl_df.to_csv(outputfile,index=False)
    QR_raw.close()
示例#4
0
def segmentation_photometry(path_file_abs,
                            bkg_sigma=3.0,
                            source_snr=3.0,
                            fwhm_kernel=2.0,
                            x_size_kernel=3,
                            y_size_kernel=3,
                            clobber=False):
    """
    aperture photometry from source segmentation
    make_source_mask not yet available in photutils v0.2.2, this version
    manually creates a source mask for determining background

    """

    import os
    import copy
    import glob
    import pickle
    import numpy as np
    from scipy import ndimage
    import matplotlib
    #matplotlib.rcParams['text.usetex'] = True
    #matplotlib.rcParams['text.latex.unicode'] = True
    #from matplotlib.backends.backend_pdf import PdfPages
    import matplotlib.pyplot as plt
    from astropy.io import fits, ascii
    from astropy.convolution import Gaussian2DKernel
    from astropy.stats import sigma_clipped_stats, gaussian_fwhm_to_sigma
    #    from astropy.table import Table
    from astropy.visualization import (LogStretch, mpl_normalize)
    #    from astropy.extern.six.moves import StringIO
    from photutils import (detect_threshold, EllipticalAperture,
                           source_properties, properties_table)
    from photutils.detection import detect_sources
    from photutils.utils import random_cmap

    # create preliminary mask
    #from photutils import make_source_mask
    #masterMask = make_source_mask(master, snr=2, npixels=5, dilate_size=11)

    #        if LEDoff was used, get threshold from LEDoff/background
    #        path_dataset = os.path.dirname(path_file_abs) + os.path.sep
    #        filenameCombined = '\t'.join(
    #            os.listdir(os.path.join(datasetDirLocal, 'master')))
    #        if 'master_ledoff_subtracted' in filename:
    #            print('Using master_ledoff')
    #            # path_file_abs = os.path.join(datasetDir, 'master', filename)
    #            hdu = fits.open(path_file_abs)[0]
    #            data_subtracted = hdu.data
    #            # calculate threadhold
    #            ledoff_pred = np.mean(data_subtracted) * \
    #                np.ones(data_subtracted.shape)
    #            mse = mean_squared_error(data_subtracted, ledoff_pred)
    #            rmse = np.sqrt(mse)
    #            threshold = 7.0 * rmse
    #            threshold_value = threshold
    #         if no LEDoff was used, background subtraction is needed
    #         there should exist no file named "subtracted"
    #         if 'master.fit' in filenameCombined \
    #             or 'master_normalised.fit' in filenameCombined:

    #filenamedir = os.path.basename(path_file_abs)
    #print(filenamedir)
    #New stuff made by Parker
    f_dir, filename = os.path.split(path_file_abs)
    ff = os.path.splitext(filename)[0]
    new_dir = f_dir + '/' + ff

    if not os.path.exists(new_dir):
        os.makedirs(new_dir)
    dir_save = new_dir
    print("The photometry files will be saved in ", dir_save)
    filenames_combined = '\t'.join(os.listdir(dir_save))

    if clobber == False \
        and 'segm.obj' in filenames_combined  \
        and 'props.obj' in filenames_combined \
        and 'props.csv' in filenames_combined\
        and 'props.ecsv' in filenames_combined:
        print('Photometry properties table already exists. Reading objects...')
        segm = pickle.load(
            open(glob.glob(os.path.join(dir_save, '*segm.obj*'))[0], 'rb'))
        props = pickle.load(
            open(glob.glob(os.path.join(dir_save, '*props.obj*'))[0], 'rb'))

        return [segm, props]

    if 'master' in path_file_abs:
        if 'normalised' in path_file_abs:
            print('Performing photometry to ' +
                  'normalised master object image {}...'.format(path_file_abs))
        else:
            print('Performing photometry to ' +
                  'un-normalised master image {}...'.format(path_file_abs))
    else:
        print('Warning: Photometry being performed to ' +
              'a single exposure {}...'.format(path_file_abs))

    hdu = fits.open(path_file_abs)[0]
    data = hdu.data
    header = hdu.header

    if 'EXPREQ' in header:
        exptime = header['EXPREQ']
    elif 'EXPTIME' in header:
        exptime = header['EXPTIME']
    else:
        print('Exposure time not found in header. Cannot determine magnitude.')
        exptime = np.nan

    # === Iteratively determine background level ===

    # assuming background is homogenous, estimate background by sigma clipping
    # if background noise varies across image, generate 2D background instead
    print('Determining background noise level...' '')
    [mean, median, std] = sigma_clipped_stats(data, sigma=bkg_sigma, iters=5)
    threshold = median + (std * 2.0)
    segm = detect_sources(data, threshold, npixels=5)
    # turn segm into a mask
    mask = segm.data.astype(np.bool)
    # dilate the source mask to ensure complete masking of detected sources
    dilate_structure = np.ones((5, 5))
    mask_dilated = ndimage.binary_dilation(mask, structure=dilate_structure)
    # get sigma clipping stats of background, without sources that are masekd
    [bkg_mean, bkg_median, bkg_std] = sigma_clipped_stats(data,
                                                          sigma=bkg_sigma,
                                                          mask=mask_dilated,
                                                          iters=3)

    # === Detect sources by segmentation ===

    print('Determining threshold for source detection...')
    # determine threshold for source detection
    # in current implementation, if all inputs are present, the formula is
    # threshold = background + (background_error * snr)
    threshold = detect_threshold(data,
                                 background=bkg_median,
                                 error=bkg_std,
                                 snr=source_snr)
    print('Preparing 2D Gaussian kernal...')
    sigma_kernel = fwhm_kernel * gaussian_fwhm_to_sigma
    kernel = Gaussian2DKernel(sigma_kernel,
                              x_size=x_size_kernel,
                              y_size=y_size_kernel)
    # normalise kernel
    # The kernel models are normalized per default, ∫∞−∞f(x)dx=1∫−∞∞f(x)dx=1.
    # But because of the limited kernel array size, the normalization
    # for kernels with an infinite response can differ from one.
    kernel.normalize()
    # obtain a  SegmentationImage object with the same shape as the data,
    # where sources are labeled by different positive integer values.
    # A value of zero is always reserved for the background.
    # if the threshold includes the background level as above, then the image
    # input into detect_sources() should not be background subtracted.
    print('Segmentation processing...')
    segm = detect_sources(data, threshold, npixels=5, filter_kernel=kernel)
    print('Segmentation labels are: ', repr(segm.labels))

    # === Measure regional source properties ===

    # source_properties() assumes that the data have been background-subtracted.
    # Background is the background level that was previously present
    # in the input data.
    # The input background does not get subtracted from the input data,
    # which should already be background-subtracted.
    print('Extracting source properties...')
    props = source_properties(data - bkg_median, segm, background=bkg_median)
    # add flux and instrumental magnitude to properties
    # flux = source_sum / exptime
    # instrumental magnitude = -2.5 * log10(flux)
    for i in range(len(props)):
        # source_sum is by definition background-subtracted already
        props[i].flux = props[i].source_sum / exptime
        props[i].mag_instr = -2.5 * np.log10(props[i].flux)
    # make plots and save to images
    # define approximate isophotal ellipses for each object
    apertures = []
    r = 2.8  # approximate isophotal extent
    for prop in props:
        position = (prop.xcentroid.value, prop.ycentroid.value)
        a = prop.semimajor_axis_sigma.value * r
        b = prop.semiminor_axis_sigma.value * r
        theta = prop.orientation.value
        apertures.append(EllipticalAperture(position, a, b, theta=theta))

    # create a table of properties
    try:
        props_table = properties_table(props)
    except:
        print('No source detected in {}'.format(path_file_abs))
        return [None, None]

    props_table['flux'] = [props[i].flux for i in range(len(props))]
    props_table['mag_instr'] = [props[i].mag_instr for i in range(len(props))]
    # add custom columns to the table: mag_instru and flux

    # plot centroid and segmentation using approximate elliptical apertures
    norm = mpl_normalize.ImageNormalize(stretch=LogStretch())
    rand_cmap = random_cmap(segm.max + 1, random_state=12345)
    #[fig1, (ax1, ax2)] = plt.subplots(1, 2, figsize = (12, 6))
    #ax1.imshow(data, origin='lower', cmap=plt.cm.gray, norm=norm)
    #ax1.plot(
    #        props_table['xcentroid'], props_table['ycentroid'],
    #        ls='none', color='blue', marker='+', ms=10, lw=1.5)
    #ax2.imshow(segm, origin='lower', cmap=rand_cmap)
    #for aperture in apertures:
    #    aperture.plot(ax=ax1, lw=1.0, alpha=1.0, color='red')
    #    aperture.plot(ax=ax2, lw=1.0, alpha=1.0, color='red')
    # plot using actual segmentation outlines (to be improved)
    #[fig2, ax3] = plt.subplots(figsize = (6, 6))
    #ax3.imshow(data, origin='lower', cmap=plt.cm.gray, norm=norm)
    #segm_outline = np.array(segm.outline_segments(), dtype=float)
    #segm_outline[segm_outline<1] = np.nan
    # get a copy of the gray color map
    #segm_outline_cmap = copy.copy(plt.cm.get_cmap('autumn'))
    # set how the colormap handles 'bad' values
    #segm_outline_cmap.set_bad(alpha=0)
    #ax3.imshow(segm_outline, origin='lower', cmap=segm_outline_cmap)

    # === save ===
    # Save segm, porps to object files, and also save props to table file.
    print('Saving segmentation and source propdderties to {}...'.format(
        dir_save))
    try:
        # if filename ends with fits, remove it in the  filename
        if filename[-5:] == '.fits':
            dir_save_prefix = os.path.join(dir_save, filename[0:-5])
        else:
            dir_save_prefix = os.path.join(dir_save, filename)
        # Enhanced CSV allows preserving table meta-data such as
        # column data types and units.
        # In this way a data table can be stored and read back as ASCII
        # with no loss of information.
        ascii.write(props_table,
                    dir_save_prefix + '-phot_props.ecsv',
                    format='ecsv')
        # csv for readability in MS excel
        ascii.write(props_table,
                    dir_save_prefix + '-phot_props.csv',
                    format='csv')

        # dump segmentation and properties to object files in binary mode
        file_segm = open(dir_save_prefix + '-phot_segm.obj', 'wb')
        pickle.dump(segm, file_segm)
        file_props = open(dir_save_prefix + '-phot_props.obj', 'wb')
        pickle.dump(props, file_props)

        # save figures
        #fig1.savefig(dir_save_prefix + '-phot_segm_fig1.png', dpi=600)
        #pp1 = PdfPages(dir_save_prefix + '-phot_segm_fig1.pdf')
        #pp1.savefig(fig1)
        #pp1.close()

        #fig2.savefig(dir_save_prefix + '-phot_segm_fig2.png', dpi=600)
        #pp2 = PdfPages(dir_save_prefix + '-phot_segm_fig2.pdf')
        #pp2.savefig(fig2)
        #pp2.close()

        print('Segmentation, properties objects, tables, and images saved to',
              dir_save)
    except:
        print('Unable to write to disk, check permissions.')

    return [segm, props]
	
	""" We have run through all of the images now. """
	
	allSources = []
	sourceList = ultraspecClasses.sourceList()
	for index, w in enumerate(allWindows):
		xll = w.xll/w.xbin - xmin
		yll = w.yll/w.ybin - ymin
		image = w.stackedData
		mean, median, std = sigma_clipped_stats(image, sigma=3.0)
		maximum = numpy.max(image)
		minimum = numpy.min(image)
		debug.write("Mean: %f,  Median: %f,  Std (clipped 3sigma):%f"%(mean, median, std) , 2)
		debug.write("Minimum: %f,  Maximum: %f"%(minimum, maximum), 2)
		threshold = median + (std * 2.)
		segm_img = detect_sources(image, threshold, npixels=5)
		mask = segm_img.astype(numpy.bool)
		mean, median, std = sigma_clipped_stats(image, sigma=3.0, mask=mask) 
		debug.write("After source masking", 2)
		debug.write("Mean: %f,  Median: %f,  Std (clipped 3sigma): %f"%(mean, median, std), 2)
		selem = numpy.ones((5, 5))    # dilate using a 5x5 box
		mask2 = binary_dilation(mask, selem)
		mean, median, std = sigma_clipped_stats(image, sigma=3.0, mask=mask2)
		debug.write("After dilation", 2)
		debug.write("Mean: %f,  Median: %f,  Std (clipped 3sigma): %f"%(mean, median, std), 2)
		
		# Check the window image for any areas that should be masked...
		lowerLimitBkg = median - std*5.
		debug.write("5 sigma below the median is the lowerLimitBkg for the mask: %f"%(lowerLimitBkg), 2)
		mask = (image < lowerLimitBkg)
		maskBitmap = numpy.zeros(numpy.shape(mask))
示例#6
0
def bkg_boxes(hdu,nboxes,length,sources):
  """
  Function to calculate the sigma clipped statistics
  of a number of randomly generated boxes
  Variables:
  frame: fits image 
  nboxes: number of boxes to generate
  length: length of side of box in pixels
  sources: if sources = True, the sources in each box will be detected and masked
           if sources = False, no masking is done 
  """
  #hdu = pyfits.open(frame,memmap=True)
  image = hdu.data
  
  
  
  #Get length of image in each axis
  naxis1 = hdu.header['NAXIS1']
  naxis2 = hdu.header['NAXIS2']
  
  #generate the centers of 1000 random boxes.
  #np.random.seed(1234)
  # box_centers = np.random.random_integers(0,np.min([naxis1,naxis2]),size=(nboxes,2))
  
  # use np.random.randint() instead due to deprecation error on wopr
  box_centers = np.random.randint(0,np.min([naxis1,naxis2]),size=(nboxes,2))
  
  #divide length by 2
  # side = float(length)/2.0
  # another numpy error on wopr (can't convert to integer), so don't worry about integer arithmetic
  side = length/2
  
  bg_stats = []
  centers = []
  for center in range(len(box_centers)):
    x1 = box_centers[center][0]-side
    x2 = box_centers[center][0]+side
    y1 = box_centers[center][1]-side
    y2 = box_centers[center][1]+side
    
    #Check to ensure that box is within image
    if (x1 > side and x2 < naxis1-side) and (y1 > side and y2 < naxis2-side):
      centers.append(box_centers[center])
      """
      The centers that are within the image bounds are returned
      in case you need to examine the regions used.
      """      
      box = image[x1:x2,y1:y2]
      
      # Mask gaps
      #gaps_mask = np.isnan(box).astype(int)
      # Mask hot pixels count greater than 58000
      #hot_pix_mask = (box > 58000.0).astype(int)
      # Mask dead pixels
      #dead_pix_mask = (box < 1.0).astype(int)

      
      #mask_first_pass = hot_pix_mask + dead_pix_mask + gaps_mask
      
      #if (box >= 0).all() == True:
      if np.isnan(box).any() == False:
       """
       Only boxes with non-negative values are kept.
       This should help deal with cell gaps
       The sigma and iter values might need some tuning.
       """
       mean, median, std = sigma_clipped_stats(box, sigma=3.0)
       if sources == False:
           bg_stats.append((mean, median, std))
       if sources == True:
           threshold = median + (std * 2.)
           segm_img = detect_sources(box, threshold, npixels=20)
           mask = segm_img.data.astype(np.bool)# turn segm_img into a mask
           selem = np.ones((10, 10))    # dilate using a 25x25 box
           mask2 = binary_dilation(mask, selem)
           #new_mask = mask_first_pass + mask2
           new_mask = mask2
           
           mean_mask, median_mask, std_mask = sigma_clipped_stats(box, sigma=3.0, mask=new_mask)
           bg_stats.append((mean_mask, median_mask, std_mask))
           
  bg_stats = np.reshape(np.array(bg_stats),(len(bg_stats),3))
  centers = np.reshape(np.array(centers),(len(centers),2))
  
  #Calculate median std of Background
  med_std = np.median(bg_stats[:,2])
  #calculate standard deviation of the std values
  std_std = np.std(bg_stats[:,2])
  #median
  bg_median = np.median(bg_stats[:,1])
  
  #Locate the box that had the largest std
  #Array will be returned for plotting if wanted
  max_std = np.argmax(bg_stats[:,2])
  max_center = centers[max_std]
  max_box = image[max_center[0]-side:max_center[0]+side,max_center[1]-side:max_center[1]+side]
  #plt.imshow(max_box,origin='lower', cmap='Greys_r')
  #plt.show()
 
  return bg_stats,bg_median,med_std,std_std,centers,max_box