Beispiel #1
0
    def _initialize_ovv_im(self, shape):
        """
        Initialize an overview image, i.e. a black DataArray with corresponding
        metadata. 
        shape (int, int, int): XYC tuple
        returns:
            DataArray of shape XYC: a new DataArray, black, with PIXEL_SIZE and POS metadata
              to fit the stage (active) range
            (float, float): mpp value
        """
        # Initialize the size of the ovv image with the MD_POS_ACTIVE_RANGE,
        # fallback to the stage size.
        # It it's too "big" (> 5cm) fallback to OVV_SHAPE.
        stg_md = self.main_data.stage.getMetadata()

        def get_range(an):
            ax_def = self.main_data.stage.axes[an]
            rng = None
            if hasattr(ax_def, "range"):
                rng = ax_def.range

            try:
                rng = stg_md[MD_POS_ACTIVE_RANGE][an]
            except KeyError:
                pass
            except Exception:
                logging.exception("Failed to get active range for axis %s", an)

            return rng

        rng_x = get_range("x")
        rng_y = get_range("y")

        mpp = max(MAX_OVV_SIZE / shape[0], MAX_OVV_SIZE / shape[1])
        pos = self.m_view.view_pos.value
        if rng_x is not None and rng_y is not None:
            max_x = rng_x[1] - rng_x[0]
            max_y = rng_y[1] - rng_y[0]
            if max_x < MAX_OVV_SIZE and max_y < MAX_OVV_SIZE:
                mpp = max(max_x / shape[0], max_y / shape[1])
            pos = sum(rng_x) / 2, sum(rng_y) / 2

        ovv_im = DataArray(numpy.zeros(shape, dtype=numpy.uint8))
        ovv_im.metadata[MD_DIMS] = "YXC"
        ovv_im.metadata[MD_PIXEL_SIZE] = (mpp, mpp)
        ovv_im.metadata[MD_POS] = pos

        return ovv_im, mpp
Beispiel #2
0
    def constructCube(self, images):
        # images is a list of 3 dim data arrays.
        ret = []
        for image in images:
            stack = numpy.dstack(image)
            stack = numpy.swapaxes(stack, 1, 2)
            ret.append(stack[0])

        # Add back metadata
        metadata3d = copy.copy(images[0].metadata)
        # Extend pixel size to 3D
        ps_x, ps_y = metadata3d[model.MD_PIXEL_SIZE]
        ps_z = self.zstep.value

        # Computer cube centre
        c_x, c_y = metadata3d[model.MD_POS]
        c_z = self.zstart.value + (self.zstep.value * self.numberOfAcquisitions.value) / 2
        metadata3d[model.MD_POS] = (c_x, c_y, c_z)

        # For a negative pixel size, convert to a positive and flip the z axis
        if ps_z < 0:
            ret = numpy.flipud(ret)
            ps_z = -ps_z

        metadata3d[model.MD_PIXEL_SIZE] = (ps_x, ps_y, abs(ps_z))
        metadata3d[model.MD_DIMS] = "ZYX"

        ret = DataArray(ret, metadata3d)

        return ret
Beispiel #3
0
def assembleZCube(images, zlevels):
    """
        Construct xyz cube from a  z stack of images
        :param images:  (list of DataArray of shape YX) list of z ordered images
        :param zlevels:  (list of float) list of focus positions
        :return: (DataArray of shape ZYX) the data array of the xyz cube
        """
    # images is a list of 3 dim data arrays.
    # Will fail on purpose if the images contain more than 2 dimensions
    ret = numpy.array([im.reshape(im.shape[-2:]) for im in images])

    # Add back metadata
    metadata3d = copy.copy(images[0].metadata)
    # Extend pixel size to 3D
    ps_x, ps_y = metadata3d[model.MD_PIXEL_SIZE]
    ps_z = (zlevels[-1] - zlevels[0]) / (len(zlevels) -
                                         1) if len(zlevels) > 1 else 1e-6

    # Compute cube centre
    c_x, c_y = metadata3d[model.MD_POS]
    c_z = (zlevels[0] + zlevels[-1]) / 2  # Assuming zlevels are ordered
    metadata3d[model.MD_POS] = (c_x, c_y, c_z)

    # For a negative pixel size, convert to a positive and flip the z axis
    if ps_z < 0:
        ret = numpy.flipud(ret)
        ps_z = -ps_z

    metadata3d[model.MD_PIXEL_SIZE] = (ps_x, ps_y, ps_z)
    metadata3d[model.MD_DIMS] = "ZYX"

    ret = DataArray(ret, metadata3d)

    return ret
Beispiel #4
0
    def _initialize_ovv_im(self, shape):
        """
        Initialize an overview image, i.e. a black DataArray with corresponding
        metadata. 
        shape: XYC tuple 
        returns: DataArray of shape XYC, mpp value 
        """
        # Initialize the size of the ovv image with the stage size if the stage is small (< 5cm),
        # otherwise fall back to OVV_SHAPE
        ax_x = self.main_data.stage.axes["x"]
        ax_y = self.main_data.stage.axes["y"]
        mpp = max(MAX_OVV_SIZE / shape[0], MAX_OVV_SIZE / shape[1])
        if hasattr(ax_x, "range") and hasattr(ax_y, "range"):
            max_x = ax_x.range[1] - ax_x.range[0]
            max_y = ax_y.range[1] - ax_y.range[0]
            if max_x < MAX_OVV_SIZE and max_y < MAX_OVV_SIZE:
                mpp = max(max_x / shape[0], max_y / shape[1])

        ovv_im = DataArray(numpy.zeros(shape, dtype=numpy.uint8))
        ovv_im.metadata[MD_DIMS] = "YXC"
        ovv_im.metadata[MD_PIXEL_SIZE] = (mpp, mpp)
        ovv_im.metadata[MD_POS] = self.m_view.view_pos.value
        return ovv_im, mpp
Beispiel #5
0
    def _initialize_ovv_im(self, shape):
        """
        Initialize an overview image, i.e. a black DataArray with corresponding
        metadata. 
        shape: XYC tuple 
        returns: DataArray of shape XYC, mpp value 
        """
        # Initialize the size of the ovv image with the stage size if the stage is small (< 5cm),
        # otherwise fall back to OVV_SHAPE
        ax_x = self.main_data.stage.axes["x"]
        ax_y = self.main_data.stage.axes["y"]
        mpp = max(MAX_OVV_SIZE / shape[0], MAX_OVV_SIZE / shape[1])
        if hasattr(ax_x, "range") and hasattr(ax_y, "range"):
            max_x = ax_x.range[1] - ax_x.range[0]
            max_y = ax_y.range[1] - ax_y.range[0]
            if max_x < MAX_OVV_SIZE and max_y < MAX_OVV_SIZE:
                mpp = max(max_x / shape[0], max_y / shape[1])

        ovv_im = DataArray(numpy.zeros(shape, dtype=numpy.uint8))
        ovv_im.metadata[MD_DIMS] = "YXC"
        ovv_im.metadata[MD_PIXEL_SIZE] = (mpp, mpp)
        ovv_im.metadata[MD_POS] = self.m_view.view_pos.value
        return ovv_im, mpp
Beispiel #6
0
    def _acquireStreamCompressedZStack(self, i, ix, iy, stream):
        """
        Acquire a compressed zstack image for the given stream.
        The method does the following:
            - Move focus over the list of zlevels
            - For each focus level acquire image of the stream
            - Construct xyz cube for the acquired zstack
            - Compress the cube into a single image using 'maximum intensity projection'
        :return DataArray: Acquired da for the current tile stream
        """
        zstack = []
        for z in self._zlevels:
            logging.debug(f"Moving focus for tile {ix}x{iy} to {z}.")
            stream.focuser.moveAbsSync({'z': z})
            da = self._acquireStreamTile(i, ix, iy, stream)
            zstack.append(da)

        if self._future._task_state == CANCELLED:
            raise CancelledError()
        logging.debug(
            f"Zstack acquisition for tile {ix}x{iy}, stream {stream.name} finished, compressing data into a single image."
        )
        # Convert zstack into a cube
        fm_cube = assembleZCube(zstack, self._zlevels)
        # Save the cube on disk if a log path exists
        if self._log_path:
            self._save_tiles(ix,
                             iy,
                             fm_cube,
                             stream_cube_id=self._streams.index(stream))

        if self._focusing_method == FocusingMethod.MAX_INTENSITY_PROJECTION:
            # Compress the cube into a single image (using maximum intensity projection)
            mip_image = numpy.amax(fm_cube, axis=0)
            if self._future._task_state == CANCELLED:
                raise CancelledError()
            logging.debug(
                f"Zstack compression for tile {ix}x{iy}, stream {stream.name} finished."
            )
            return DataArray(mip_image, copy.copy(zstack[0].metadata))
        else:
            # TODO: support stitched Z-stacks
            # For now, the init will raise NotImplementedError in such case
            logging.warning("Zstack returned as-is, while it is not supported")
            return fm_cube
Beispiel #7
0
    def test_nanana(self):

        self.app.test_frame.SetSize((500, 500))
        self.app.test_frame.Center()
        self.app.test_frame.Layout()

        # old_canvas = DraggableCanvas(self.panel)
        tab = self.create_simple_tab_model()
        mpp = FloatContinuous(10e-6, range=(1e-3, 1), unit="m/px")
        tab.focussedView.value.mpp = mpp

        view = tab.focussedView.value
        canvas = miccanvas.DblMicroscopeCanvas(self.panel)

        shape = (5, 5, 4)
        rgb = numpy.empty(shape, dtype=numpy.uint8)
        rgb[::2, ...] = [
                    [255, 0, 0, 255],
                    [0, 255, 0, 255],
                    [255, 255, 0, 255],
                    [255, 0, 255, 255],
                    [0, 0, 255, 255]
                ][:shape[1]]
        rgb[1::2, ...] = [
                    [127, 0, 0, 255],
                    [0, 127, 0, 255],
                    [127, 127, 0, 255],
                    [127, 0, 127, 255],
                    [0, 0, 127, 255]
                ][:shape[1]]

        rgb[..., [0, 1, 2, 3]] = rgb[..., [2, 1, 0, 3]]
        darray = DataArray(rgb)

        canvas.setView(view, tab)
        self.add_control(canvas, flags=wx.EXPAND, proportion=1)
        test.gui_loop()
        # Set the mpp again, because the on_size handler will have recalculated it
        view.mpp.value = 1

        images = [(darray, (0.0, 0.0), (2, 2), True, None, None, None, None, "nanana")]
        canvas.set_images(images)
        canvas.scale = 1
        canvas.update_drawing()
        test.gui_loop(0.1)
Beispiel #8
0
def generate_img_data(width, height, depth, alpha=255):
    """ Create an image of the given dimensions """

    shape = (height, width, depth)
    rgb = numpy.empty(shape, dtype=numpy.uint8)

    if width > 100 or height > 100:
        tl = random_color(alpha=alpha)
        tr = random_color(alpha=alpha)
        bl = random_color(alpha=alpha)
        br = random_color(alpha=alpha)

        rgb = numpy.zeros(shape, dtype=numpy.uint8)

        rgb[..., -1, 0] = numpy.linspace(tr[0], br[0], height)
        rgb[..., -1, 1] = numpy.linspace(tr[1], br[1], height)
        rgb[..., -1, 2] = numpy.linspace(tr[2], br[2], height)

        rgb[..., 0, 0] = numpy.linspace(tl[0], bl[0], height)
        rgb[..., 0, 1] = numpy.linspace(tl[1], bl[1], height)
        rgb[..., 0, 2] = numpy.linspace(tl[2], bl[2], height)

        for i in xrange(height):
            sr, sg, sb = rgb[i, 0, :3]
            er, eg, eb = rgb[i, -1, :3]

            rgb[i, :, 0] = numpy.linspace(int(sr), int(er), width)
            rgb[i, :, 1] = numpy.linspace(int(sg), int(eg), width)
            rgb[i, :, 2] = numpy.linspace(int(sb), int(eb), width)

        if depth == 4:
            rgb[..., 3] = min(255, max(alpha, 0))

    else:
        for w in xrange(width):
            for h in xrange(height):
                rgb[h, w] = random_color((230, 230, 255), alpha)

    return DataArray(rgb)
    def xtest_calc_img_buffer_rect(self):

        # Setting up test frame
        self.app.test_frame.SetSize((500, 500))
        self.app.test_frame.Center()
        self.app.test_frame.Layout()

        test.gui_loop()
        test.gui_loop()

        tab = self.create_simple_tab_model()
        view = tab.focussedView.value

        # Changes in default values might affect other test, so we need to know
        self.assertEqual(view.mpp.value, 1e-6,
                         "The default mpp value has changed!")

        cnvs = miccanvas.DblMicroscopeCanvas(self.panel)
        cnvs.fit_view_to_next_image = False
        # Create a even black background, so we can test pixel values
        cnvs.background_brush = wx.BRUSHSTYLE_SOLID

        self.add_control(cnvs, flags=wx.EXPAND, proportion=1)
        test.gui_loop(0.01)

        # Changes in default values might affect other test, so we need to know
        self.assertEqual(cnvs.scale, 1, "Default canvas scale has changed!")
        cnvs.setView(view, tab)

        # Setting the view, calls _onMPP with the view.mpp value
        # mpwu / mpp = scale => 1 (fixed, default) / view.mpp (1e-5)
        self.assertEqual(cnvs.scale, 1 / view.mpp.value)

        # Make sure the buffer is set at the right size
        expected_size = tuple(s + 2 * 512
                              for s in self.app.test_frame.ClientSize)
        self.assertEqual(cnvs._bmp_buffer_size, expected_size)

        ############ Create test image ###############

        img = generate_img_data(100, 100, 4)
        # 100 pixels is 1e-4 meters
        img.metadata[model.MD_PIXEL_SIZE] = (1e-6, 1e-6)
        img.metadata[model.MD_POS] = im_pos = (0, 0)
        img.metadata[model.MD_DIMS] = "YXC"
        im_scale = img.metadata[model.MD_PIXEL_SIZE][0]

        self.assertEqual(im_scale, img.metadata[model.MD_PIXEL_SIZE][0])

        stream1 = RGBStream("s1", img)
        view.addStream(stream1)

        # Verify view mpp and canvas scale
        self.assertEqual(view.mpp.value, 1e-6,
                         "Default mpp value has changed!")
        self.assertEqual(cnvs.scale, 1 / view.mpp.value,
                         "Canvas scale should not have changed!")

        cnvs.update_drawing()

        # We're going to control the render size of the image using the
        # following meter per pixel values
        mpps = [1e-6, 1e-7, 1e-8]  #, 1e-9, 1e-10]

        # They should set the canvas scales to the following values
        exp_scales = [1e6, 1e7, 1e8]  #, 1e9, 1e10]

        exp_b_rect = [
            (711, 697, 100.0, 100.0),
            # (261, 247, 1000.0, 1000.0),
            # (-4239, -4253, 10000.0, 10000.0),
        ]

        for mpp, scale, rect in zip(mpps, exp_scales, exp_b_rect):
            view.mpp.value = mpp
            self.assertAlmostEqual(scale, cnvs.scale)
            calc_rect = cnvs._calc_img_buffer_rect(img.shape[:2], im_scale,
                                                   im_pos)
            for ev, v in zip(rect, calc_rect):
                self.assertAlmostEqual(ev, v)
            test.gui_loop(0.1)

        stream1 = RGBStream("stream_one", img)
        # Set the mpp again, because the on_size handler will recalculate it
        view.mpp._value = 1

        # Dummy image
        shape = (200, 201, 4)
        rgb = numpy.empty(shape, dtype=numpy.uint8)
        rgb[...] = 255
        darray = DataArray(rgb)

        logging.getLogger().setLevel(logging.DEBUG)

        buffer_rect = (0, 0) + cnvs._bmp_buffer_size
        logging.debug("Buffer size is %s", buffer_rect)

        im_scales = [0.00001, 0.33564, 0.9999, 1, 1.3458, 2, 3.0, 101.0, 333.5]
        im_centers = [(0.0, 0.0), (-1.5, 5.2), (340.0, -220.0), (-20.0, -1.0)]

        canvas.scale = 0.5
        # Expected rectangles for the given image scales and canvas scale 0.5
        rects = [
            (611.9994975, 611.9995, 0.001005, 0.001),
            (595.13409, 595.218, 33.73182, 33.564),
            (561.755025, 562.005, 100.48995000000001, 99.99),
            (561.75, 562.0, 100.5, 100.0),
            (544.37355, 544.71, 135.2529, 134.58),
            (511.5, 512.0, 201.0, 200.0),
            (461.25, 462.0, 301.5, 300.0),
            (-4463.25, -4438.0, 10150.5, 10100.0),
            (-16146.375, -16063.0, 33516.75, 33350.0),
        ]

        for im_center in im_centers:
            logging.debug("Center: %s", im_center)
            for im_scale, rect in zip(im_scales, rects):
                logging.debug("Scale: %s", im_scale)
                b_rect = cnvs._calc_img_buffer_rect(darray.shape[:2], im_scale,
                                                    im_center)

                for v in b_rect:
                    self.assertIsInstance(v, float)

                rect = (rect[0] + im_center[0] * cnvs.scale,
                        rect[1] + im_center[1] * cnvs.scale, rect[2], rect[3])
                # logging.debug(b_rect)
                for b, r in zip(b_rect, rect):
                    self.assertAlmostEqual(b, r)

        canvas.scale = 1.0
        # Expected rectangle size for the given image scales and canvas scale 1
        rects = [
            (611.998995, 611.999, 0.00201, 0.002),
            (578.26818, 578.436, 67.46364, 67.128),
            (511.51005, 512.01, 200.97990000000001, 199.98),
            (511.5, 512.0, 201.0, 200.0),
            (476.7471, 477.41999999999996, 270.5058, 269.16),
            (411.0, 412.0, 402.0, 400.0),
            (310.5, 312.0, 603.0, 600.0),
            (-9538.5, -9488.0, 20301.0, 20200.0),
            (-32904.75, -32738.0, 67033.5, 66700.0),
        ]

        for im_center in im_centers:
            logging.debug("Center: %s", im_center)
            for im_scale, rect in zip(im_scales, rects):
                logging.debug("Scale: %s", im_scale)
                b_rect = cnvs._calc_img_buffer_rect(darray.shape[:2], im_scale,
                                                    im_center)

                for v in b_rect:
                    self.assertIsInstance(v, float)

                # logging.debug(b_rect)
                rect = (rect[0] + im_center[0] * cnvs.scale,
                        rect[1] + im_center[1] * cnvs.scale, rect[2], rect[3])
                # logging.debug(b_rect)
                for b, r in zip(b_rect, rect):
                    self.assertAlmostEqual(b, r)

        canvas.scale = 2.3
        # Expected rectangles for the given image scales and canvas scale 2.3
        rects = [
            (611.9976885, 611.9977, 0.0046229999999999995, 0.0046),
            (534.416814, 534.8028, 155.166372, 154.3944),
            (380.873115, 382.023, 462.25377, 459.95399999999995),
            (380.85, 382.0, 462.29999999999995, 459.99999999999994),
            (300.91833, 302.466, 622.16334, 619.068),
            (149.70000000000005, 152.00000000000006, 924.5999999999999,
             919.9999999999999),
            (-81.44999999999993, -78.0, 1386.8999999999999, 1380.0),
            (-22734.149999999998, -22618.0, 46692.299999999996, 46460.0),
            (-76476.525, -76093.0, 154177.05, 153410.0),
        ]

        for im_center in im_centers:
            logging.debug("Center: %s", im_center)
            for im_scale, rect in zip(im_scales, rects):
                logging.debug("Scale: %s", im_scale)
                b_rect = cnvs._calc_img_buffer_rect(darray.shape[:2], im_scale,
                                                    im_center)

                for v in b_rect:
                    self.assertIsInstance(v, float)

                # logging.debug(b_rect)
                rect = (rect[0] + im_center[0] * cnvs.scale,
                        rect[1] + im_center[1] * cnvs.scale, rect[2], rect[3])
                # logging.debug(b_rect)
                for b, r in zip(b_rect, rect):
                    self.assertAlmostEqual(b, r)

        logging.getLogger().setLevel(logging.ERROR)