def __init__(self, image_data=None, interpolation_order=3): super(self.__class__, self).__init__() self.image = image_data self.interpolation_order = interpolation_order if self.image is not None: self.mdh = NestedClassMDHandler(self.image.mdh) else: self.mdh = None
def mdh(self): mdh = NestedClassMDHandler(self._mdh) mdh['Pyramid.Depth'] = self.depth mdh['Pyramid.NTilesX'] = self.n_tiles_x mdh['Pyramid.NTilesY'] = self.n_tiles_y mdh['Pyramid.PixelsX'] = self.n_tiles_x * self.tile_size mdh['Pyramid.PixelsY'] = self.n_tiles_y * self.tile_size return mdh
def __init__(self, storage_directory, pyramid_tile_size=256, mdh=None, n_tiles_x=0, n_tiles_y=0, depth=0, x0=0, y0=0, pixel_size=1, backend=PZFTileIO): if isinstance(storage_directory, tempfile.TemporaryDirectory): # If the storage directory is a temporary directory, keep a reference and cleanup the directory when we delete the pyramid # used to support transitory pyramids. self._temp_directory = storage_directory storage_directory = storage_directory.name if unifiedIO.is_cluster_uri(storage_directory): assert (backend == ClusterPZFTileIO) storage_directory, _ = unifiedIO.split_cluster_url( storage_directory) self.base_dir = storage_directory self.tile_size = pyramid_tile_size self.pyramid_valid = False self._mdh = NestedClassMDHandler(mdh) self._mdh['Pyramid.TileSize'] = self.tile_size self.n_tiles_x = n_tiles_x self.n_tiles_y = n_tiles_y self.depth = depth self.x0 = x0 self.y0 = y0 self.pixel_size = pixel_size # TODO - should we be re-assigning these on load, not just when we create a new pyramid? self._mdh['Pyramid.x0'] = x0 self._mdh['Pyramid.y0'] = y0 self._mdh['Pyramid.PixelSize'] = pixel_size if (not os.path.exists(self.base_dir)) and (not backend == ClusterPZFTileIO): os.makedirs(self.base_dir) #self._tilecache = TileCache() if backend is None: backend = infer_tileio_backend(self.base_dir) self._imgs = backend(base_dir=self.base_dir, suff='img') self._acc = backend(base_dir=self.base_dir, suff='acc') self._occ = backend(base_dir=self.base_dir, suff='occ')
def OnGenEvents(self, event): from PYME.simulation import locify #from PYME.Acquire.Hardware.Simulator import wormlike2 from PYME.IO import tabular from PYME.IO.image import ImageBounds # import pylab import matplotlib.pyplot as plt #wc = wormlike2.wormlikeChain(100) pipeline = self.visFr.pipeline pipeline.filename='Simulation' plt.figure() plt.plot(self.xp, self.yp, 'x') #, lw=2) if isinstance(self.source, WormlikeSource): plt.plot(self.xp, self.yp, lw=2) if self.mode == 'STORM': res = locify.eventify(self.xp, self.yp, self.meanIntensity, self.meanDuration, self.backgroundIntensity, self.meanEventNumber, self.scaleFactor, self.meanTime, z=self.zp) else: res = locify.eventify2(self.xp, self.yp, self.meanIntensity, self.meanDuration, self.backgroundIntensity, self.meanEventNumber, self.scaleFactor, self.meanTime, z=self.zp) plt.plot(res['fitResults']['x0'],res['fitResults']['y0'], '+') ds = tabular.MappingFilter(tabular.FitResultsSource(res)) if isinstance(self.source, ImageSource): pipeline.imageBounds = image.openImages[self.source.image].imgBounds else: pipeline.imageBounds = ImageBounds.estimateFromSource(ds) pipeline.addDataSource('Generated Points', ds) pipeline.selectDataSource('Generated Points') from PYME.IO.MetaDataHandler import NestedClassMDHandler pipeline.mdh = NestedClassMDHandler() pipeline.mdh['Camera.ElectronsPerCount'] = 1 pipeline.mdh['Camera.TrueEMGain'] = 1 pipeline.mdh['Camera.CycleTime'] = 1 pipeline.mdh['voxelsize.x'] = .110 try: pipeline.filterKeys.pop('sig') except: pass pipeline.Rebuild() if len(self.visFr.layers) < 1: self.visFr.add_pointcloud_layer() #TODO - move this logic so that layer added automatically when datasource is added? #self.visFr.CreateFoldPanel() self.visFr.SetFit()
def nPhotons(fitMod,fr,mdh,psfname=None,nmax=100,progressBar=None,updateStep=100): mdh2 = NestedClassMDHandler(mdh) if psfname is not None: mdh2['PSFFile'] = psfname npoints = min(fr.shape[0],nmax) nph = np.zeros((npoints)) us = int(updateStep) for i in range(npoints): nph[i] = get_photons(genFitImage(fitMod,fr[i],mdh2,psfname=None), mdh2) if (progressBar is not None) and ((i % us) == 0): progressBar.Update(100.0*i/float(npoints)) wx.Yield() return nph
def rebuild(self, event=None): self.tree.DeleteRoot() self.root = self.tree.AddRoot("Metadata") self.tree.SetItemText(self.root, "root", 0) nmdh = NestedClassMDHandler(self.mdh) self.addEntries(nmdh, self.root) if wx.__version__ > '4': self.tree.ExpandAll() #self.root) else: self.tree.ExpandAll(self.root)
def generate_uniform_map(source): logger.warning('Simulating uniform maps - use with care') sensorSize = get_sensor_size(source.mdh) mfull, vefull, mapmdh = insert_into_full_map(None, None, source.mdh, sensor_size=sensorSize) mapmdh['CameraMap.Uniform'] = True mmd = NestedClassMDHandler(mapmdh) mmd['CameraMap.Type'] = 'mean' mmd['CameraMap.Units'] = 'ADU' vmd = NestedClassMDHandler(mapmdh) vmd['CameraMap.Type'] = 'variance' vmd['CameraMap.Units'] = 'electrons^2' im_dark = ImageStack(mfull, mdh=mmd) im_variance = ImageStack(vefull, mdh=vmd) return im_dark, im_variance
def get_psf(): from PYME.IO.image import ImageStack from PYME.IO.MetaDataHandler import NestedClassMDHandler mdh = NestedClassMDHandler() mdh['ImageType'] = 'PSF' mdh['voxelsize.x'] = dx / 1e3 mdh['voxelsize.y'] = dy / 1e3 mdh['voxelsize.z'] = dz / 1e3 im = ImageStack(data=[c for c in interpModel_by_chan if not c is None], mdh=mdh, titleStub='Simulated PSF') return im
def OnProcPoints(self, event=None): try: points = self.dsviewer.view.points except AttributeError: Warn(None, 'no object locations found') return if len(self.dsviewer.view.points) < 1: Warn(None, 'object location list empty') return if not self.procPtsSel.configure_traits(kind='modal'): return xp = np.rint(self.dsviewer.view.points[:, 0]) yp = np.rint(self.dsviewer.view.points[:, 1]) mindistnm = self.procPtsSel.minimal_distance_in_nm # make this an option mindistpix = mindistnm / (1e3 * self.dsviewer.image.mdh.voxelsize.x) # here we need some code to remove points with NND < mindist xd = np.subtract.outer(xp, xp) yd = np.subtract.outer(yp, yp) d = np.sqrt(xd**2 + yd**2) np.fill_diagonal(d, 1e6) dmin = d.min(0) xp2 = xp[dmin >= mindistpix] yp2 = yp[dmin >= mindistpix] imd = np.zeros(self.dsviewer.image.data.shape[0:2]) imd[xp2.astype('i'), yp2.astype('i')] = 1 sigma = self.procPtsSel.sigma_for_Gaussian_blur # in future may make this a config parameter imf = gaussian_filter(imd, sigma) im = ImageStack(imf, titleStub='object positions') mdh2 = NestedClassMDHandler(self.dsviewer.image.mdh) im.mdh.copyEntriesFrom(mdh2) if self.dsviewer.mode == 'visGUI': mode = 'visGUI' else: mode = 'lite' dv = ViewIm3D(im, mode=mode, glCanvas=self.dsviewer.glCanvas, parent=wx.GetTopLevelParent(self.dsviewer))
def prefillSampleData(parent): #global currentSlide global slideMD dlg = SampleInfoDialog(parent, acquiring=False) slideMD = NestedClassMDHandler( ) # provide a new clean copy - otherwise we keep unset fields from last run if dlg.ShowModal() == wx.ID_OK: dlg.PopulateMetadata(slideMD, False) # print slideMD print('bar') print((dlg.slide)) currentSlide[0] = dlg.slide print(currentSlide) else: currentSlide[0] = None dlg.Destroy()
def execute(self, namespace): from PYME.Analysis.points import spherical_harmonics from PYME.IO.MetaDataHandler import NestedClassMDHandler inp = namespace[self.inputName] mapped = tabular.MappingFilter(inp) rep = namespace[self.inputSphericalHarmonics] center = rep.mdh['Processing.SphericalHarmonicShell.Centre'] z_scale = rep.mdh['Processing.SphericalHarmonicShell.ZScale'] x0, y0, z0 = center # calculate theta, phi, and rad for each localization in the pipeline theta, phi, datRad = spherical_harmonics.cart2sph( inp['x'] - x0, inp['y'] - y0, (inp['z'] - z0) / z_scale) # additionally calculate the cartesian distance min_distance, nearest_point_on_shell = spherical_harmonics.distance_to_surface( [inp['x'], inp['y'], inp['z']], center, rep['modes'], rep['coefficients'], z_scale=z_scale) mapped.addColumn(self.input_name_r, datRad) mapped.addColumn(self.input_name_theta, theta) mapped.addColumn(self.input_name_phi, phi) mapped.addColumn( self.input_name_r_norm, datRad / spherical_harmonics.reconstruct_from_modes( rep['modes'], rep['coefficients'], theta, phi)) mapped.addColumn(self.input_name_distance_to_shell, min_distance) try: # note that copying overwrites shared fields mapped.mdh = NestedClassMDHandler(rep.mdh) mapped.mdh.copyEntriesFrom(inp.mdh) except AttributeError: pass namespace[self.outputName] = mapped
def OnExtractMultiviewPSF(self, event): if (len(self.PSFLocs) > 0): from PYME.Analysis.PSFEst import extractImages psfROISize = [int(s) for s in self.tPSFROI.GetValue().split(',')] psfBlur = [float(s) for s in self.tPSFBlur.GetValue().split(',')] psfs = [] for chnum in range(self.image.data.shape[3]): alignZ = (chnum > 0) and self.cbAlignZ.GetValue() #always align the first channel psf, offsets = extractImages.getPSF3D( self.image.data[:, :, :, chnum], self.PSFLocs, psfROISize, psfBlur, centreZ=alignZ, expand_z=self.cbExpandROI.GetValue()) if self.cbBackgroundCorrect.GetValue(): #widefield image - do special background subtraction psf = extractImages.backgroundCorrectPSFWF(psf) psfs.append(psf) from PYME.DSView.dsviewer import ImageStack, ViewIm3D from PYME.IO.MetaDataHandler import NestedClassMDHandler mdh = NestedClassMDHandler(self.image.mdh) self.write_metadata(mdh, 'Multiview') mdh['ImageType'] = 'PSF' im = ImageStack(data=psfs, mdh=mdh, titleStub='Extracted PSF') im.defaultExt = '*.tif' #we want to save as PSF by default ViewIm3D(im, mode='psf', parent=wx.GetTopLevelParent(self.dsviewer))
def __init__(self, storage_directory, pyramid_tile_size=256, mdh=None, n_tiles_x=0, n_tiles_y=0, depth=0, x0=0, y0=0, pixel_size=1): self.base_dir = storage_directory self.tile_size = pyramid_tile_size self.pyramid_valid = False self._mdh = NestedClassMDHandler(mdh) self._mdh['Pyramid.TileSize'] = self.tile_size self.n_tiles_x = n_tiles_x self.n_tiles_y = n_tiles_y self.depth = depth self.x0 = x0 self.y0 = y0 self.pixel_size = pixel_size # TODO - should we be re-assigning these on load, not just when we create a new pyramid? self._mdh['Pyramid.x0'] = x0 self._mdh['Pyramid.y0'] = y0 self._mdh['Pyramid.PixelSize'] = pixel_size if not os.path.exists(self.base_dir): os.makedirs(self.base_dir) #self._tilecache = TileCache() self._imgs = PZFTileIO(base_dir=self.base_dir, suff='img') self._acc = PZFTileIO(base_dir=self.base_dir, suff='acc') self._occ = PZFTileIO(base_dir=self.base_dir, suff='occ')
def OnGenEvents(self, event): from PYME.simulation import locify #from PYME.Acquire.Hardware.Simulator import wormlike2 from PYME.IO import tabular from PYME.IO.image import ImageBounds # import pylab import matplotlib.pyplot as plt #wc = wormlike2.wormlikeChain(100) pipeline = self.visFr.pipeline pipeline.filename = 'Simulation' plt.figure() plt.plot(self.xp, self.yp, 'x') #, lw=2) if isinstance(self.source, WormlikeSource): plt.plot(self.xp, self.yp, lw=2) if self.mode == 'STORM': res = locify.eventify(self.xp, self.yp, self.meanIntensity, self.meanDuration, self.backgroundIntensity, self.meanEventNumber, self.scaleFactor, self.meanTime, z=self.zp) else: res = locify.eventify2(self.xp, self.yp, self.meanIntensity, self.meanDuration, self.backgroundIntensity, self.meanEventNumber, self.scaleFactor, self.meanTime, z=self.zp) plt.plot(res['fitResults']['x0'], res['fitResults']['y0'], '+') ds = tabular.MappingFilter(tabular.FitResultsSource(res)) try: # some data sources (current ImageSource) have image bound info. Use this if available # this could fail on either an AttributeError (if the data source doesn't implement bounds # or another error if something fails in get_bounds(). Only catch the AttributeError, as we have # should not be handling other errors here. pipeline.imageBounds = self.source.get_bounds() except AttributeError: pipeline.imageBounds = ImageBounds.estimateFromSource(ds) pipeline.addDataSource('Generated Points', ds) pipeline.selectDataSource('Generated Points') from PYME.IO.MetaDataHandler import NestedClassMDHandler pipeline.mdh = NestedClassMDHandler() pipeline.mdh['Camera.ElectronsPerCount'] = 1 pipeline.mdh['Camera.TrueEMGain'] = 1 pipeline.mdh['Camera.CycleTime'] = 1 pipeline.mdh['voxelsize.x'] = .110 # some info about the parameters pipeline.mdh['GeneratedPoints.MeanIntensity'] = self.meanIntensity pipeline.mdh['GeneratedPoints.MeanDuration'] = self.meanDuration pipeline.mdh['GeneratedPoints.MeanEventNumber'] = self.meanEventNumber pipeline.mdh[ 'GeneratedPoints.BackgroundIntensity'] = self.backgroundIntensity pipeline.mdh['GeneratedPoints.ScaleFactor'] = self.scaleFactor pipeline.mdh['GeneratedPoints.MeanTime'] = self.meanTime pipeline.mdh['GeneratedPoints.Mode'] = self.mode # the source info self.source.genMetaData(pipeline.mdh) try: pipeline.filterKeys.pop('sig') except: pass pipeline.Rebuild() if len(self.visFr.layers) < 1: self.visFr.add_pointcloud_layer( ) #TODO - move this logic so that layer added automatically when datasource is added? #self.visFr.CreateFoldPanel() self.visFr.SetFit()
def execute(self, namespace): from PYME.Analysis.points import twoColour from PYME.Analysis.points import multiview from PYME.IO.MetaDataHandler import NestedClassMDHandler inp = namespace[self.input_name] try: # make sure we're looking at multiview data n_chan = inp.mdh['Multiview.NumROIs'] except AttributeError: raise AttributeError('multiview metadata is missing or incomplete') # sort in frame order I = inp['tIndex'].argsort() x_sort, y_sort = inp['x'][I], inp['y'][I] chan_sort = inp['multiviewChannel'][I] clump_id, keep = multiview.pair_molecules( inp['tIndex'][I], x_sort, y_sort, chan_sort, self.search_radius_nm * np.ones_like(x_sort), appear_in=np.arange(n_chan), n_frame_sep=inp['tIndex'].max(), pix_size_nm=1e3 * inp.mdh['voxelsize.x']) # only look at the clumps which showed up in all channels x = x_sort[keep] y = y_sort[keep] chan = chan_sort[keep] clump_id = clump_id[keep] # Generate raw shift vectors (map of displacements between channels) for each channel mol_list = np.unique(clump_id) n_mols = len(mol_list) dx = np.zeros((n_chan - 1, n_mols)) dy = np.zeros_like(dx) dx_err = np.zeros_like(dx) dy_err = np.zeros_like(dx) x_clump, y_clump, x_std, y_std, x_shifted, y_shifted = [], [], [], [], [], [] shift_map_dtype = [ ('mx', '<f4'), ('mx2', '<f4'), ('mx3', '<f4'), # x terms ('my', '<f4'), ('my2', '<f4'), ('my3', '<f4'), # y terms ('mxy', '<f4'), ('mx2y', '<f4'), ('mxy2', '<f4'), # cross terms ('x0', '<f4') ] # 0th order shift shift_maps = np.zeros(2 * (n_chan - 1), dtype=shift_map_dtype) mdh = NestedClassMDHandler(inp.mdh) mdh['Multiview.shift_map.legend'] = {} for ii in range(n_chan): chan_mask = (chan == ii) x_chan = np.zeros(n_mols) y_chan = np.zeros(n_mols) x_chan_std = np.zeros(n_mols) y_chan_std = np.zeros(n_mols) for ind in range(n_mols): # merge clumps within channels clump_mask = np.where( np.logical_and(chan_mask, clump_id == mol_list[ind])) x_chan[ind] = x[clump_mask].mean() y_chan[ind] = y[clump_mask].mean() x_chan_std[ind] = x[clump_mask].std() y_chan_std[ind] = y[clump_mask].std() x_clump.append(x_chan) y_clump.append(y_chan) x_std.append(x_chan_std) y_std.append(y_chan_std) if ii > 0: dx[ii - 1, :] = x_clump[0] - x_clump[ii] dy[ii - 1, :] = y_clump[0] - y_clump[ii] dx_err[ii - 1, :] = np.sqrt(x_std[ii]**2 + x_std[0]**2) dy_err[ii - 1, :] = np.sqrt(y_std[ii]**2 + y_std[0]**2) # generate shiftmap between ii-th channel and the 0th channel dxx, dyy, spx, spy, good = twoColour.genShiftVectorFieldQ( x_clump[0], y_clump[0], dx[ii - 1, :], dy[ii - 1, :], dx_err[ii - 1, :], dy_err[ii - 1, :]) # store shiftmaps in structured array mdh['Multiview.shift_map.legend']['Chan0%s.X' % ii] = 2 * (ii - 1) mdh['Multiview.shift_map.legend']['Chan0%s.Y' % ii] = 2 * (ii - 1) + 1 for ki in range(len(shift_map_dtype)): k = shift_map_dtype[ki][0] shift_maps[2 * (ii - 1)][k] = spx.__getattribute__(k) shift_maps[2 * (ii - 1) + 1][k] = spy.__getattribute__(k) # shift_maps['Chan0%s.X' % ii], shift_maps['Chan0%s.Y' % ii] = spx.__dict__, spy.__dict__ mdh['Multiview.shift_map.model'] = '.'.join( [spx.__class__.__module__, spx.__class__.__name__]) namespace[self.output_name] = tabular.RecArraySource(shift_maps) namespace[self.output_name].mdh = mdh
def __init__(self, parent, mdh, editable=True, refreshable=True): self.mdh = mdh wx.Panel.__init__(self, parent, -1) #self.Bind(wx.EVT_SIZE, self.OnSize) sizer1 = wx.BoxSizer(wx.VERTICAL) self.tree = MyTreeListCtrl( self, -1, style=wx.TR_DEFAULT_STYLE #| wx.TR_HAS_BUTTONS #| wx.TR_TWIST_BUTTONS #| wx.TR_ROW_LINES | wx.TR_EDIT_LABELS #| wx.TR_COLUMN_LINES #| wx.TR_NO_LINES | wx.TR_FULL_ROW_HIGHLIGHT) # create some columns self.tree.AddColumn("Entry") self.tree.AddColumn("Value") self.tree.SetMainColumn(0) # the one with the tree in it... self.tree.SetColumnWidth(0, 300) self.tree.SetColumnWidth(1, 300) self.root = self.tree.AddRoot("Metadata") self.tree.SetItemText(self.root, "root", 0) self.paths = {} nmdh = NestedClassMDHandler(mdh) self.addEntries(nmdh, self.root) if editable: self.editableCols = [1] else: self.editableCols = [] #entryNames = self.mdh.getEntryNames() # for k in nmdh.__dict__.keys(): # #txt = "Item %d" % x # child = self.tree.AppendItem(self.root, k) # self.tree.SetItemText(child, txt + "(c1)", 1) if wx.__version__ > '4': self.tree.ExpandAll() #self.root) else: self.tree.ExpandAll(self.root) #self.tree.GetMainWindow().Bind(wx.EVT_LEFT_DOWN, self.OnRightDown) self.tree.GetMainWindow().Bind(wx.EVT_LEFT_UP, self.OnRightUp) self.tree.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnEndEdit) self.tree.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnBeginEdit) #self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivate) sizer1.Add(self.tree, 1, wx.EXPAND, 0) if refreshable: bRefresh = wx.Button(self, -1, 'Refresh') bRefresh.Bind(wx.EVT_BUTTON, self.rebuild) sizer1.Add(bRefresh, 0, wx.ALL | wx.ALIGN_RIGHT, 5) self.SetSizerAndFit(sizer1)
def main(): logging.basicConfig( ) # without it got 'No handlers could be found for logger...' defaultSensorSize = ( 2048, 2048 ) # we currently assume this is correct but could be chosen based # on camera model in meta data TODO - add CCD size to camera metadata darkthreshold = 1e4 # this really should depend on the gain mode (12bit vs 16 bit etc) variancethreshold = 300**2 # again this is currently picked fairly arbitrarily blemishvariance = 1e8 # options parsing op = argparse.ArgumentParser( description='generate offset and variance maps from darkseries.') op.add_argument('filename', metavar='filename', nargs='?', default=None, help='filename of the darkframe series') op.add_argument('-s', '--start', type=int, default=0, help='start frame to use') op.add_argument('-e', '--end', type=int, default=-1, help='end frame to use') op.add_argument('-u', '--uniform', action='store_true', help='make uniform map using metadata info') op.add_argument( '-i', '--install', action='store_true', help='install map in default location - the filename argument is a map' ) op.add_argument( '-d', '--dir', metavar='destdir', default=None, help='destination directory (default is PYME calibration path)') op.add_argument('-l', '--list', action='store_true', help='list all maps in default location') op.add_argument('-p', '--prefix', metavar='prefix', default='', help='prefix for dark/variance map filenames') args = op.parse_args() if args.list: listCalibrationDirs() sys.exit(0) # body of script filename = args.filename prefix = args.prefix if filename is None: op.error('need a file name if -l or --list not requested') if args.install: #copy the map to the default maps directory install_map(filename) sys.exit(0) logger.info('Opening image series...') source = ImageStack(filename=filename) start = args.start end = args.end if end < 0: end = int(source.dataSource.getNumSlices() + end) # pre-checks before calculations to minimise the pain sensorSize = list(defaultSensorSize) try: sensorSize[0] = source.mdh['Camera.SensorWidth'] except AttributeError: logger.warning('no valid sensor width in metadata - using default %d' % sensorSize[0]) try: sensorSize[1] = source.mdh['Camera.SensorHeight'] except AttributeError: logger.warning( 'no valid sensor height in metadata - using default %d' % sensorSize[1]) if not ((source.mdh['Camera.ROIWidth'] == sensorSize[0]) and (source.mdh['Camera.ROIHeight'] == sensorSize[1])): logger.warning( 'Generating a map from data with ROI set. Use with EXTREME caution.\nMaps should be calculated from the whole chip.' ) if args.dir is None: logger.error( 'Maps with an ROI set cannot be stored to the default map directory\nPlease specify an output directory.' ) sys.exit(-1) logger.info('Calculating mean and variance...') m, ve = (None, None) if not args.uniform: m, v = _meanvards(source.dataSource, start=start, end=end) eperADU = source.mdh['Camera.ElectronsPerCount'] ve = v * eperADU * eperADU # occasionally the cameras seem to have completely unusable pixels # one example was dark being 65535 (i.e. max value for 16 bit) if m.max() > darkthreshold: ve[m > darkthreshold] = blemishvariance if ve.max() > variancethreshold: ve[ve > variancethreshold] = blemishvariance nbad = np.sum((m > darkthreshold) * (ve > variancethreshold)) else: logger.warning('Simulating uniform maps - use with care') nbad = 0 if args.dir is None: logger.error( 'Uniform maps cannot be stored to the default map directory\nPlease specify an output directory.' ) sys.exit(-1) # if the uniform flag is set, then m and ve are passed as None # which makes sure that just the uniform defaults from meta data are used mfull, vefull, basemdh = insert_into_full_map(m, ve, source.mdh, sensor_size=sensorSize) logger.info('Saving results...') if args.dir is None: logger.info('installing in standard location...') mname = mkDefaultPath('dark', source.mdh) vname = mkDefaultPath('variance', source.mdh) else: mname = mkDestPath(args.dir, prefix + 'dark', source.mdh) vname = mkDestPath(args.dir, prefix + 'variance', source.mdh) logger.info('dark map -> %s...' % mname) logger.info('var map -> %s...' % vname) commonMD = NestedClassMDHandler() commonMD.setEntry('Analysis.name', 'mean-variance') commonMD.setEntry('Analysis.start', start) commonMD.setEntry('Analysis.end', end) commonMD.setEntry('Analysis.SourceFilename', filename) commonMD.setEntry('Analysis.darkThreshold', darkthreshold) commonMD.setEntry('Analysis.varianceThreshold', variancethreshold) commonMD.setEntry('Analysis.blemishVariance', blemishvariance) commonMD.setEntry('Analysis.NBadPixels', nbad) if args.uniform: commonMD.setEntry('Analysis.isuniform', True) mmd = NestedClassMDHandler(basemdh) mmd.copyEntriesFrom(commonMD) mmd.setEntry('Analysis.resultname', 'mean') mmd.setEntry('Analysis.units', 'ADU') vmd = NestedClassMDHandler(basemdh) vmd.copyEntriesFrom(commonMD) vmd.setEntry('Analysis.resultname', 'variance') vmd.setEntry('Analysis.units', 'electrons^2') ImageStack(mfull, mdh=mmd).Save(filename=mname) ImageStack(vefull, mdh=vmd).Save(filename=vname)
from PYME.contrib import TextCtrlAutoComplete #from PYME.SampleDB2 import populate #just to setup the Django environment #from PYME.SampleDB2.samples import models lastCreator = nameUtils.getUsername() lastSlideRef = '' currentSlide = [None] WantSlideChangeNotification = [] from PYME.IO import MetaDataHandler from PYME.IO.MetaDataHandler import NestedClassMDHandler slideMD = NestedClassMDHandler() if 'PYME_DATABASE_HOST' in os.environ.keys(): dbhost = os.environ['PYME_DATABASE_HOST'] else: dbhost = 'dbsrv1' class AutoWidthListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin): def __init__(self, parent, ID, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0): wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
# name = 'Andor IXon DV97' # ADOffset = 1100 #counts (@ T ~ -70, em gain ~ 150) # ReadNoise = 109.8 #electrons # noiseFactor = 1.41 # electronsPerCount = 27.32 # # #class MetaData: # def __init__(self, voxSize, CCDMD = None): # self.voxelsize = voxSize # self.CCD = CCDMD # ##FIXME - THIS SHOULD ALL BE EXTRACTED FROM LOG FILES OR THE LIKE #TIRFDefault = MetaData(VoxelSize(0.07, 0.07, 0.2), CCDMetaDataIXonDefault()) TIRFDefault = NestedClassMDHandler() #voxelsize TIRFDefault.setEntry('voxelsize.x', 0.07) TIRFDefault.setEntry('voxelsize.y', 0.07) TIRFDefault.setEntry('voxelsize.z', 0.2) TIRFDefault.setEntry('voxelsize.units', 'um') #camera properties - for Andor camera - see above #TIRFDefault.setEntry('Camera.ADOffset',1100) TIRFDefault.setEntry('Camera.ReadNoise', 109.8) TIRFDefault.setEntry('Camera.NoiseFactor', 1.41) TIRFDefault.setEntry('Camera.ElectronsPerCount', 27.32) TIRFDefault.setEntry( 'Camera.TrueEMGain', 20 ) #mostly use gain register setting of 150 - this will hopefully be overwitten
def insert_into_full_map(dark, variance, metadata, sensor_size=(2048, 2048)): """ Embeds partial-sensor camera maps into full-sized camera map by padding with basic values in metadata. Alternatively can be used to create boring maps to use in place of metadata scalars. Parameters ---------- dark: ndarray or None darkmap for valid ROI, or None to generate a uniform, ~useless metadata map variance: ndarray variance for valid ROI, or None to generate a uniform, ~useless metadata map metadata: MetaDataHandler instance ROI informatrion and camera noise parameters to use when padding maps sensor_size: 2-int tuple x and y camera sensor size Returns ------- full_dark: ndarray padded dark map full_var: ndarray padded variance map mdh: PYME.IO.MetadataHandler.NestedClassMDHandler metadata handler to be associated with full maps while maintaining information about the original/valid ROI. """ mdh = NestedClassMDHandler(metadata) x_origin, y_origin = get_camera_roi_origin(mdh) if not ((x_origin == 0) and (y_origin == 0) and (metadata['Camera.ROIWidth'] == sensor_size[0]) and (metadata['Camera.ROIHeight'] == sensor_size[1])): mdh['CameraMap.SubROI'] = True mdh['CameraMap.ValidROI.ROIOriginX'] = x_origin mdh['CameraMap.ValidROI.ROIOriginY'] = y_origin mdh['CameraMap.ValidROI.ROIWidth'] = mdh['Camera.ROIWidth'] mdh['CameraMap.ValidROI.ROIHeight'] = mdh['Camera.ROIHeight'] mdh['Camera.ROIOriginX'], mdh['Camera.ROIOriginY'] = 0, 0 mdh['Camera.ROIWidth'], mdh['Camera.ROIHeight'] = sensor_size mdh['Camera.ROI'] = (0, 0, sensor_size[0], sensor_size[1]) if dark is not None and variance is not None: full_dark = mdh['Camera.ADOffset'] * np.ones(sensor_size, dtype=dark.dtype) full_var = (mdh['Camera.ReadNoise']**2) * np.ones(sensor_size, dtype=variance.dtype) xslice = slice(x_origin, x_origin + metadata['Camera.ROIWidth']) yslice = slice(y_origin, y_origin + metadata['Camera.ROIHeight']) full_dark[xslice, yslice] = dark full_var[xslice, yslice] = variance else: logger.warning('Generating uniform maps') full_dark = mdh['Camera.ADOffset'] * np.ones(sensor_size) full_var = (mdh['Camera.ReadNoise']**2) * np.ones(sensor_size) mdh['CamerMap.Uniform'] = True return full_dark, full_var, mdh
def OnExtractSplitPSF(self, event): if (len(self.PSFLocs) > 0): from PYME.Analysis.PSFEst import extractImages chnum = self.chChannel.GetSelection() psfROISize = [int(s) for s in self.tPSFROI.GetValue().split(',')] psfBlur = [float(s) for s in self.tPSFBlur.GetValue().split(',')] #print psfROISize psfs = [] offsetsAllChannel = [] #extract first channel (always aligned) psf, offsets = extractImages.getPSF3D(self.image.data[:, :, :, 0].squeeze(), self.PSFLocs, psfROISize, psfBlur, centreZ=True) if self.chType.GetSelection() == 0: #widefield image - do special background subtraction psf = extractImages.backgroundCorrectPSFWF(psf) psfs.append(psf) offsetsAllChannel.append(offsets) alignZ = self.cbAlignZ.GetValue() z_offset = offsets[2] #extract subsequent channels, aligning if necessary, otherwise offsetting by the calculated offset for the first channel for i in range(1, self.image.data.shape[3]): psf, offsets = extractImages.getPSF3D( self.image.data[:, :, :, i].squeeze(), self.PSFLocs, psfROISize, psfBlur, centreZ=alignZ, z_offset=z_offset) if self.cbBackgroundCorrect.GetValue(): #widefield image - do special background subtraction psf = extractImages.backgroundCorrectPSFWF(psf) psfs.append(psf) offsetsAllChannel.append(offsets) psf = numpy.concatenate(psfs, 0) offsetsAllChannel = numpy.asarray(offsetsAllChannel) offsetsAllChannel -= offsetsAllChannel[0] print(offsetsAllChannel) # from pylab import * # import cPickle # imshow(psf.max(2)) from PYME.DSView.dsviewer import ImageStack, ViewIm3D from PYME.IO.MetaDataHandler import NestedClassMDHandler mdh = NestedClassMDHandler(self.image.mdh) self.write_metadata(mdh, 'Split', offsetsAllChannel[:, 2]) mdh['ImageType'] = 'PSF' im = ImageStack(data=psf, mdh=mdh, titleStub='Extracted PSF') im.defaultExt = '*.tif' #we want to save as PSF by default ViewIm3D(im, mode='psf', parent=wx.GetTopLevelParent(self.dsviewer))
def combine_maps(maps, return_validMap=False): destarr = None mapimgs = [] for map in maps: mapimg = ImageStack(filename=map) mapimgs.append(mapimg) if destarr is None: mdh = NestedClassMDHandler(mapimg.mdh) destarr = mkdestarr(mapimg) validMap = np.zeros_like(destarr, dtype='int') else: checkMapCompat(mapimg, mdh) insertvmap(mapimg, destarr, validMap) mdh.setEntry('CameraMap.combinedFromMaps', maps) mdh.setEntry('CameraMap.ValidROI.ROIHeight', mapimgs[0].mdh['Camera.SensorHeight']) mdh.setEntry('CameraMap.ValidROI.ROIWidth', mapimgs[0].mdh['Camera.SensorWidth']) mdh.setEntry('CameraMap.ValidROI.ROIOriginX', 0) mdh.setEntry('CameraMap.ValidROI.ROIOriginY', 0) combinedMap = ImageStack(destarr, mdh=mdh) if return_validMap: vmdh = NestedClassMDHandler(mdh) vmdh.setEntry('CameraMap.ValidMask', True) return (combinedMap, ImageStack(validMap, mdh=vmdh)) else: return combinedMap
CHANGES = np.array([(0, 50.0 + 0.5), (1, 50.001 + 0.5), (801, 51.000), (850, 50.600 + 0.5), (1601, 52.000), (1650, 51.450 + 0.5), (2401, 53), (2450, 52.705 + 0.5)], dtype= [('frame', '<i4'), ('z', '<f8')]) TEST_DATA_SOURCE = np.arange(2500).astype([('t', '<i4')]) GROUND_TRUTH_Z = np.empty(len(TEST_DATA_SOURCE), dtype=float) for ind in range(len(CHANGES)): GROUND_TRUTH_Z[CHANGES[ind]['frame']:] = CHANGES[ind]['z'] TEST_MDH = NestedClassMDHandler() TEST_MDH['Camera.CycleTime'] = 0.00125 TEST_MDH['StartTime'] = 0 def test_flag_piezo_movement(): from PYME.Analysis.piezo_movement_correction import flag_piezo_movement moving = flag_piezo_movement(TEST_DATA_SOURCE['t'], TEST_EVENTS, TEST_MDH) assert np.all(moving[np.where(np.logical_and(TEST_DATA_SOURCE['t'] >= 2401, TEST_DATA_SOURCE['t'] < 2450))]) assert not np.all(np.all(moving[np.where(TEST_DATA_SOURCE['t'] >= 2450)])) def test_focus_correction(): from PYME.Analysis.piezo_movement_correction import correct_target_positions corrected_focus = correct_target_positions(TEST_DATA_SOURCE['t'], TEST_EVENTS, TEST_MDH) np.testing.assert_array_almost_equal(GROUND_TRUTH_Z, corrected_focus)
def insertIntoFullMap(m, ve, smdh, chipsize=(2048, 2048)): x0, y0 = get_camera_roi_origin(smdh) validROI = { 'PosX': x0 + 1, 'PosY': x0 + 1, 'Width': smdh['Camera.ROIWidth'], 'Height': smdh['Camera.ROIHeight'] } bmdh = NestedClassMDHandler() bmdh.copyEntriesFrom(smdh) bmdh.setEntry('Analysis.name', 'mean-variance') bmdh.setEntry('Analysis.valid.ROIPosX', validROI['PosX']) bmdh.setEntry('Analysis.valid.ROIPosY', validROI['PosY']) bmdh.setEntry('Analysis.valid.ROIWidth', validROI['Width']) bmdh.setEntry('Analysis.valid.ROIHeight', validROI['Height']) bmdh['Camera.ROIOriginX'] = 0 bmdh['Camera.ROIOriginY'] = 0 bmdh['Camera.ROIWidth'] = chipsize[0] bmdh['Camera.ROIHeight'] = chipsize[1] bmdh['Camera.ROI'] = (0, 0, chipsize[0], chipsize[1]) if m is None: mfull = np.zeros(chipsize, dtype='float64') vefull = np.zeros(chipsize, dtype='float64') else: mfull = np.zeros(chipsize, dtype=m.dtype) vefull = np.zeros(chipsize, dtype=ve.dtype) mfull.fill(smdh['Camera.ADOffset']) vefull.fill(smdh['Camera.ReadNoise']**2) if m is not None: mfull[validROI['PosX'] - 1:validROI['PosX'] - 1 + validROI['Width'], validROI['PosY'] - 1:validROI['PosY'] - 1 + validROI['Height']] = m vefull[validROI['PosX'] - 1:validROI['PosX'] - 1 + validROI['Width'], validROI['PosY'] - 1:validROI['PosY'] - 1 + validROI['Height']] = ve return mfull, vefull, bmdh
def main(): chipsize = ( 2048, 2048 ) # we currently assume this is correct but could be chosen based # on camera model in meta data darkthreshold = 1e4 # this really should depend on the gain mode (12bit vs 16 bit etc) variancethreshold = 300**2 # again this is currently picked fairly arbitrarily blemishvariance = 1e8 # options parsing op = argparse.ArgumentParser( description='generate offset and variance maps from darkseries.') op.add_argument('filename', metavar='filename', nargs='?', default=None, help='filename of the darkframe series') op.add_argument('-s', '--start', type=int, default=0, help='start frame to use') op.add_argument('-e', '--end', type=int, default=-1, help='end frame to use') op.add_argument('-u', '--uniform', action='store_true', help='make uniform map using metadata info') op.add_argument( '-i', '--install', action='store_true', help='install map in default location - the filename argument is a map' ) op.add_argument( '-d', '--dir', metavar='destdir', default=None, help='destination directory (default is PYME calibration path)') op.add_argument('-l', '--list', action='store_true', help='list all maps in default location') args = op.parse_args() if args.list: listCalibrationDirs() sys.exit(0) # body of script filename = args.filename if filename is None: op.error('need a file name if -l or --list not requested') print('Opening image series...', file=sys.stderr) source = im.ImageStack(filename=filename) if args.install: if source.mdh.getOrDefault('Analysis.name', '') != 'mean-variance': print( 'Analysis.name is not equal to "mean-variance" - probably not a map', file=sys.stderr) sys.exit('aborting...') if source.mdh['Analysis.resultname'] == 'mean': maptype = 'dark' else: maptype = 'variance' mapname = mkDefaultPath(maptype, source.mdh) saveasmap(source.dataSource.getSlice(0), mapname, mdh=source.mdh) sys.exit(0) start = args.start end = args.end if end < 0: end = int(source.dataSource.getNumSlices() + end) print('Calculating mean and variance...', file=sys.stderr) m, ve = (None, None) if not args.uniform: m, v = meanvards(source.dataSource, start=start, end=end) eperADU = source.mdh['Camera.ElectronsPerCount'] ve = v * eperADU * eperADU # occasionally the cameras seem to have completely unusable pixels # one example was dark being 65535 (i.e. max value for 16 bit) if m.max() > darkthreshold: ve[m > darkthreshold] = blemishvariance if ve.max() > variancethreshold: ve[ve > variancethreshold] = blemishvariance nbad = np.sum((m > darkthreshold) * (ve > variancethreshold)) # if the uniform flag is set, then m and ve are passed as None # which makes sure that just the uniform defaults from meta data are used mfull, vefull, basemdh = insertIntoFullMap(m, ve, source.mdh, chipsize=chipsize) #mfull, vefull, basemdh = (m, ve, source.mdh) print('Saving results...', file=sys.stderr) if args.dir is None: print('installing in standard location...', file=sys.stderr) mname = mkDefaultPath('dark', source.mdh) vname = mkDefaultPath('variance', source.mdh) else: mname = mkDestPath(args.dir, 'dark', source.mdh) vname = mkDestPath(args.dir, 'variance', source.mdh) print('dark map -> %s...' % mname, file=sys.stderr) print('var map -> %s...' % vname, file=sys.stderr) commonMD = NestedClassMDHandler() commonMD.setEntry('Analysis.name', 'mean-variance') commonMD.setEntry('Analysis.start', start) commonMD.setEntry('Analysis.end', end) commonMD.setEntry('Analysis.SourceFilename', filename) commonMD.setEntry('Analysis.darkThreshold', darkthreshold) commonMD.setEntry('Analysis.varianceThreshold', variancethreshold) commonMD.setEntry('Analysis.blemishVariance', blemishvariance) commonMD.setEntry('Analysis.NBadPixels', nbad) if args.uniform: commonMD.setEntry('Analysis.isuniform', True) mmd = NestedClassMDHandler(basemdh) mmd.copyEntriesFrom(commonMD) mmd.setEntry('Analysis.resultname', 'mean') mmd.setEntry('Analysis.units', 'ADU') vmd = NestedClassMDHandler(basemdh) vmd.copyEntriesFrom(commonMD) vmd.setEntry('Analysis.resultname', 'variance') vmd.setEntry('Analysis.units', 'electrons^2') saveasmap(mfull, mname, mdh=mmd) saveasmap(vefull, vname, mdh=vmd)