def findBrightImageFromNorm(self, normdata): ''' Find BrighetImageData based on imported NormImageData. This is needed for older data since BrightImageData was not linked to AcquisitionImages previously. ''' if normdata['bright']: return normdata['bright'] timestamp = normdata.timestamp normcam = normdata['camera'] qcam = leginondata.CameraEMData(dimension=normcam['dimension'], offset=normcam['offset'], binning=normcam['binning'], ccdcamera=normcam['ccdcamera']) qcam['exposure type'] = 'normal' qcam['energy filtered'] = normcam['energy filtered'] normscope = normdata['scope'] qscope = leginondata.ScopeEMData(tem=normscope['tem']) qscope['high tension'] = normscope['high tension'] q = leginondata.BrightImageData(camera=qcam, scope=qscope, channel=normdata['channel']) brightlist = q.query() for brightdata in brightlist: if brightdata.timestamp < timestamp: break return brightdata
def alreadyAcquired(self, targetdata, presetname): ''' determines if image already acquired using targetdata and presetname ''' ## if image exists with targetdata and presetdata, no acquire ## we expect target to be exact, however, presetdata may have ## changed so we only query on preset name # seems to have trouple with using original targetdata as # a query, so use a copy with only some of the fields presetquery = leginondata.PresetData(name=presetname) targetquery = leginondata.AcquisitionImageTargetData(initializer=targetdata) ## don't care if drift correction was done on target after image was ## acquired, so ignore version, delta row/col, parentimage, and fromtarget targetquery['version'] = None targetquery['delta row'] = None targetquery['delta column'] = None targetquery['image'] = None targetquery['fromtarget'] = None imagequery = leginondata.AcquisitionImageData(target=targetquery, preset=presetquery) ## other things to fill in imagequery['scope'] = leginondata.ScopeEMData() imagequery['camera'] = leginondata.CameraEMData() imagequery['session'] = leginondata.SessionData() datalist = self.research(datainstance=imagequery) if datalist: ## no need to acquire again, but need to republish self.reportStatus('output', 'Image was acquired previously, republishing') imagedata = datalist[0] self.publishDisplayWait(imagedata) return True else: return False
def researchCorrectorImageData(self, type, scopedata, cameradata, channel): if type == 'dark': imagetemp = leginondata.DarkImageData() elif type == 'bright': imagetemp = leginondata.BrightImageData() elif type == 'norm': imagetemp = leginondata.NormImageData() else: return None ## query only based on certain camera parameters, not all imagetemp['camera'] = leginondata.CameraEMData() for key in ('ccdcamera', 'dimension', 'binning', 'offset', 'gain index'): imagetemp['camera'][key] = cameradata[key] # query only based on certain scope parameters, not all imagetemp['scope'] = leginondata.ScopeEMData() for key in ('tem', 'high tension'): imagetemp['scope'][key] = scopedata[key] imagetemp['channel'] = channel try: ref = imagetemp.query(results=1) except Exception, e: self.logger.warning('Reference image query failed: %s' % e) ref = None
def calculateTiles(self, tilesize): ## figure out the final shape of global space rowsize = int(numpy.ceil(float(self.shape[0]) / tilesize) * tilesize) colsize = int(numpy.ceil(float(self.shape[1]) / tilesize) * tilesize) ## make list of stage center for each tile print 'calculating tile positions...' centerpixel = rowsize / 2.0 - 0.5, colsize / 2.0 - 0.5 firstpixel = tilesize / 2.0 - 0.5 rowi = 0 tiles = ordereddict.OrderedDict() for row in numpy.arange(firstpixel, rowsize, tilesize): coli = 0 for col in numpy.arange(firstpixel, colsize, tilesize): pixel = { 'row': row - centerpixel[0], 'col': col - centerpixel[1] } newstage = self.trans.transform(pixel, self.stage, self.bin) tilescope = leginondata.ScopeEMData(initializer=self.scope) tilescope['stage position'] = newstage tilecamera = leginondata.CameraEMData(initializer=self.camera) tilecamera['dimension'] = {'x': tilesize, 'y': tilesize} args = tilescope, tilecamera, self.timestamp kwargs = {'rotation': self.rotation} tiles[(rowi, coli)] = {'args': args, 'kwargs': kwargs} coli += 1 rowi += 1 print 'Calculated %d tiles, %d rows, %d cols' % (len(tiles), rowi, coli) return tiles
def measureImageShiftComaMatrix(self, shift_n, shift_step, repeat, tilt_value, settle): ''' Measure coma for a range of image shift and fit the results to a straight line on individual axis. Strickly speaking should use orthogonal distance regression.''' calibration_client = self.calibration_clients['beam tilt'] f = open(self.session['name'] + 'tilt.dat', 'w') tem = self.instrument.getTEMData() shift0 = self.instrument.tem.ImageShift state = leginondata.ScopeEMData() tilt0 = self.instrument.tem.BeamTilt state['image shift'] = shift0 state['beam tilt'] = tilt0 coma0 = tilt0 tdict = {} xydict = {} ordered_axes = ['x', 'y'] debug = False try: for axis in ordered_axes: tdata = [] data = {'x': [], 'y': []} for i in range(0, 2 * shift_n + 1): shift = (i - shift_n) * shift_step tdata.append(shift) state['image shift'][axis] = shift0[axis] + shift self.instrument.setData(state) newshift = self.instrument.tem.ImageShift self.logger.info( 'Image Shift ( %5.2f, %5.2f)' % (newshift['x'] * 1e6, newshift['y'] * 1e6)) text = '%5.2f %5.2f ' % (newshift['x'] * 1e6, newshift['y'] * 1e6) xarray, yarray = calibration_client.repeatMeasureComaFree( tilt_value, settle, repeat) xmean = xarray.mean() ymean = yarray.mean() text = text + "%5.2f %5.2f %5.2f %5.2f" % ( xmean * 1000, xarray.std() * 1000, ymean * 1000, yarray.std() * 1000) + '\n' f.write(text) state['image shift'] = shift0 state['beam tilt'] = tilt0 self.instrument.setData(state) comatilt = {'x': xmean, 'y': ymean} data['x'].append(xmean) data['y'].append(ymean) self.checkAbort() tdict[axis] = tdata xydict[axis] = data matrix, coma0 = calibration_client.calculateImageShiftComaMatrix( tdict, xydict) except: raise matrix = None f.close() return matrix, coma0
def createGlobalOutput(imdata, angle=0.0, bin=1): sys.stderr.write('creating global image space\n') timestamp = imdata.timestamp scope = leginondata.ScopeEMData(initializer=imdata['scope']) camera = leginondata.CameraEMData(initializer=imdata['camera']) binning = { 'x': camera['binning']['x'] * bin, 'y': camera['binning']['y'] * bin } camera['binning'] = binning globaloutput = MontageImage(scope, camera, timestamp, rotation=angle) return globaloutput
def queryCorrectionImage(self, scopedata, camdata, type, channel): # only query based on instrument and high tension scope = leginondata.ScopeEMData() scope['tem'] = scopedata['tem'] scope['high tension'] = scopedata['high tension'] # only query based on instrument, dimension, binning, offset camera = leginondata.CameraEMData() camera['ccdcamera'] = camdata['ccdcamera'] camera['dimension'] = camdata['dimenion'] camera['binning'] = camdata['binning'] camera['offset'] = camdata['offset'] ## first try requested channel, then try any channel corimg = None for channel in (channel, None): ## try cache try: key = self.getkey(scopedata, camdata, type, channel) return self.cache[key] except KeyError: pass self.node.logger.info('Loading %s...' % self.formatKey(key)) qimage = leginondata.CorrectionImageData(scope=scope, camera=camera, type=type, channel=channel) try: corimg = qimage.query(results=1) corimg = corimg[0] break except: pass self.node.logger.warning( 'requested correction channel %s not available, using channel: %s' % (channel, corimg['channel'])) else: self.node.logger.error('No correction image in database') corimg = None if corimg is not None: self.node.logger.info('Correction image loaded: %s' % (corimg['filename'], )) ## make it float to do float math later image = numpy.asarray(corimg['image'], numpy.float32) key = self.getkey(corimg['scope'], corimg['camera'], corimg['type'], corimg['channel']) self.cache[key] = image else: image = None return image
def __init__(self, scope, camera, timestamp, fileref=None, rotation=0.0): self.scope = leginondata.ScopeEMData(initializer=scope) self.camera = leginondata.CameraEMData(initializer=camera) self.shape = self.camera['dimension']['y'], self.camera['dimension'][ 'x'] self.fileref = fileref self.timestamp = timestamp self.trans = caltransformer.getTransformer(scope['tem'], camera['ccdcamera'], scope['high tension'], scope['magnification'], timestamp, rotation) self.newStage(scope['stage position'])
def storeCorrectorImageData(self, imagedata, type, channel): # check for bad shape imarray = imagedata['image'] shape = imarray.shape cameradata = imagedata['camera'] dim = cameradata['dimension'] if dim['x'] != shape[1] or dim['y'] != shape[0]: raise RuntimeError('%s: bad array shape: %s' % ( type, shape, )) if type == 'dark': refclass = leginondata.DarkImageData elif type == 'bright': refclass = leginondata.BrightImageData elif type == 'norm': refclass = leginondata.NormImageData refdata = refclass(initializer=imagedata) refdata['filename'] = self.makeCorrectorImageFilename( type, channel, imarray.shape) ## replace session of scope, camera, refdata with ref session refsession = self.getReferenceSession() scopedata = refdata['scope'] cameradata = refdata['camera'] newscope = leginondata.ScopeEMData(initializer=scopedata) newscope['session'] = refsession newcamera = leginondata.CameraEMData(initializer=cameradata) newcamera['session'] = refsession refdata['session'] = refsession refdata['scope'] = newscope refdata['camera'] = newcamera refdata['channel'] = channel self.logger.info('Saving new %s' % (type, )) refdata.insert(force=True) self.logger.info('Saved: %s' % (refdata['filename'], )) ## store in cache key = self.makeCorrectorKey(type, scopedata, cameradata, channel) ref_cache[key] = refdata return refdata
def getAlternativeChannelNorm(self, refdata): ''' Get norm image data of the other channel closest in time ''' if refdata is None: return None reftype = 'norm' timestamp = refdata.timestamp refcam = refdata['camera'] qcam = leginondata.CameraEMData(dimension=refcam['dimension'], offset=refcam['offset'], binning=refcam['binning'], ccdcamera=refcam['ccdcamera']) qcam['exposure time'] = refcam['exposure time'] qcam['energy filtered'] = refcam['energy filtered'] qcam['gain index'] = refcam['gain index'] refscope = refdata['scope'] qscope = leginondata.ScopeEMData(tem=refscope['tem']) qscope['high tension'] = refscope['high tension'] altchannel = int(refdata['channel'] == 0) q = self.createRefQuery(reftype, qcam, qscope, altchannel) reflist = q.query() if len(reflist) == 0: # Not to query exposure time if none found qcam['exposure time'] = None q = self.createRefQuery(reftype, qcam, qscope, altchannel) reflist = q.query() if len(reflist) == 0: #no switching, no alternative channel found return refdata for newrefdata in reflist: if newrefdata.timestamp < timestamp: break before_ref = newrefdata reflist.reverse() for newrefdata in reflist: if newrefdata.timestamp > timestamp: break after_ref = newrefdata if after_ref.timestamp - timestamp > timestamp - before_ref.timestamp: return before_ref else: return after_ref
def __calibrateStigmator(self, beam_tilt, delta, stigmator): if self.initInstruments(): raise RuntimeError('cannot initialize instrument') calibration_client = self.calibration_clients['beam tilt'] magnification = self.instrument.tem.Magnification high_tension = self.instrument.tem.HighTension probe = self.instrument.tem.ProbeMode # set up the stigmator states axes = ('x', 'y') deltas = (delta / 2.0, -delta / 2.0) for stig_axis in axes: self.logger.info('Calibrating stig. %s-axis...' % stig_axis) parameters = [] states = [] for delta in deltas: v = dict(stigmator) v[stig_axis] += delta parameters.append(v[stig_axis]) s = leginondata.ScopeEMData(stigmator={'objective': v}) states.append(s) matrix = numpy.identity(2, numpy.float) for i, tilt_axis in enumerate(axes): self.logger.info('Calibrating on %s-axis...' % tilt_axis) args = (tilt_axis, beam_tilt, states) kwargs = { 'correct_tilt': self.settings['correct tilt'], 'settle': self.settings['settling time'], } shifts = calibration_client.measureDisplacements( *args, **kwargs) args = (shifts, parameters, beam_tilt) matrix[:, i] = calibration_client.eq11(*args) self.checkAbort() # store calibration type = 'stig' + stig_axis args = (high_tension, magnification, type, matrix) kwargs = {'probe': probe} calibration_client.storeMatrix(*args, **kwargs)
def getEMTargetData(self, check_preset_name=None): target_data = self.reference_target if target_data is None: raise MoveError('no reference target available') move_type = self.settings['move type'] calibration_client = self.calibration_clients[move_type] target_delta_row = target_data['delta row'] target_delta_column = target_data['delta column'] pixel_shift = {'row': -target_delta_row, 'col': -target_delta_column} target_scope = leginondata.ScopeEMData( initializer=target_data['scope']) for i in ['image shift', 'beam shift', 'stage position']: target_scope[i] = dict(target_data['scope'][i]) target_camera = target_data['camera'] args = (pixel_shift, target_scope, target_camera) try: scope = calibration_client.transform(*args) except calibrationclient.NoMatrixCalibrationError, e: message = 'no %s calibration to move to reference target: %s' raise MoveError(message % (move_type, e))
def getBrightImageFromNorm(self, normdata): ''' Get bright image used to produce the norm image This is made to be back compatible to early leginondata that has no bright image association but would be the closest in time before the norm was calculated ''' if normdata is None: return None # newer leginon data will have bright image associated with norm image if 'bright' in normdata.keys() and normdata['bright'] is not None: return normdata['bright'] # bright image may have the same CameraEMData q = leginondata.BrightImageData(camera=normdata['camera']) brightresults = q.query(results=1) if brightresults: return brightresults[0] # otherwise need to look up timestamp timestamp = normdata.timestamp normcam = normdata['camera'] qcam = leginondata.CameraEMData(dimension=normcam['dimension'], offset=normcam['offset'], binning=normcam['binning'], ccdcamera=normcam['ccdcamera']) qcam['exposure type'] = 'normal' qcam['energy filtered'] = normcam['energy filtered'] qcam['gain index'] = normcam['gain index'] normscope = normdata['scope'] qscope = leginondata.ScopeEMData(tem=normscope['tem']) qscope['high tension'] = normscope['high tension'] q = leginondata.BrightImageData(camera=qcam, scope=qscope, channel=normdata['channel']) brightlist = q.query() for brightdata in brightlist: if brightdata.timestamp < timestamp: break return brightdata
def makeStates(self): ## list of tilts entered by user in degrees, converted to radians tiltstr = self.settings['tilts'] try: alphatilts = eval(tiltstr) except: self.logger.error('Invalid tilt list') return ## check for singular value if isinstance(alphatilts, float) or isinstance(alphatilts, int): alphatilts = (alphatilts,) if len(alphatilts) == 0: self.logger.warning("Please set to Bypass if you do not want to repeat") return [] self.makeTiltPatterns(alphatilts) states = [] self.logger.info('tilt series =' + str(alphatilts)) for a in alphatilts: rad = a * 3.14159 / 180.0 scope = leginondata.ScopeEMData() scope['stage position'] = {'a': rad} states.append(scope) return states
def calculateMosaicImage(self): ''' calculates (but does not generate) an unscaled mosaic image ''' if not self.tiles: return param = self.calibrationclient.parameter() ## calculate parameter center of final mosaic image center = {'x': 0.0, 'y': 0.0} for tile in self.tiles: tileparam = tile.imagedata['scope'][param] center['x'] += tileparam['x'] center['y'] += tileparam['y'] n = len(self.tiles) center['x'] /= n center['y'] /= n self.center = center ## Calculate pixel vector on final image to center of ## each tile. ## To use calibrationclient's itransform method, we need ## a fake image from which to calculate a pixel vector ## Maybe could use an actual final image leginondata. someimage = self.tiles[0].imagedata self.fakescope = leginondata.ScopeEMData(initializer=someimage['scope']) self.fakescope[param] = dict(someimage['scope'][param]) self.fakescope[param].update(center) ## assume the final fake image has same binning as first tile self.fakecamera = leginondata.CameraEMData(initializer=someimage['camera']) tile0 = self.tiles[0] mosaic0 = mosaic1 = None for tile in self.tiles: tileparam = {} ## calculate the parameter shift from center of ## mosaic image to center of tile for axis in ('x','y'): tileparam[axis] = tile.imagedata['scope'][param][axis] ## calculate corresponding pixel shift (float) center2center = self.positionByCalibration(tileparam) ## for targeting, until it's fixed tile.position = center2center ## pixel shift mosaic center to tile center (int) center2center = self.round(center2center) tile.center_vect = center2center ## pixel shift from center of mosaic to corners of tile shape = tile.image.shape corner_vect = center2center[0]-shape[0]/2, center2center[1]-shape[1]/2 corner1_vect = corner_vect[0]+shape[0], corner_vect[1]+shape[1] tile.corner_vect = corner_vect ## check if this is a min or max in the mosaic if mosaic0 is None: mosaic0 = [corner_vect[0], corner_vect[1]] mosaic1 = [corner1_vect[0], corner1_vect[1]] for axis in (0,1): if corner_vect[axis] < mosaic0[axis]: mosaic0[axis] = corner_vect[axis] if corner1_vect[axis] > mosaic1[axis]: mosaic1[axis] = corner1_vect[axis] ## mosaic shape at full scale self.mosaicshape = mosaic1[0]-mosaic0[0], mosaic1[1]-mosaic0[1] ## center of mosaic image mosaic_center = self.mosaicshape[0]/2, self.mosaicshape[1]/2 ## position of corner and center for tile in self.tiles: corner_pos = tile.corner_vect[0]-mosaic0[0], tile.corner_vect[1]-mosaic0[1] center_pos = tile.center_vect[0]-mosaic0[0], tile.center_vect[1]-mosaic0[1] tile.corner_pos = corner_pos tile.center_pos = center_pos
def targetToEMTargetData(self, targetdata,movetype): ''' copied from acquisition but get move type from old emtarget ''' emtargetdata = leginondata.EMTargetData() if targetdata is not None: # get relevant info from target data targetdeltarow = targetdata['delta row'] targetdeltacolumn = targetdata['delta column'] origscope = targetdata['scope'] targetscope = leginondata.ScopeEMData(initializer=origscope) ## copy these because they are dictionaries that could ## otherwise be shared (although transform() should be ## smart enough to create copies as well) targetscope['stage position'] = dict(origscope['stage position']) targetscope['image shift'] = dict(origscope['image shift']) targetscope['beam shift'] = dict(origscope['beam shift']) oldpreset = targetdata['preset'] zdiff = 0.0 ### simulated target does not require transform if targetdata['type'] == 'simulated': newscope = origscope else: targetcamera = targetdata['camera'] ## to shift targeted point to center... deltarow = -targetdeltarow deltacol = -targetdeltacolumn pixelshift = {'row':deltarow, 'col':deltacol} ## figure out scope state that gets to the target calclient = self.calclients[movetype] try: newscope = calclient.transform(pixelshift, targetscope, targetcamera) except calibrationclient.NoMatrixCalibrationError, e: m = 'No calibration for acquisition move to target: %s' self.logger.error(m % (e,)) raise NoMoveCalibration(m) ## if stage is tilted and moving by image shift, ## calculate z offset between center of image and target if movetype in ('image shift','image beam shift','beam shift') and abs(targetscope['stage position']['a']) > 0.02: calclient = self.calclients['stage position'] try: tmpscope = calclient.transform(pixelshift, targetscope, targetcamera) except calibrationclient.NoMatrixCalibrationError: message = 'No stage calibration for z measurement' self.logger.error(message) raise NoMoveCalibration(message) ydiff = tmpscope['stage position']['y'] - targetscope['stage position']['y'] zdiff = ydiff * numpy.sin(targetscope['stage position']['a']) ### check if stage position is valid if newscope['stage position']: self.validateStagePosition(newscope['stage position']) emtargetdata['preset'] = oldpreset emtargetdata['movetype'] = movetype emtargetdata['image shift'] = dict(newscope['image shift']) emtargetdata['beam shift'] = dict(newscope['beam shift']) emtargetdata['stage position'] = dict(newscope['stage position']) emtargetdata['delta z'] = zdiff
from leginon import leginondata import dbdatakeeper dk = dbdatakeeper.DBDataKeeper(('asdf', 3), None) md = leginondata.MyData() mod = leginondata.MyOtherData() mod['stuff'] = 6 mod['encore'] = 'asdf' md['other'] = mod scopedata = leginondata.ScopeEMData(('scopeasdf', ), initializer={ 'magnification': 1501, 'beam tilt': { 'x': 1.1, 'y': 2.2 } }) cameradata = leginondata.CameraEMData(('camasdf', ), initializer={ 'exposure time': 510, 'binning': { 'x': 1, 'y': 1 } }) ## PresetData pdata = leginondata.NewPresetData(('pdata', 1)) pdata['name'] = 'hole3'
def targetToEMTargetData(self, targetdata, z=None): ''' convert an ImageTargetData to an EMTargetData object using chosen move type. The result is a valid scope state that will center the target on the camera, but not necessarily at the desired preset. It is shifted from the preset of the original targetdata. Certain fields are reset to None becuase they are not necessary, and cause problems if used between different magnification modes (LM, M, SA). ''' emtargetdata = leginondata.EMTargetData() if targetdata is not None: # get relevant info from target data targetdeltarow = targetdata['delta row'] targetdeltacolumn = targetdata['delta column'] origscope = targetdata['scope'] targetscope = leginondata.ScopeEMData(initializer=origscope) ## copy these because they are dictionaries that could ## otherwise be shared (although transform() should be ## smart enough to create copies as well) targetscope['stage position'] = dict(origscope['stage position']) targetscope['image shift'] = dict(origscope['image shift']) targetscope['beam shift'] = dict(origscope['beam shift']) if z is not None: # since presetsmanager settings 'only xy' is always True, this # is only good for database record targetscope['stage position']['z'] = z movetype = self.settings['move type'] oldpreset = targetdata['preset'] zdiff = 0.0 ### simulated target does not require transform if targetdata['type'] == 'simulated': newscope = origscope else: targetcamera = targetdata['camera'] ## to shift targeted point to center... deltarow = -targetdeltarow deltacol = -targetdeltacolumn pixelshift = {'row':deltarow, 'col':deltacol} ## figure out scope state that gets to the target calclient = self.calclients[movetype] try: newscope = calclient.transform(pixelshift, targetscope, targetcamera) except calibrationclient.NoMatrixCalibrationError, e: raise NoMoveCalibration(e) ## if stage is tilted and moving by image shift, ## calculate z offset between center of image and target if movetype in ('image shift','image beam shift','beam shift') and abs(targetscope['stage position']['a']) > 0.02: calclient = self.calclients['stage position'] try: tmpscope = calclient.transform(pixelshift, targetscope, targetcamera) except calibrationclient.NoMatrixCalibrationError,e: raise NoMoveCalibration(e) ydiff = tmpscope['stage position']['y'] - targetscope['stage position']['y'] zdiff = ydiff * numpy.sin(targetscope['stage position']['a'])