Ejemplo n.º 1
0
    def test_compressed_stack(self):
        """
       Test the whole procedure (acquire compressed zstack + stitch) of acquireTiledArea function
       """
        # With fm streams
        settings_obs = SettingsObserver([self.stage])
        fm_fov = compute_camera_fov(self.ccd)
        # Using "songbird-sim-ccd.h5" in simcam with tile max_res: (260, 348)
        area = (0, 0, fm_fov[0] * 2, fm_fov[1] * 2)  # left, top, right, bottom
        overlap = 0.2
        focus_value = self.focus.position.value['z']
        zsteps = 3
        # Create focus zlevels from the given zsteps number
        zlevels = numpy.linspace(focus_value - (zsteps / 2 * 1e-6),
                                 focus_value + (zsteps / 2 * 1e-6),
                                 zsteps).tolist()

        future = acquireTiledArea(self.fm_streams,
                                  self.stage,
                                  area=area,
                                  overlap=overlap,
                                  settings_obs=settings_obs,
                                  zlevels=zlevels)
        data = future.result()
        self.assertTrue(future.done())
        self.assertEqual(len(data), 2)
        self.assertIsInstance(data[0], model.DataArray)
        self.assertEqual(len(data[0].shape), 2)
Ejemplo n.º 2
0
def _run_overview_acquisition(f, stream, stage, area, live_stream):
    """
    :returns: (DataArray)
    """
    _configure_overview_hw(stream.emitter)

    # The stage movement precision is quite good (just a few pixels). The stage's
    # position reading is much better, and we can assume it's below a pixel.
    # So as long as we are sure there is some overlap, the tiles will be positioned
    # correctly and without gap.
    overlap = STAGE_PRECISION / stream.emitter.horizontalFoV.value
    logging.debug("Overlap is %s%%", overlap * 100)  # normally < 1%

    def _pass_future_progress(sub_f, start, end):
        f.set_progress(start, end)

    # Note, for debugging, it's possible to keep the intermediary tiles with log_path="./tile.ome.tiff"
    sf = stitching.acquireTiledArea([stream],
                                    stage,
                                    area,
                                    overlap,
                                    registrar=REGISTER_IDENTITY)
    # Connect the progress of the underlying future to the main future
    sf.add_update_callback(_pass_future_progress)
    das = sf.result()

    if len(das) != 1:
        logging.warning("Expected 1 DataArray, but got %d: %r", len(das), das)
    return das[0]
Ejemplo n.º 3
0
    def test_cancel(self):
        """
        Test cancelling of acquireTiledArea function
        """
        self.start = None
        self.end = None
        self.updates = 0
        self.done = False
        # Get area from stage metadata
        area = (-0.0001, -0.0001, 0.0001, 0.0001)
        overlap = 0.2
        f = acquireTiledArea(self.fm_streams,
                             self.stage,
                             area=area,
                             overlap=overlap)
        f.add_update_callback(self.on_progress_update)
        f.add_done_callback(self.on_done)

        time.sleep(1)  # make sure it's started
        self.assertTrue(f.running())
        f.cancel()

        self.assertRaises(CancelledError, f.result, 1)
        self.assertGreaterEqual(self.updates,
                                1)  # at least one update at cancellation
        self.assertLessEqual(self.end, time.time())
        self.assertTrue(self.done)
        self.assertTrue(f.cancelled())
Ejemplo n.º 4
0
    def on_acquire(self, evt):
        """ Start the actual acquisition """
        logging.info("Acquire button clicked, starting acquisition")
        acq_streams = self.get_acq_streams()
        if not acq_streams:
            logging.info("No stream to acquire, ending immediately")
            self.on_close(
                evt)  # Nothing to do, so it's the same as closing the window

        self.acquiring = True

        # Adjust view FoV to the whole area, so that it's possible to follow the acquisition
        self._fit_view_to_area()

        self.btn_secom_acquire.Disable()

        # Freeze all the settings so that it's not possible to change anything
        self._pause_settings()

        self.gauge_acq.Show()
        self.Layout()  # to put the gauge at the right place

        # For now, always indicate the best quality
        if self._main_data_model.opm:
            self._main_data_model.opm.setAcqQuality(path.ACQ_QUALITY_BEST)

        zlevels = self._get_zstack_levels()
        focus_mtd = FocusingMethod.MAX_INTENSITY_PROJECTION if zlevels else FocusingMethod.NONE

        if self.filename_tiles:
            logging.info("Acquisition tiles logged at %s", self.filename_tiles)
            os.makedirs(os.path.dirname(self.filename_tiles))

        self.acq_future = stitching.acquireTiledArea(
            acq_streams,
            self._main_data_model.stage,
            area=self.area,
            overlap=self.overlap,
            settings_obs=self._main_data_model.settings_obs,
            log_path=self.filename_tiles,
            weaver=WEAVER_COLLAGE_REVERSE,
            zlevels=zlevels,
            focusing_method=focus_mtd)
        self._acq_future_connector = ProgressiveFutureConnector(
            self.acq_future, self.gauge_acq, self.lbl_acqestimate)
        # TODO: Build-up the complete image during the acquisition, so that the
        #       progress can be followed live.
        self.acq_future.add_done_callback(self.on_acquisition_done)

        self.btn_cancel.SetLabel("Cancel")
        self.btn_cancel.Bind(wx.EVT_BUTTON, self.on_cancel)
Ejemplo n.º 5
0
def _run_overview_acquisition(f, stream, stage, area, live_stream):
    """
    Runs the acquisition of one overview image (typically one scintillator).

    :param f: (ProgressiveFuture) Acquisition future object.
    :param stream: (SEMstream) The stream used for the acquisition.
    :param stage: (actuator.MultiplexActuator) The stage in the sample carrier coordinate system.
        The x and y axes are aligned with the x and y axes of the ebeam scanner.
    :param area: (float, float, float, float) xmin, ymin, xmax, ymax coordinates of the overview region.
    :param live_stream: (StaticStream or None): StaticStream to be updated with each tile acquired,
           to build up live the whole acquisition. NOT SUPPORTED YET.

    :returns: (DataArray) The complete overview image.
    """
    fastem_conf.configure_scanner(stream.emitter, fastem_conf.OVERVIEW_MODE)

    # The stage movement precision is quite good (just a few pixels). The stage's
    # position reading is much better, and we can assume it's below a pixel.
    # So as long as we are sure there is some overlap, the tiles will be positioned
    # correctly and without gap.
    overlap = STAGE_PRECISION / stream.emitter.horizontalFoV.value
    logging.debug("Overlap is %s%%", overlap * 100)  # normally < 1%

    def _pass_future_progress(sub_f, start, end):
        f.set_progress(start, end)

    # Note, for debugging, it's possible to keep the intermediary tiles with log_path="./tile.ome.tiff"
    sf = stitching.acquireTiledArea([stream],
                                    stage,
                                    area,
                                    overlap,
                                    registrar=REGISTER_IDENTITY,
                                    focusing_method=FocusingMethod.NONE)
    # Connect the progress of the underlying future to the main future
    # FIXME removed to provide better progress update in GUI
    #  When _tiledacq.py has proper time update implemented, add this line here again.
    # sf.add_update_callback(_pass_future_progress)
    das = sf.result()

    if len(das) != 1:
        logging.warning("Expected 1 DataArray, but got %d: %r", len(das), das)

    # Switch immersion mode back on, so we can focus the SEM from the TFS GUI.
    stream.emitter.immersion.value = True

    # FIXME auto blanking not working properly, so force beam blanking after image acquisition for now.
    stream.emitter.blanker.value = True

    return das[0]
Ejemplo n.º 6
0
    def test_whole_procedure(self):
        """
        Test the whole procedure (acquire + stitch) of acquireTiledArea function
        """
        # With fm streams
        settings_obs = SettingsObserver([self.stage])

        fm_fov = compute_camera_fov(self.ccd)
        # Using "songbird-sim-ccd.h5" in simcam with tile max_res: (260, 348)
        area = (0, 0, fm_fov[0] * 4, fm_fov[1] * 4)  # left, bottom, right, top
        overlap = 0.2
        self.stage.moveAbs({'x': 0, 'y': 0}).result()
        future = acquireTiledArea(self.fm_streams,
                                  self.stage,
                                  area=area,
                                  overlap=overlap,
                                  settings_obs=settings_obs,
                                  weaver=WEAVER_COLLAGE_REVERSE)
        data = future.result()
        self.assertEqual(future._state, FINISHED)
        self.assertEqual(len(data), 2)
        self.assertIsInstance(data[0], model.DataArray)
        self.assertEqual(len(data[0].shape), 2)

        # With sem stream
        area = (0, 0, 0.00001, 0.00001)
        self.stage.moveAbs({'x': 0, 'y': 0}).result()
        future = acquireTiledArea(self.sem_streams,
                                  self.stage,
                                  area=area,
                                  overlap=overlap)
        data = future.result()
        self.assertEqual(future._state, FINISHED)
        self.assertEqual(len(data), 1)
        self.assertIsInstance(data[0], model.DataArray)
        self.assertEqual(len(data[0].shape), 2)
Ejemplo n.º 7
0
    def test_registrar_weaver(self):

        overlap = 0.05  # Little overlap, no registration
        sem_fov = compute_scanner_fov(self.ebeam)
        area = (0, 0, sem_fov[0], sem_fov[1])
        self.stage.moveAbs({'x': 0, 'y': 0}).result()
        future = acquireTiledArea(self.sem_streams,
                                  self.stage,
                                  area=area,
                                  overlap=overlap,
                                  registrar=REGISTER_IDENTITY,
                                  weaver=WEAVER_MEAN)
        data = future.result()
        self.assertEqual(future._state, FINISHED)
        self.assertEqual(len(data), 1)
        self.assertIsInstance(data[0], model.DataArray)
        self.assertEqual(len(data[0].shape), 2)
Ejemplo n.º 8
0
    def test_progress(self):
        """
       Test progress update of acquireTiledArea function
        """
        self.start = None
        self.end = None
        self.updates = 0
        area = (0, 0, 0.00001, 0.00001)  # left, top, right, bottom
        overlap = 0.2
        self.stage.moveAbs({'x': 0, 'y': 0}).result()
        f = acquireTiledArea(self.sem_streams,
                             self.stage,
                             area=area,
                             overlap=overlap)

        f.add_update_callback(self.on_progress_update)

        data = f.result()
        self.assertIsInstance(data[0], model.DataArray)
        self.assertGreaterEqual(self.updates,
                                2)  # at least one update per stream
Ejemplo n.º 9
0
    def test_area(self):
        """
        Test the acquired area matches the requested area
        """
        fm_fov = compute_camera_fov(self.ccd)
        # Using "songbird-sim-ccd.h5" in simcam with tile max_res: (260, 348)
        area = (0, 0, fm_fov[0] * 2, fm_fov[1] * 3)  # left, bottom, right, top
        overlap = 0.2

        # No focuser, to make it faster, and it doesn't affect the FoV
        fs = stream.FluoStream("fluo1", self.ccd, self.ccd.data, self.light,
                               self.light_filter)
        future = acquireTiledArea([fs],
                                  self.stage,
                                  area=area,
                                  overlap=overlap,
                                  registrar=REGISTER_IDENTITY,
                                  weaver=WEAVER_MEAN)
        data = future.result()
        self.assertIsInstance(data[0], model.DataArray)
        self.assertEqual(len(data[0].shape), 2)

        # The center should be almost precisely at the center of the request RoA,
        # modulo the stage precision (which is very good on the simulator).
        # The size can be a little bit bigger (but never smaller), as it's
        # rounded up to a tile.
        bbox = img.getBoundingBox(data[0])
        data_center = data[0].metadata[model.MD_POS]
        area_center = (area[0] + area[2]) / 2, (area[1] + area[3]) / 2
        logging.debug("Expected area: %s %s, actual area: %s %s", area,
                      area_center, bbox, data_center)
        self.assertAlmostEqual(data_center[0], area_center[0],
                               delta=1e-6)  # +- 1µm
        self.assertAlmostEqual(data_center[1], area_center[1],
                               delta=1e-6)  # +- 1µm

        self.assertTrue(area[0] - fm_fov[0] / 2 <= bbox[0] <= area[0])
        self.assertTrue(area[1] - fm_fov[1] / 2 <= bbox[1] <= area[1])
        self.assertTrue(area[2] <= bbox[2] <= area[2] + fm_fov[0] / 2)
        self.assertTrue(area[3] <= bbox[3] <= area[3] + fm_fov[1] / 2)
Ejemplo n.º 10
0
def _run_overview_acquisition(f, stream, stage, area, live_stream):
    """
    :returns: (DataArray)
    """
    fastem_conf.configure_scanner(stream.emitter, fastem_conf.OVERVIEW_MODE)

    # The stage movement precision is quite good (just a few pixels). The stage's
    # position reading is much better, and we can assume it's below a pixel.
    # So as long as we are sure there is some overlap, the tiles will be positioned
    # correctly and without gap.
    overlap = STAGE_PRECISION / stream.emitter.horizontalFoV.value
    logging.debug("Overlap is %s%%", overlap * 100)  # normally < 1%

    def _pass_future_progress(sub_f, start, end):
        f.set_progress(start, end)

    # Note, for debugging, it's possible to keep the intermediary tiles with log_path="./tile.ome.tiff"
    sf = stitching.acquireTiledArea([stream],
                                    stage,
                                    area,
                                    overlap,
                                    registrar=REGISTER_IDENTITY,
                                    focusing_method=FocusingMethod.NONE)
    # Connect the progress of the underlying future to the main future
    sf.add_update_callback(_pass_future_progress)
    das = sf.result()

    if len(das) != 1:
        logging.warning("Expected 1 DataArray, but got %d: %r", len(das), das)

    # Switch immersion mode back on, so we can focus the SEM from the TFS GUI.
    stream.emitter.immersion.value = True

    # FIXME auto blanking not working properly, so force beam blanking after image acquisition for now.
    stream.emitter.blanker.value = True

    return das[0]