Exemple #1
0
    def __init__(
        self,
        stop_event: LoggedEvent,
        saving_signal: LoggedEvent,
        wait_signal: LoggedEvent,
        noise_subtraction_on: Event,
        camera_queue: ArrayQueue,
        saver_queue: ArrayQueue,
        max_queue_size=1200,
    ):
        super().__init__(name="dispatcher")
        self.stop_event = stop_event
        self.saving_signal = saving_signal.new_reference(self.logger)
        self.wait_signal = wait_signal.new_reference(self.logger)
        self.noise_subtraction_active = noise_subtraction_on.new_reference(
            self.logger)

        self.camera_queue = camera_queue
        self.saver_queue = saver_queue
        self.n_planes_queue = Queue()
        self.viewer_queue = ArrayQueue(max_mbytes=max_queue_size)
        self.calibration_ref_queue = ArrayQueue()

        self.volume_buffer = None
        self.calibration_ref = None

        self.n_planes = 1
        self.i_plane = 0
        self.first_volume = True
 def __init__(
     self,
     stop_event: LoggedEvent,
     is_saving_event: LoggedEvent,
     duration_queue: Queue,
     max_queue_size=2000,
 ):
     super().__init__(name="saver")
     self.stop_event = stop_event.new_reference(self.logger)
     self.save_queue = ArrayQueue(max_mbytes=max_queue_size)
     self.saving_signal = is_saving_event
     self.saver_stopped_signal = LoggedEvent(self.logger,
                                             SashimiEvents.SAVING_STOPPED)
     self.saving = False
     self.saving_parameter_queue = Queue()
     self.save_parameters: Optional[SavingParameters] = SavingParameters()
     self.i_in_chunk = 0
     self.i_chunk = 0
     self.i_plane = 0
     self.i_volume = 0
     self.n_volumes = 10
     self.current_data = None
     self.saved_status_queue = Queue()
     self.frame_shape = None
     self.dtype = np.uint16
     self.duration_queue = duration_queue
     self.notifier = notifiers[conf["notifier"]]
Exemple #3
0
class ImageReconstructor(Process):
    def __init__(self, data_in_queue, stop_event, max_mbytes_queue=300):
        super().__init__()
        self.data_in_queue = data_in_queue
        self.parameter_queue = Queue()
        self.stop_event = stop_event
        self.output_queue = ArrayQueue(max_mbytes_queue)
        self.scanning_parameters = None
        self.waveform = None

    def run(self):
        while not self.stop_event.is_set():
            try:
                self.scanning_parameters = self.parameter_queue.get(
                    timeout=0.001)
                self.waveform = compute_waveform(self.scanning_parameters)
            except Empty:
                pass

            try:
                image = self.data_in_queue.get(timeout=0.001)
                self.output_queue.put(
                    scanning_patterns.reconstruct_image_pattern(
                        np.roll(image,
                                self.scanning_parameters.mystery_offset),
                        *self.waveform,
                        (self.scanning_parameters.n_x,
                         self.scanning_parameters.n_y),
                        self.scanning_parameters.n_bin,
                    ))
            except Empty:
                pass
Exemple #4
0
 def __init__(self, data_in_queue, stop_event, max_mbytes_queue=300):
     super().__init__()
     self.data_in_queue = data_in_queue
     self.parameter_queue = Queue()
     self.stop_event = stop_event
     self.output_queue = ArrayQueue(max_mbytes_queue)
     self.scanning_parameters = None
     self.waveform = None
Exemple #5
0
 def __init__(self,
              experiment_start_event,
              duration_queue,
              max_queuesize=200):
     super().__init__()
     self.data_queue = ArrayQueue(max_mbytes=max_queuesize)
     self.parameter_queue = Queue()
     self.stop_event = Event()
     self.experiment_start_event = experiment_start_event
     self.scanning_parameters = ScanningParameters()
     self.new_parameters = copy(self.scanning_parameters)
     self.duration_queue = duration_queue
     self.n_frames_queue = Queue()
Exemple #6
0
    def __init__(self, *args, signal_start_rec, output_queue_mb=500, **kwargs):
        super().__init__(*args, **kwargs)
        self.save_queue = ArrayQueue(max_mbytes=output_queue_mb)
        self.framestart_queue = Queue()
        self.diagnostic_queue = Queue()

        self.processing_parameters = MovementDetectionParameters(
        ).get_clean_values()

        self.signal_start_rec = signal_start_rec
        self.mem_use = 0

        self.diagnostic_params = [
            "n_pixels_difference",
            "recording_state",
            "n_images_in_buffer",
        ]
Exemple #7
0
 def __init__(self, n_items=100, timestamped=False, indexed=False,
              n_mbytes=2, wait=0, test_full=False):
     super().__init__()
     self.source_array = IndexedArrayQueue(max_mbytes==n_mbytes) if indexed \
         else (TimestampedArrayQueue(max_mbytes=n_mbytes) if timestamped \
                   else ArrayQueue(max_mbytes=n_mbytes))
     self.n_items = n_items
     self.wait = wait
     self.test_full = test_full
Exemple #8
0
    def __init__(self, diagnostics=False):
        super().__init__()
        if diagnostics:
            self.sequence_queue = Queue()
            self.sequence_diagram = SequenceDiagram(self.sequence_queue,
                                                    "main")

        self.experiment_start_event = Event()
        self.scanning_settings = ScanningSettings()
        self.experiment_settings = ExperimentSettings()
        self.pause_after = False

        self.parameter_tree = ParameterTree()
        self.parameter_tree.add(self.scanning_settings)
        self.parameter_tree.add(self.experiment_settings)

        self.end_event = Event()
        self.external_sync = ZMQcomm()
        self.duration_queue = Queue()
        self.scanner = Scanner(self.experiment_start_event,
                               duration_queue=self.duration_queue)
        self.scanning_parameters = None
        self.reconstructor = ImageReconstructor(self.scanner.data_queue,
                                                self.scanner.stop_event)
        self.save_queue = ArrayQueue(max_mbytes=800)

        self.saver = StackSaver(self.scanner.stop_event, self.save_queue,
                                self.scanner.n_frames_queue)
        self.save_status: Optional[SavingStatus] = None

        self.motors = dict()
        self.motors["x"] = MotorControl("COM6", axes="x")
        self.motors["y"] = MotorControl("COM6", axes="y")
        self.motors["z"] = MotorControl("COM6", axes="z")
        self.power_controller = LaserPowerControl()
        self.scanning_settings.sig_param_changed.connect(self.send_scan_params)
        self.scanning_settings.sig_param_changed.connect(self.send_save_params)
        self.scanner.start()
        self.reconstructor.start()
        self.saver.start()
        self.open_setup()

        self.paused = False
Exemple #9
0
    def __init__(
        self,
        stop_event: LoggedEvent,
        wait_event: LoggedEvent,
        exp_trigger_event: LoggedEvent,
        camera_id=0,
        max_queue_size=1200,
        n_fps_frames=20,
    ):
        super().__init__(name="camera")
        # Queue to communicate
        self.triggered_frame_rate_queue = Queue()
        self.parameter_queue = Queue()

        self.stop_event = stop_event.new_reference(self.logger)
        self.wait_event = wait_event.new_reference(self.logger)
        self.experiment_trigger_event = exp_trigger_event.new_reference(
            self.logger)
        self.image_queue = ArrayQueue(max_mbytes=max_queue_size)
        self.camera_id = camera_id
        self.camera = None
        self.parameters = CamParameters()
        self.framerate_rec = FramerateRecorder(n_fps_frames=n_fps_frames)
        self.was_waiting = False
Exemple #10
0
    def __init__(
        self,
        stop_event: LoggedEvent,
        waiting_event: LoggedEvent,
        restart_event: LoggedEvent,
        start_experiment_from_scanner=False,
        n_samples_waveform=10000,
        sample_rate=40000,
    ):
        """"""
        super().__init__(name="scanner")

        self.stop_event = stop_event.new_reference(self.logger)
        self.restart_event = restart_event.new_reference(self.logger)
        self.wait_signal = waiting_event.new_reference(self.logger)

        self.parameter_queue = Queue()

        self.waveform_queue = ArrayQueue(max_mbytes=100)
        self.n_samples = n_samples_waveform
        self.sample_rate = sample_rate

        self.parameters = ScanParameters()
        self.start_experiment_from_scanner = start_experiment_from_scanner
Exemple #11
0
class VolumeDispatcher(LoggingProcess):
    """

    Parameters
    ----------
    stop_event
    saving_signal
    wait_signal
    noise_subtraction_on
    camera_queue
    saver_queue
    max_queue_size

    """
    def __init__(
        self,
        stop_event: LoggedEvent,
        saving_signal: LoggedEvent,
        wait_signal: LoggedEvent,
        noise_subtraction_on: Event,
        camera_queue: ArrayQueue,
        saver_queue: ArrayQueue,
        max_queue_size=1200,
    ):
        super().__init__(name="dispatcher")
        self.stop_event = stop_event
        self.saving_signal = saving_signal.new_reference(self.logger)
        self.wait_signal = wait_signal.new_reference(self.logger)
        self.noise_subtraction_active = noise_subtraction_on.new_reference(
            self.logger)

        self.camera_queue = camera_queue
        self.saver_queue = saver_queue
        self.n_planes_queue = Queue()
        self.viewer_queue = ArrayQueue(max_mbytes=max_queue_size)
        self.calibration_ref_queue = ArrayQueue()

        self.volume_buffer = None
        self.calibration_ref = None

        self.n_planes = 1
        self.i_plane = 0
        self.first_volume = True

    def run(self):
        self.logger.log_message("started")
        while not self.stop_event.is_set():
            self.receive_options()
            self.get_frame()
        self.close_log()

    def process_frame(self, current_frame):
        if self.calibration_ref is not None and self.noise_subtraction_active.is_set(
        ):
            current_frame = neg_dif(current_frame, self.calibration_ref)

        if self.first_volume or self.volume_buffer.shape[
                1:3] != current_frame.shape:
            self.volume_buffer = np.empty(
                (self.n_planes, *current_frame.shape), dtype=np.uint16)
            self.first_volume = False

        self.logger.log_message(f"received plane {self.i_plane}")
        self.volume_buffer[self.i_plane, :, :] = current_frame
        self.i_plane += 1
        if self.i_plane == self.n_planes:
            self.fill_queues()
            self.i_plane = 0

    def fill_queues(self):
        if self.viewer_queue.queue.qsize() < 3:
            self.viewer_queue.put(self.volume_buffer)
        else:
            pass  # volume has been dropped from the viewer
        if self.saving_signal.is_set():
            self.saver_queue.put(self.volume_buffer)

    def get_frame(self):
        if self.wait_signal.is_set():
            self.logger.log_message("wait starting")
            self.saver_queue.clear()
            while self.wait_signal.is_set():
                try:
                    _ = self.camera_queue.get(timeout=TIMEOUT_S)
                except Empty:
                    pass
            self.logger.log_message("wait over")
            self.i_plane = 0
        try:
            current_frame = self.camera_queue.get(timeout=TIMEOUT_S)
            self.process_frame(current_frame)
        except Empty:
            pass

    def receive_options(self):
        # Get number of planes:
        n_planes = get_last_parameters(self.n_planes_queue, timeout=TIMEOUT_S)

        if n_planes is not None:
            self.n_planes = n_planes
            self.reset()

        # Get flat noise image to subtract:
        calibration_ref = get_last_parameters(self.calibration_ref_queue,
                                              timeout=TIMEOUT_S)
        if calibration_ref is not None:
            self.calibration_ref = calibration_ref

    def reset(self):
        self.first_volume = True
        self.i_plane = 0
class StackSaver(LoggingProcess):
    def __init__(
        self,
        stop_event: LoggedEvent,
        is_saving_event: LoggedEvent,
        duration_queue: Queue,
        max_queue_size=2000,
    ):
        super().__init__(name="saver")
        self.stop_event = stop_event.new_reference(self.logger)
        self.save_queue = ArrayQueue(max_mbytes=max_queue_size)
        self.saving_signal = is_saving_event
        self.saver_stopped_signal = LoggedEvent(self.logger,
                                                SashimiEvents.SAVING_STOPPED)
        self.saving = False
        self.saving_parameter_queue = Queue()
        self.save_parameters: Optional[SavingParameters] = SavingParameters()
        self.i_in_chunk = 0
        self.i_chunk = 0
        self.i_plane = 0
        self.i_volume = 0
        self.n_volumes = 10
        self.current_data = None
        self.saved_status_queue = Queue()
        self.frame_shape = None
        self.dtype = np.uint16
        self.duration_queue = duration_queue
        self.notifier = notifiers[conf["notifier"]]

    def run(self):
        self.logger.log_message("started")
        while not self.stop_event.is_set():
            if self.saving_signal.is_set(
            ) and self.save_parameters is not None:
                self.save_loop()
            else:
                self.receive_save_parameters()
        self.close_log()

    def save_loop(self):
        notifier = self.notifier("lightsheet", **conf["notifier_options"])
        # remove files if some are found at the save location
        Path(self.save_parameters.output_dir).mkdir(parents=True,
                                                    exist_ok=True)
        if (Path(self.save_parameters.output_dir) / "original" /
                "stack_metadata.json").is_file():
            shutil.rmtree(Path(self.save_parameters.output_dir) / "original")

        (Path(self.save_parameters.output_dir) / "original").mkdir(
            parents=True, exist_ok=True)
        self.i_in_chunk = 0
        self.i_chunk = 0
        self.i_volume = 0
        self.current_data = None

        while (self.i_volume < self.n_volumes and self.saving_signal.is_set()
               and not self.stop_event.is_set()):
            self.receive_save_parameters()
            try:
                frame = self.save_queue.get(timeout=0.01)
                self.logger.log_message("received volume")
                self.fill_dataset(frame)
            except Empty:
                pass

        if self.i_volume > 0:
            if self.i_in_chunk != 0:
                self.save_chunk()
            self.update_saved_status_queue()
            self.finalize_dataset()
            self.current_data = None
            if self.saving_signal.is_set():
                notifier.notify()

        self.saving_signal.clear()
        self.saver_stopped_signal.set()

        # Update status queue by resetting it:
        self.update_saved_status_queue()
        self.i_in_chunk = 0
        self.i_chunk = 0
        self.i_volume = 0
        self.save_parameters = None

    def fill_dataset(self, volume):
        if self.current_data is None:
            self.calculate_optimal_size(volume)
            self.current_data = np.empty(
                (self.save_parameters.chunk_size, *volume.shape),
                dtype=self.dtype,
            )

        self.current_data[self.i_in_chunk, :, :, :] = volume

        self.i_volume += 1
        self.i_in_chunk += 1
        self.update_saved_status_queue()

        if self.i_in_chunk == self.save_parameters.chunk_size:
            self.save_chunk()

    def update_saved_status_queue(self):
        self.saved_status_queue.put(
            SavingStatus(
                target_params=self.save_parameters,
                i_in_chunk=self.i_in_chunk,
                i_chunk=self.i_chunk,
                i_volume=self.i_volume,
                n_volumes=self.n_volumes,
            ))

    def finalize_dataset(self):
        self.logger.log_message("finished saving")
        with open(
            (Path(self.save_parameters.output_dir) / "original" /
             "stack_metadata.json"),
                "w",
        ) as f:
            json.dump(
                {
                    "shape_full": (
                        self.n_volumes,
                        *self.current_data.shape[1:],
                    ),
                    "shape_block": (
                        self.save_parameters.chunk_size,
                        *self.current_data.shape[1:],
                    ),
                    "crop_start": [0, 0, 0, 0],
                    "crop_end": [0, 0, 0, 0],
                    "padding": [0, 0, 0, 0],
                    "voxel_size":
                    self.save_parameters.voxel_size,
                },
                f,
            )

    def save_chunk(self):
        self.logger.log_message("saved chunk")
        fl.save(
            Path(self.save_parameters.output_dir) /
            "original/{:04d}.h5".format(self.i_chunk),
            {"stack_4D": self.current_data[:self.i_in_chunk, :, :, :]},
            compression="blosc",
        )
        self.i_in_chunk = 0
        self.i_chunk += 1

    def calculate_optimal_size(self, volume):
        if self.dtype == np.uint16:
            array_megabytes = (2 * volume.shape[0] * volume.shape[1] *
                               volume.shape[2] / 1048576)
        else:
            raise TypeError(
                "Saving data type not supported. Only uint16 is supported")
        self.save_parameters.chunk_size = int(
            self.save_parameters.optimal_chunk_MB_RAM / array_megabytes)

    def receive_save_parameters(self):
        """Receive parameters on the stack shape from the `State` obj and new duration
        from either the `EsternalTrigger` or the `State` if triggering is disabled.
        """
        # Get parameters:
        parameters = get_last_parameters(self.saving_parameter_queue)
        if parameters is not None:
            self.save_parameters = parameters

        # Get duration and update number of volumes:
        new_duration = get_last_parameters(self.duration_queue)
        if new_duration is not None:
            self.n_volumes = int(
                np.ceil(self.save_parameters.volumerate * new_duration))
Exemple #13
0
class CameraProcess(LoggingProcess):
    """Process that handles the setting of new parameters to and the acquisition of
    frames from the camera.

    Parameters
    ----------
    stop_event
    wait_event
    exp_trigger_event
    camera_id
    max_queue_size
    n_fps_frames
    """
    def __init__(
        self,
        stop_event: LoggedEvent,
        wait_event: LoggedEvent,
        exp_trigger_event: LoggedEvent,
        camera_id=0,
        max_queue_size=1200,
        n_fps_frames=20,
    ):
        super().__init__(name="camera")
        # Queue to communicate
        self.triggered_frame_rate_queue = Queue()
        self.parameter_queue = Queue()

        self.stop_event = stop_event.new_reference(self.logger)
        self.wait_event = wait_event.new_reference(self.logger)
        self.experiment_trigger_event = exp_trigger_event.new_reference(
            self.logger)
        self.image_queue = ArrayQueue(max_mbytes=max_queue_size)
        self.camera_id = camera_id
        self.camera = None
        self.parameters = CamParameters()
        self.framerate_rec = FramerateRecorder(n_fps_frames=n_fps_frames)
        self.was_waiting = False

    def initialize_camera(self):
        if conf["scopeless"]:
            self.camera = camera_class_dict["mock"]()
        else:
            self.camera = camera_class_dict[conf["camera"]["name"]](
                camera_id=conf["camera"]["id"],
                max_sensor_resolution=tuple(
                    conf["camera"]["max_sensor_resolution"]),
            )

    def run(self):
        self.logger.log_message("started")
        self.initialize_camera()
        self.run_camera()
        self.camera.shutdown()
        self.logger.close()

    def run_camera(self):
        """Main run for the camera. Depending on whether the camera mode is PAUSED or not,
        either the self.pause_loop or self.camera_loop are executed.
        """
        while not self.stop_event.is_set():
            # removed if statement based on camera mode: toggeling between modes is done in loops.
            self.pause_loop()
            self.camera_loop()

    def pause_loop(self):
        """Camera idle loop, just wait until parameters are updated. Check them, and if
        CameraMode.PAUSED is still set, return here.
        """
        self.logger.log_message("Paused aquisition")
        self.camera.stop_acquisition()
        while (not self.stop_event.is_set()
               and self.parameters.camera_mode == CameraMode.PAUSED):
            try:
                new_parameters = self.parameter_queue.get(timeout=0.001)
                if new_parameters != self.parameters:
                    self.update_parameters(new_parameters, stop_start=False)
                    if self.parameters.camera_mode != CameraMode.PAUSED:
                        break
            except Empty:
                pass

    def camera_loop(self):
        """Camera running loop, grab frames and set new parameters if available."""
        self.logger.log_message("Started acquisition")
        self.camera.start_acquisition()
        while (not self.stop_event.is_set()
               and self.parameters.camera_mode != CameraMode.PAUSED):
            is_waiting = self.wait_event.is_set()
            frames = self.camera.get_frames()

            # if no frames are received (either this loop is in between frames
            # or we are in the waining period)
            if frames:

                for frame in frames:
                    self.logger.log_message("received frame of shape " +
                                            str(frame.shape))
                    # this means this is the first frame received since
                    # the waiting period is over, the signal has to be sent that
                    # saving can start
                    if self.was_waiting and not is_waiting:
                        self.experiment_trigger_event.set()
                        # TODO do not crash here if queue is full
                    self.image_queue.put(frame)
                    self.was_waiting = is_waiting
                    self.update_framerate()

            # Empty parameters queue and set new parameters with the most recent value
            new_parameters = get_last_parameters(self.parameter_queue,
                                                 timeout=0.001)

            if new_parameters is not None:
                if new_parameters.camera_mode == CameraMode.ABORT or (
                        new_parameters != self.parameters):
                    self.update_parameters(new_parameters)

    def update_parameters(self, new_parameters, stop_start=True):
        """ "Set new parameters and stop and start the camera to make sure all changes take place."""
        self.parameters = new_parameters

        if stop_start:
            self.camera.stop_acquisition()

        # In general, ROI and binning are a bit funny in their interactions, and need to be handled
        # carefully in the specific camera interfaces.
        for attribute in ["binning", "roi", "exposure_time", "trigger_mode"]:
            setattr(self.camera, attribute, getattr(self.parameters,
                                                    attribute))

        if stop_start:
            self.camera.start_acquisition()
        self.framerate_rec.restart()
        self.logger.log_message("Updated parameters " + str(self.parameters))

    def update_framerate(self):
        self.framerate_rec.update_framerate()
        if self.framerate_rec.i_fps == 0:
            self.triggered_frame_rate_queue.put(
                self.framerate_rec.current_framerate)

    def close_camera(self):
        self.camera.shutdown()
Exemple #14
0
class Scanner(Process):
    def __init__(self,
                 experiment_start_event,
                 duration_queue,
                 max_queuesize=200):
        super().__init__()
        self.data_queue = ArrayQueue(max_mbytes=max_queuesize)
        self.parameter_queue = Queue()
        self.stop_event = Event()
        self.experiment_start_event = experiment_start_event
        self.scanning_parameters = ScanningParameters()
        self.new_parameters = copy(self.scanning_parameters)
        self.duration_queue = duration_queue
        self.n_frames_queue = Queue()

    def run(self):
        self.compute_scan_parameters()
        self.run_scanning()

    def compute_scan_parameters(self):
        self.extent_x = (
            -self.scanning_parameters.voltage_x,
            self.scanning_parameters.voltage_x,
        )
        self.extent_y = (
            -self.scanning_parameters.voltage_y,
            self.scanning_parameters.voltage_y,
        )

        self.n_x = self.scanning_parameters.n_x
        self.n_y = self.scanning_parameters.n_y
        self.raw_x, self.raw_y = compute_waveform(self.scanning_parameters)
        self.pos_x = (self.raw_x *
                      ((self.extent_x[1] - self.extent_x[0]) / self.n_x) +
                      self.extent_x[0])
        self.pos_y = (self.raw_y *
                      ((self.extent_y[1] - self.extent_y[0]) / self.n_y) +
                      self.extent_y[0])

        self.n_bin = self.scanning_parameters.n_bin

        self.n_samples_out = len(self.raw_x)
        self.n_samples_in = self.n_samples_out * self.n_bin

        self.sample_rate_out = self.scanning_parameters.sample_rate_out
        self.plane_duration = self.n_samples_out / self.sample_rate_out

        self.sample_rate_in = self.n_bin * self.sample_rate_out

        self.write_signals = np.stack([self.pos_x, self.pos_y], 0)
        self.read_buffer = np.zeros((2, self.n_samples_in))
        self.mystery_offset = self.scanning_parameters.mystery_offset

    def setup_tasks(self, read_task, write_task, shutter_task):
        # Configure the channels
        read_task.ai_channels.add_ai_voltage_chan(
            "Dev1/ai0:1", min_val=-1, max_val=1
        )  # channels are 0: green PMT, 1 x galvo pos 2 y galvo pos
        write_task.ao_channels.add_ao_voltage_chan("Dev1/ao0:1",
                                                   min_val=-10,
                                                   max_val=10)
        shutter_task.do_channels.add_do_chan(
            "Dev1/port0/line1", line_grouping=LineGrouping.CHAN_PER_LINE)
        # Set the timing of both to the onboard clock so that they are synchronised
        read_task.timing.cfg_samp_clk_timing(
            rate=self.sample_rate_in,
            source="OnboardClock",
            active_edge=Edge.RISING,
            sample_mode=AcquisitionType.CONTINUOUS,
            samps_per_chan=self.n_samples_in,
        )
        write_task.timing.cfg_samp_clk_timing(
            rate=self.sample_rate_out,
            source="OnboardClock",
            active_edge=Edge.RISING,
            sample_mode=AcquisitionType.CONTINUOUS,
            samps_per_chan=self.n_samples_out,
        )

        # This is necessary to synchronise reading and wrting
        read_task.triggers.start_trigger.cfg_dig_edge_start_trig(
            "/Dev1/ao/StartTrigger", Edge.RISING)

    def check_start_plane(self):
        if self.scanning_parameters.scanning_state == ScanningState.EXPERIMENT_RUNNING:
            while not self.experiment_start_event.is_set():
                sleep(0.00001)

    def calculate_duration(self):
        try:
            duration = self.duration_queue.get(timeout=0.0001)
            self.scanning_parameters.n_frames = (int(
                ceil(duration / frame_duration(self.scanning_parameters))) + 1)
            self.n_frames_queue.put(self.scanning_parameters.n_frames)
        except Empty:
            pass

    def scan_loop(self, read_task, write_task):
        writer = AnalogMultiChannelWriter(write_task.out_stream)
        reader = AnalogMultiChannelReader(read_task.in_stream)

        first_write = True
        i_acquired = 0
        while not self.stop_event.is_set() and (
                not self.scanning_parameters.scanning_state
                == ScanningState.EXPERIMENT_RUNNING
                or i_acquired < self.scanning_parameters.n_frames):
            # The first write has to be defined before the task starts
            try:
                writer.write_many_sample(self.write_signals)
                if i_acquired == 0:
                    self.check_start_plane()
                if first_write:
                    read_task.start()
                    write_task.start()
                    first_write = False
                reader.read_many_sample(
                    self.read_buffer,
                    number_of_samples_per_channel=self.n_samples_in,
                    timeout=1,
                )
                i_acquired += 1
            except nidaqmx.DaqError as e:
                print(e)
                break
            self.data_queue.put(self.read_buffer[0, :])
            # if new parameters have been received and changed, update
            # them, breaking out of the loop if the experiment is not running
            try:
                self.new_parameters = self.parameter_queue.get(timeout=0.0001)
                if self.new_parameters != self.scanning_parameters and (
                        self.scanning_parameters.scanning_state !=
                        ScanningState.EXPERIMENT_RUNNING
                        or self.new_parameters.scanning_state
                        == ScanningState.PREVIEW):
                    break
            except Empty:
                pass

            # calculate duration
            self.calculate_duration()

    def pause_loop(self):
        while not self.stop_event.is_set():
            try:
                self.new_parameters = self.parameter_queue.get(timeout=0.001)
                if self.new_parameters != self.scanning_parameters and (
                        self.scanning_parameters.scanning_state !=
                        ScanningState.EXPERIMENT_RUNNING
                        or self.new_parameters.scanning_state
                        == ScanningState.PREVIEW):
                    break
            except Empty:
                pass

    def toggle_shutter(self, shutter_task):
        shutter_task.write(False, auto_start=True)
        shutter_task.write(True, auto_start=True)
        shutter_task.write(False, auto_start=True)
        sleep(0.05)

    def run_scanning(self):
        while not self.stop_event.is_set():
            toggle_shutter = False
            if (self.new_parameters.scanning_state == ScanningState.PAUSED
                    and self.scanning_parameters.scanning_state !=
                    ScanningState.PAUSED
                ) or (
                    self.new_parameters.scanning_state != ScanningState.PAUSED
                    and self.scanning_parameters.scanning_state
                    == ScanningState.PAUSED):
                toggle_shutter = True

            self.scanning_parameters = self.new_parameters
            self.compute_scan_parameters()
            with Task() as write_task, Task() as read_task, Task(
            ) as shutter_task:
                self.setup_tasks(read_task, write_task, shutter_task)
                if self.scanning_parameters.reset_shutter or toggle_shutter:
                    self.toggle_shutter(shutter_task)
                if self.scanning_parameters.scanning_state == ScanningState.PAUSED:
                    self.pause_loop()
                else:
                    self.scan_loop(read_task, write_task)
Exemple #15
0
class ExperimentState(QObject):
    sig_scanning_changed = pyqtSignal()

    def __init__(self, diagnostics=False):
        super().__init__()
        if diagnostics:
            self.sequence_queue = Queue()
            self.sequence_diagram = SequenceDiagram(self.sequence_queue,
                                                    "main")

        self.experiment_start_event = Event()
        self.scanning_settings = ScanningSettings()
        self.experiment_settings = ExperimentSettings()
        self.pause_after = False

        self.parameter_tree = ParameterTree()
        self.parameter_tree.add(self.scanning_settings)
        self.parameter_tree.add(self.experiment_settings)

        self.end_event = Event()
        self.external_sync = ZMQcomm()
        self.duration_queue = Queue()
        self.scanner = Scanner(self.experiment_start_event,
                               duration_queue=self.duration_queue)
        self.scanning_parameters = None
        self.reconstructor = ImageReconstructor(self.scanner.data_queue,
                                                self.scanner.stop_event)
        self.save_queue = ArrayQueue(max_mbytes=800)

        self.saver = StackSaver(self.scanner.stop_event, self.save_queue,
                                self.scanner.n_frames_queue)
        self.save_status: Optional[SavingStatus] = None

        self.motors = dict()
        self.motors["x"] = MotorControl("COM6", axes="x")
        self.motors["y"] = MotorControl("COM6", axes="y")
        self.motors["z"] = MotorControl("COM6", axes="z")
        self.power_controller = LaserPowerControl()
        self.scanning_settings.sig_param_changed.connect(self.send_scan_params)
        self.scanning_settings.sig_param_changed.connect(self.send_save_params)
        self.scanner.start()
        self.reconstructor.start()
        self.saver.start()
        self.open_setup()

        self.paused = False

    @property
    def saving(self):
        return self.saver.saving_signal.is_set()

    def open_setup(self):
        self.send_scan_params()

    def start_experiment(self, first_plane=True):
        duration = self.external_sync.send(self.parameter_tree.serialize())
        if duration is None:
            self.restart_scanning()
            return False
        self.duration_queue.put(duration)
        params_to_send = convert_params(self.scanning_settings)
        params_to_send.scanning_state = ScanningState.EXPERIMENT_RUNNING
        self.scanner.parameter_queue.put(params_to_send)
        if first_plane:
            self.send_save_params()
            self.saver.saving_signal.set()
        self.experiment_start_event.set()
        return True

    def end_experiment(self, force=False):
        self.experiment_start_event.clear()

        if not force and self.save_status.i_z + 1 < self.save_status.target_params.n_z:
            self.advance_plane()
        else:
            self.saver.saving_signal.clear()
            if self.pause_after:
                self.pause_scanning()
            else:
                self.restart_scanning()

    def restart_scanning(self):
        params_to_send = convert_params(self.scanning_settings)
        params_to_send.scanning_state = ScanningState.PREVIEW
        self.scanner.parameter_queue.put(params_to_send)
        self.paused = False

    def pause_scanning(self):
        params_to_send = convert_params(self.scanning_settings)
        params_to_send.scanning_state = ScanningState.PAUSED
        self.scanner.parameter_queue.put(params_to_send)
        self.paused = True

    def advance_plane(self):
        self.motors["z"].move_rel(self.experiment_settings.dz / 1000)
        sleep(0.2)
        self.start_experiment(first_plane=False)

    def close_setup(self):
        """ Cleanup on programe close:
        end all parallel processes, close all communication channels

        """
        for motor in self.motors.values():
            motor.end_session()
        self.power_controller.terminate_connection()
        self.scanner.stop_event.set()
        self.end_event.set()
        self.scanner.join()
        self.reconstructor.join()

    def get_image(self):
        try:
            image = -self.reconstructor.output_queue.get(timeout=0.001)
            if self.saver.saving_signal.is_set():
                if (self.save_status is not None and self.save_status.i_t + 1
                        == self.save_status.target_params.n_t):
                    self.end_experiment()
                self.save_queue.put(image)
            return image
        except Empty:
            return None

    def send_scan_params(self):
        self.scanning_parameters = convert_params(self.scanning_settings)
        self.power_controller.move_abs(self.scanning_settings.laser_power)
        self.scanner.parameter_queue.put(self.scanning_parameters)
        self.reconstructor.parameter_queue.put(self.scanning_parameters)
        self.sig_scanning_changed.emit()

    def send_save_params(self):
        self.saver.saving_parameter_queue.put(
            SavingParameters(
                output_dir=Path(self.experiment_settings.save_dir),
                plane_size=(self.scanning_parameters.n_x,
                            self.scanning_parameters.n_y),
                n_z=self.experiment_settings.n_planes,
                notification_email=self.experiment_settings.notification_email,
                notification_frequency=self.experiment_settings.
                notify_every_n_planes))

    def get_save_status(self) -> Optional[SavingStatus]:
        try:
            self.save_status = self.saver.saved_status_queue.get(timeout=0.001)
            return self.save_status
        except Empty:
            pass
        return None
Exemple #16
0
class MovingFrameDispatcher(FrameDispatcher):
    """ """
    def __init__(self, *args, signal_start_rec, output_queue_mb=500, **kwargs):
        super().__init__(*args, **kwargs)
        self.save_queue = ArrayQueue(max_mbytes=output_queue_mb)
        self.framestart_queue = Queue()
        self.diagnostic_queue = Queue()

        self.processing_parameters = MovementDetectionParameters(
        ).get_clean_values()

        self.signal_start_rec = signal_start_rec
        self.mem_use = 0

        self.diagnostic_params = [
            "n_pixels_difference",
            "recording_state",
            "n_images_in_buffer",
        ]

    def run(self):
        """ """
        t, frame_0 = self.frame_queue.get(timeout=10)
        n_previous_compare = 3

        image_crop = slice(
            self.processing_parameters["frame_margin"],
            -self.processing_parameters["frame_margin"],
        )

        previous_ims = np.zeros(
            (n_previous_compare, ) + frame_0[image_crop].shape, dtype=np.uint8)

        image_buffer = deque()
        record_counter = 0

        i_frame = 0
        recording_state = False

        i_recorded = 0

        while not self.finished_signal.is_set():

            # Gets the processing parameters from their queue
            if self.processing_parameter_queue is not None:
                try:
                    self.processing_parameters = self.processing_parameter_queue.get(
                        timeout=0.00001)
                except Empty:
                    pass

            try:
                current_time, current_frame = self.frame_queue.get(
                    timeout=0.001)
                # process frames as they come, threshold them to roughly
                # find the fish (e.g. eyes)
                _, current_frame_thresh = cv2.threshold(
                    cv2.boxFilter(current_frame[image_crop], -1, (3, 3)),
                    self.processing_parameters["fish_threshold"],
                    255,
                    cv2.THRESH_BINARY,
                )
                # compare the thresholded frame to the previous ones,
                # if there are enough differences
                # because the fish moves, start recording to file
                if i_frame >= n_previous_compare:
                    difsum = _compare_to_previous(current_frame_thresh,
                                                  previous_ims)

                    # put the difference in the diagnostic queue so that
                    # the threshold can be set correctly

                    if np.all(difsum > self.
                              processing_parameters["motion_threshold_n_pix"]):
                        record_counter = self.processing_parameters[
                            "n_next_save"]

                    if record_counter > 0:
                        if self.signal_start_rec.is_set(
                        ) and self.mem_use < 0.9:
                            if not recording_state:
                                while image_buffer:
                                    time, im = image_buffer.popleft()
                                    self.framestart_queue.put(time)
                                    self.save_queue.put(im)
                                    i_recorded += 1
                            self.save_queue.put(current_frame)
                            self.framestart_queue.put(current_time)
                            i_recorded += 1
                        recording_state = True
                        record_counter -= 1
                    else:
                        recording_state = False
                        image_buffer.append((current_time, current_frame))
                        if (len(image_buffer) >
                                self.processing_parameters["n_previous_save"]):
                            image_buffer.popleft()

                    self.diagnostic_queue.put((
                        current_time,
                        (
                            difsum[i_frame % n_previous_compare],
                            recording_state,
                            len(image_buffer),
                        ),
                    ))

                i_frame += 1

                previous_ims[i_frame %
                             n_previous_compare, :, :] = current_frame_thresh

                # calculate the framerate and send frame to gui
                self.update_framerate()
                if self.processing_parameters["show_thresholded"]:
                    self.send_to_gui(current_frame_thresh)
                else:
                    self.send_to_gui(current_frame)

            except Empty:
                pass