Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ publishing = [
"wheel",
"build",
]
simulation = [
"diffsims",
]

[project.scripts]
"instamatic" = "instamatic.main:main"
Expand Down
2 changes: 1 addition & 1 deletion src/instamatic/calibrate/calibrate_beamshift.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def plot(self, to_file=None, outdir=''):

def center(self, ctrl):
"""Return beamshift values to center the beam in the frame."""
pixel_center = [val / 2.0 for val in ctrl.cam.get_image_dimensions()]
pixel_center = [val / 2.0 for val in ctrl.cam.get_camera_dimensions()]

beamshift = self.pixelcoord_to_beamshift(pixel_center)
if ctrl:
Expand Down
2 changes: 1 addition & 1 deletion src/instamatic/camera/fakevideostream.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __getattr__(self, attrname):
def get_image(self, exposure=None, binsize=None):
frame = self.cam.get_image(exposure=exposure, binsize=binsize)

self.frame, scale = autoscale(frame, maxdim=self.display_dim)
# self.frame, scale = autoscale(frame, maxdim=self.display_dim)

return frame

Expand Down
73 changes: 52 additions & 21 deletions src/instamatic/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from instamatic.microscope import components
from instamatic.microscope.base import MicroscopeBase
from instamatic.microscope.microscope import get_microscope
from instamatic.simulation import get_simulation_instances

_ctrl = None # store reference of ctrl so it can be accessed without re-initializing

Expand Down Expand Up @@ -46,22 +47,25 @@ def initialize(
ctrl : `TEMController`
Return TEM control object
"""
print(f"Microscope: {tem_name}{' (server)' if use_tem_server else ''}")
tem = get_microscope(tem_name, use_server=use_tem_server)

if cam_name:
if use_cam_server:
cam_tag = ' (server)'
elif stream:
cam_tag = ' (stream)'
else:
cam_tag = ''

print(f'Camera : {cam_name}{cam_tag}')

cam = Camera(cam_name, as_stream=stream, use_server=use_cam_server)
if tem_name == 'simulate' or cam_name == 'simulate':
cam, tem = get_simulation_instances()
else:
cam = None
print(f"Microscope: {tem_name}{' (server)' if use_tem_server else ''}")
tem = get_microscope(tem_name, use_server=use_tem_server)
if cam_name:
if use_cam_server:
cam_tag = ' (server)'
elif stream:
cam_tag = ' (stream)'
else:
cam_tag = ''

print(f'Camera : {cam_name}{cam_tag}')

cam = Camera(cam_name, as_stream=stream, use_server=use_cam_server)
else:
cam = None

global _ctrl
ctrl = _ctrl = TEMController(tem=tem, cam=cam)
Expand Down Expand Up @@ -384,11 +388,11 @@ def find_eucentric_height(

def one_cycle(tilt: float = 5, sign=1) -> list:
angle1 = -tilt * sign
self.stage.a = angle1
self.stage.set(a=angle1)
img1 = self.get_rotated_image()

angle2 = +tilt * sign
self.stage.a = angle2
self.stage.set(a=angle2)
img2 = self.get_rotated_image()

if sign < 1:
Expand All @@ -398,7 +402,7 @@ def one_cycle(tilt: float = 5, sign=1) -> list:

return shift

self.stage.a = 0
self.stage.set(a=0)
# self.stage.z = 0 # for testing

zc = self.stage.z
Expand All @@ -410,7 +414,7 @@ def one_cycle(tilt: float = 5, sign=1) -> list:
sign = 1

for i, z in enumerate(zs):
self.stage.z = z
self.stage.set(z=z)
if verbose:
print(f'z = {z:.1f} nm')

Expand All @@ -419,9 +423,7 @@ def one_cycle(tilt: float = 5, sign=1) -> list:

sign *= -1

mean_shift = shifts[-1] + shifts[0]
mean_shift = mean_shift / np.linalg.norm(mean_shift)
ds = np.dot(shifts, mean_shift)
ds = np.sum(shifts, axis=1)

p = np.polyfit(zs, ds, 1) # linear fit
alpha, beta = p
Expand Down Expand Up @@ -592,6 +594,35 @@ def get_rotated_image(self, exposure: float = None, binsize: int = None) -> np.n

return arr

def get_rotated_raw_image(self, exposure: float = None, binsize: int = None) -> np.ndarray:
"""Simplified function equivalent to `get_image` that returns the
rotated image array.

Parameters
----------
exposure: float
Exposure time in seconds
binsize: int
Binning to use for the image, must be 1, 2, or 4, etc
mode : str
Magnification mode
mag : int
Magnification value

Returns
-------
arr : np.array
Image as 2D numpy array.
"""

mag = self.magnification.value
mode = self.mode.get()

arr = self.get_raw_image(exposure=exposure, binsize=binsize)
arr = rotate_image(arr, mode=mode, mag=mag)

return arr

def get_image(
self,
exposure: float = None,
Expand Down
19 changes: 12 additions & 7 deletions src/instamatic/experiments/autocred/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ def __init__(
except BaseException:
print('Is DIALS server running? Connection failed.')
self.s_c = 0
else:
self.s_c = 0

if use_vm:
self.s2 = socket.socket()
Expand All @@ -264,6 +266,12 @@ def __init__(
except BaseException:
print('Is VM server running? Connection failed.')
self.s2_c = 0
else:
self.s2_c = 0

@property
def magnification(self) -> float:
return self.ctrl.magnification.value

def image_cropper(self, img, window_size=0):
crystal_pos, r = find_defocused_image_center(
Expand Down Expand Up @@ -1152,7 +1160,7 @@ def raster_scan(self):
config.calibration['mag1']['pixelsize'][self.magnification] / 1000
) # nm -> um
xdim, ydim = self.ctrl.cam.get_camera_dimensions()
box_x, box_y = self.pixelsize_mag1 * xdim, self.pixelsize_mag1 * ydim
box_x, box_y = pixelsize_mag1 * xdim, pixelsize_mag1 * ydim

# Make negative to reflect config change 2019-07-03 to make omega more in line with other software
rot_axis = -config.camera.camera_rotation_vs_stage_xy
Expand Down Expand Up @@ -1185,7 +1193,6 @@ def raster_scan(self):
try:
img, h = self.ctrl.get_image(exposure=self.expt, header_keys=None)
if img.mean() > 10:
self.magnification = self.ctrl.magnification.value
crystal_positions = find_crystals_timepix(
img, self.magnification, spread=self.spread, offset=self.offset
)
Expand Down Expand Up @@ -1380,8 +1387,6 @@ def start_collection_point(self):
y=self.calib_beamshift.reference_shift[1],
)

self.magnification = self.ctrl.magnification.value

self.rotation_direction = self.eliminate_backlash_in_tiltx()
img, h = self.ctrl.get_image(exposure=self.expt, header_keys=header_keys)
# img, h = Experiment.apply_corrections(img, h)
Expand Down Expand Up @@ -1690,9 +1695,9 @@ def start_collection(self):
input(
'No z-height adjustment found. Please find an area with particles! Press Enter to continue auto adjustment of z height>>>'
)
x_zheight, y_zheight = center_z_height_HYMethod(
self.ctrl, spread=self.spread, offset=self.offset
)
# x_zheight, y_zheight = center_z_height_HYMethod(
# self.ctrl, spread=self.spread, offset=self.offset
# )
xpoint, ypoint, zpoint, aaa, bbb = self.ctrl.stage.get()
self.logger.info(
f'Stage position: x = {xpoint}, y = {ypoint}. Z height adjusted to {zpoint}. Tilt angle x {aaa} deg, Tilt angle y {bbb} deg'
Expand Down
6 changes: 3 additions & 3 deletions src/instamatic/experiments/red/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,12 @@ def start_collection(self, exposure_time: float, tilt_range: float, stepsize: fl
ctrl.cam.block()

# for i, a in enumerate(tilt_positions):
for i, angle in enumerate(tqdm(tilt_positions)):
ctrl.stage.a = angle
for i, angle in enumerate((tilt_positions)):
ctrl.stage.set(a=angle)

j = i + self.offset

img, h = self.ctrl.get_image(exposure_time)
img, h = ctrl.get_image(exposure_time, header_keys='')

self.buffer.append((j, img, h))

Expand Down
2 changes: 0 additions & 2 deletions src/instamatic/gui/autocred_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,6 @@ def acquire_data_autocRED(controller, **kwargs):
)
cexp.start_collection()

stop_event.clear()
stop_event_experiment.clear()
controller.log.info('Finish autocRED experiment')


Expand Down
18 changes: 18 additions & 0 deletions src/instamatic/gui/ctrl_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ def __init__(self, parent):
frame.pack(side='top', fill='x', padx=10, pady=10)

frame = Frame(self)
stage_reset_btn = Button(frame, text='Reset stage', command=self.reset_stage)
stage_reset_btn.grid(row=0, column=0, sticky='W')

Label(frame, text='Angle (-)', width=20).grid(row=1, column=0, sticky='W')
Label(frame, text='Angle (0)', width=20).grid(row=2, column=0, sticky='W')
Expand Down Expand Up @@ -161,6 +163,13 @@ def __init__(self, parent):
)
slider.grid(row=12, column=0, columnspan=3, sticky='EW')

# Magnification
Label(frame, text='Magnification', width=20).grid(row=14, column=0, sticky='W')
mag_inc_btn = Button(frame, text='+', command=self.increase_mag)
mag_inc_btn.grid(row=14, column=1)
mag_dec_btn = Button(frame, text='-', command=self.decrease_mag)
mag_dec_btn.grid(row=14, column=2)

frame.pack(side='top', fill='x', padx=10, pady=10)

frame = Frame(self)
Expand Down Expand Up @@ -228,6 +237,15 @@ def set_brightness(self, event=None):
def get_brightness(self, event=None):
self.var_brightness.set(self.ctrl.brightness.get())

def increase_mag(self):
self.ctrl.magnification.increase()

def decrease_mag(self):
self.ctrl.magnification.decrease()

def reset_stage(self):
self.ctrl.stage.set(0, 0, 0, 0, 0)

def set_difffocus(self, event=None):
self.var_difffocus.set(self.var_difffocus.get())
self.q.put(('ctrl', {'task': 'difffocus.set', 'value': self.var_difffocus.get()}))
Expand Down
2 changes: 1 addition & 1 deletion src/instamatic/microscope/microscope.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def get_microscope_class(interface: str) -> 'type[MicroscopeBase]':
raise PermissionError('Access to the TEM interface requires admin rights.')

if simulate or interface == 'simulate':
from .interface.simu_microscope import SimuMicroscope as cls
from ..simulation.microscope import MicroscopeSimulation as cls
elif interface == 'jeol':
from .interface.jeol_microscope import JeolMicroscope as cls
elif interface == 'fei':
Expand Down
4 changes: 2 additions & 2 deletions src/instamatic/processing/find_crystals.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def segment_crystals(img, r=101, offset=5, footprint=5, remove_carbon_lacing=Tru
# remove carbon lines
if remove_carbon_lacing:
arr = morphology.remove_small_objects(arr, min_size=8 * 8, connectivity=0)
arr = morphology.remove_small_holes(arr, min_size=32 * 32, connectivity=0)
arr = morphology.remove_small_holes(arr, area_threshold=32 * 32, connectivity=0)
arr = morphology.binary_dilation(arr, morphology.disk(footprint)) # dilation

# get background pixels
Expand Down Expand Up @@ -227,7 +227,7 @@ def main_entry():

for fn in args:
img, h = read_image(fn)

print(h)
crystals = find_crystals_timepix(img, h['exp_magnification'], plot=True)

for crystal in crystals:
Expand Down
32 changes: 32 additions & 0 deletions src/instamatic/simulation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from __future__ import annotations

from typing import Tuple

from instamatic import config
from instamatic.camera.camera_client import CamClient
from instamatic.camera.fakevideostream import VideoStream
from instamatic.microscope.client import MicroscopeClient
from instamatic.simulation.camera import CameraSimulation
from instamatic.simulation.microscope import MicroscopeSimulation


def get_simulation_instances() -> Tuple[CameraSimulation, MicroscopeSimulation]:
"""Initialize simulated camera and microscope.

Returns
-------
Tuple[CameraSimulation, MicroscopeSimulation]
"""
tem = MicroscopeSimulation()
cam = CameraSimulation(tem=tem)
return cam, tem
if config.settings.use_tem_server:
tem = MicroscopeClient(interface='simulate')
else:
tem = MicroscopeSimulation()
if config.settings.use_cam_server:
cam = CamClient(name='simulate', interface=config.camera.interface)
else:
camsim = CameraSimulation(tem=tem)
cam = VideoStream(camsim)
return cam, tem
Loading