diff --git a/.gitignore b/.gitignore index 264cc19d..d72bdfcb 100644 --- a/.gitignore +++ b/.gitignore @@ -133,3 +133,5 @@ ToDo.txt defaults.txt copylot/_version.py + +test_zarr diff --git a/copylot/hardware/hamamatsu_camera/camera.py b/copylot/hardware/hamamatsu_camera/camera.py index 66bee817..380d3a2e 100644 --- a/copylot/hardware/hamamatsu_camera/camera.py +++ b/copylot/hardware/hamamatsu_camera/camera.py @@ -1,15 +1,17 @@ from copylot.hardware.hamamatsu_camera.dcam import Dcamapi, Dcam - - -class CameraException(Exception): - pass +from napari._qt.qthreading import thread_worker class Camera: def __init__(self, camera_index: int = 0): self._camera_index = camera_index - def run(self, nb_frame: int = 100000): + def run(self, visualization_napari_layer): + worker = self.threaded_run(visualization_napari_layer) + worker.start() + + @thread_worker + def threaded_run(self, visualization_napari_layer, nb_frame: int = 100000): """ Method to run the camera. It handles camera initializations and uninitializations as well as camera buffer allocation/deallocation. @@ -34,6 +36,8 @@ def run(self, nb_frame: int = 100000): data = ( # noqa: F841 dcam.buf_getlastframedata() ) # Data is here + visualization_napari_layer.data = data + print("data is here") else: dcamerr = dcam.lasterr() if dcamerr.is_timeout(): @@ -46,23 +50,17 @@ def run(self, nb_frame: int = 100000): dcam.cap_stop() else: - raise CameraException( - f"dcam.cap_start() fails with error {dcam.lasterr()}" - ) + print(f"dcam.cap_start() fails with error {dcam.lasterr()}") dcam.buf_release() # release buffer else: - raise CameraException( + print( f"dcam.buf_alloc({nb_buffer_frames}) fails with error {dcam.lasterr()}" ) dcam.dev_close() else: - raise CameraException( - f"dcam.dev_open() fails with error {dcam.lasterr()}" - ) + print(f"dcam.dev_open() fails with error {dcam.lasterr()}") else: - raise CameraException( - f"Dcamapi.init() fails with error {Dcamapi.lasterr()}" - ) + print(f"Dcamapi.init() fails with error {Dcamapi.lasterr()}") Dcamapi.uninit() diff --git a/copylot/hardware/hamamatsu_camera/dcam.py b/copylot/hardware/hamamatsu_camera/dcam.py index 200d1799..bfdea1db 100644 --- a/copylot/hardware/hamamatsu_camera/dcam.py +++ b/copylot/hardware/hamamatsu_camera/dcam.py @@ -5,7 +5,7 @@ # # The declarations of classes and functions in this file are subject to change without notice. -from dcamapi4 import * +from .dcamapi4 import * import numpy as np diff --git a/copylot/hardware/live_asi_stage_debug.py b/copylot/hardware/live_asi_stage_debug.py new file mode 100644 index 00000000..da9c0cfd --- /dev/null +++ b/copylot/hardware/live_asi_stage_debug.py @@ -0,0 +1,37 @@ +from copylot.hardware.asi_stage.stage import ASIStage, ASIStageScanMode + + +# Define constants +scan_mode = ASIStageScanMode.RASTER +speed = 0.155 / 2 +range_in_um = 250 +offset = 300 +port = "COM6" + +# Create ASIStage instance +asi_stage = ASIStage(com_port=port) + +# Initialize the stage and zero it +asi_stage.set_scan_mode(scan_mode) +asi_stage.set_backlash() +asi_stage.set_speed(speed=speed) +asi_stage.zero() + +view = 0 + + +for _ in range(300): + # Set scan range + if view == 0: + asi_stage.scanr(x=0, y=range_in_um / 1000) + asi_stage.scanv(x=0, y=0, f=1.0) + else: + asi_stage.scanr( + x=-offset / 1000, y=(-offset + range_in_um) / 1000 + ) + asi_stage.scanv(x=0, y=0, f=1.0) + + asi_stage.start_scan() + +asi_stage.set_default_speed() + diff --git a/copylot/hardware/ni_daq/demo/nidaq_demo.py b/copylot/hardware/ni_daq/demo/nidaq_demo.py index f960b49a..fffd3787 100644 --- a/copylot/hardware/ni_daq/demo/nidaq_demo.py +++ b/copylot/hardware/ni_daq/demo/nidaq_demo.py @@ -4,7 +4,7 @@ if __name__ == "__main__": daq_card = NIDaq( exposure=0.100, - nb_timepoints=2000, # number of timepoints + nb_timepoints=1, # number of timepoints scan_step=0.155 * 5, # TTL100, 0.310, TTL300 0.103, TTL200 0.155 0.155 * 2 scan_range=250, # starts from current position vertical_pixels=2048, # used to calculate the readout time @@ -37,5 +37,5 @@ # scanning mode: 'Stage', 'Gavlo', 'O1' daq_card.acquire_stacks( - channels=['488', '561'], view=3, scan_option="Stage", interleave=False + channels=['488'], view=3, scan_option="Stage", interleave=False ) diff --git a/copylot/hardware/trial_timelapse.py b/copylot/hardware/trial_timelapse.py new file mode 100644 index 00000000..452182ce --- /dev/null +++ b/copylot/hardware/trial_timelapse.py @@ -0,0 +1,225 @@ +""" +This is a script to run basic timelapse together with the +nidaq script. This script tries to mimic the behavior given +in the stageScan_multiPos.bsh script. +""" +import time +from os.path import join +import tensorstore as ts + +from copylot.hardware.asi_stage.stage import ASIStage, ASIStageScanMode +from copylot.hardware.hamamatsu_camera.dcam import Dcamapi, Dcam, DCAM_IDPROP, DCAMPROP + +path = "D:/data/20210506_xiang" +path_prefix = "stage_TL100_range500um_step0.31_4um_30ms_view2_interval_2s_488_20mW_561_10mW_1800tp_3pos" + +nb_channel = 1 +nb_view = 2 +channels = ["488"] +interleave = False + +nb_frames = 1 # number of timepoint +step_size_um = 0.155 * 5 +range_in_um = 5 +interval_timepoint_in_seconds = 0 +interval_in_seconds = 2 + +scan_mode = ASIStageScanMode.RASTER # raster or serpentine +custom_offset_in_um = 300 # offset between two views for better coverage +# nr_channels = nb_view + +if nb_channel == 1: + interleave = True + +if not interleave and len(channels) != nb_channel: + print("number of channels is not consistent") + nb_channel = len(channels) + +angle = 45 +res = 0.219 # xy pixel size, TTL100 0.439, TTL200 0.219, TTL300 0.146, TTL165 0.266 + +alignment_offset_in_um = 0 +galvo_offset_in_um = 0 +offset = alignment_offset_in_um + galvo_offset_in_um + custom_offset_in_um + +nb_slices = int(range_in_um // step_size_um) +# reset the scanning range for multi channel imaging +if nb_slices % nb_channel != 0 and interleave: + nb_slices -= nb_slices % nb_channel + range_in_um = nb_slices * step_size_um +print(f"nb_slices: {nb_slices}") + + +exposure_in_ms = 10 +print(f"exposure in ms: {exposure_in_ms}") + + +port = "COM6" +asi_stage = ASIStage(com_port=port) + +speed = step_size_um / exposure_in_ms +print(f"scan range in um: {range_in_um}") + + +save_path = join(path, path_prefix) + +axis_order = ["z", "channel", "time", "position"] + + +def main(): + dataset = ts.open( + { + "driver": "zarr", + 'kvstore': { + 'driver': 'file', + 'path': r'C:\Users\PiscesScope\Documents\acs\coPylot\test_zarr', + }, + "key_encoding": ".", + "metadata": { + "shape": [nb_slices, nb_view, nb_frames, 2048, 2048], + "chunks": [128, 1, 128, 128, 128], + "dtype": " fps_calculation_interval: + print("FPS: ", counter / (time.time() - start_time)) + counter = 0 + start_time = time.time() + + for f in range(nb_frames): + for view in range(nb_view): + for slice in range(nb_slices): + write_futures[ + f * (nb_slices * nb_view) + view * nb_slices + slice + ].result() + + # Set camera for internal trigger and validate + dcam.prop_setvalue( + DCAM_IDPROP.TRIGGERSOURCE, DCAMPROP.TRIGGERSOURCE.INTERNAL + ) + + else: + print( + '-NG: Dcam.buf_alloc(3) fails with error {}'.format(dcam.lasterr()) + ) + dcam.dev_close() + + else: + print('-NG: Dcam.dev_open() fails with error {}'.format(dcam.lasterr())) + + else: + print(f"Dcamapi.init() fails with error {Dcamapi.lasterr()}") + + Dcamapi.uninit() + + asi_stage.set_default_speed() + + +if __name__ == '__main__': + main()