Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Camera driver updates #88

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,5 @@ ToDo.txt
defaults.txt

copylot/_version.py

test_zarr
28 changes: 13 additions & 15 deletions copylot/hardware/hamamatsu_camera/camera.py
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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():
Expand All @@ -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()
2 changes: 1 addition & 1 deletion copylot/hardware/hamamatsu_camera/dcam.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
37 changes: 37 additions & 0 deletions copylot/hardware/live_asi_stage_debug.py
Original file line number Diff line number Diff line change
@@ -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()

4 changes: 2 additions & 2 deletions copylot/hardware/ni_daq/demo/nidaq_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
)
225 changes: 225 additions & 0 deletions copylot/hardware/trial_timelapse.py
Original file line number Diff line number Diff line change
@@ -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": "<i2",
"order": "C",
"compressor": {
"id": "blosc",
"shuffle": -1,
"clevel": 5,
"cname": "lz4",
},
},
'create': True,
'delete_existing': True,
}
).result()

write_futures = [None] * int(nb_slices * nb_view * nb_frames)

asi_stage.set_scan_mode(scan_mode)
asi_stage.set_backlash()
asi_stage.set_speed(speed=speed)
asi_stage.zero()

if Dcamapi.init():
dcam = Dcam(0)
if dcam.dev_open():

# Set camera for external trigger and validate
dcam.prop_setvalue(
DCAM_IDPROP.TRIGGER_MODE, DCAMPROP.TRIGGER_MODE.NORMAL
)
dcam.prop_setvalue(
DCAM_IDPROP.TRIGGERPOLARITY, DCAMPROP.TRIGGERPOLARITY.POSITIVE
)
dcam.prop_setvalue(
DCAM_IDPROP.TRIGGER_CONNECTOR, DCAMPROP.TRIGGER_CONNECTOR.BNC
)
dcam.prop_setvalue(
DCAM_IDPROP.TRIGGERTIMES, 1
)
dcam.prop_setvalue(
DCAM_IDPROP.TRIGGERDELAY, 0
)


dcam.prop_setvalue(
DCAM_IDPROP.TRIGGERSOURCE, DCAMPROP.TRIGGERSOURCE.EXTERNAL
)
dcam.prop_setvalue(
DCAM_IDPROP.TRIGGERACTIVE, DCAMPROP.TRIGGERACTIVE.SYNCREADOUT
)

# Set camera trigger delay and validate
dcam.prop_setvalue(DCAM_IDPROP.TRIGGERDELAY, 0.0)

if dcam.buf_alloc(3):
start_time = time.time()

# Acquisition loop
for f in range(nb_frames):
for view in range(nb_view):

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)
print(f"scan range in um: {range_in_um}")

# if interleave:
print(f"start interleaved acquisition: {interleave}")

counter = 0
slice = 0
timeout_milisec = 1000
fps_calculation_interval = 1

while slice < nb_slices:
asi_stage.start_scan()
dcam.cap_start()

if dcam.wait_capevent_frameready(timeout_milisec):
data = dcam.buf_getlastframedata()
print(data.shape)

# Async write
# write_futures[
# f * (nb_slices * nb_view) + view * nb_slices + slice
# ] = dataset[slice, view, f, :, :].write(data)

else:
dcamerr = dcam.lasterr()
if dcamerr.is_timeout():
print('===: timeout')
else:
print(
'-NG: Dcam.wait_event() fails with error {}'.format(
dcamerr
)
)
break

print(dcam.cap_status())
print(dcam.cap_transferinfo().nNewestFrameIndex, dcam.cap_transferinfo().nFrameCount)

slice += 1
counter += 1

if (time.time() - start_time) > 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()