Beispiel #1
0
def snapshot(scene, fname=None, size=(300, 300), offscreen=True,
             order_transparent=False, stereo='off',
             multi_samples=8, max_peels=4,
             occlusion_ratio=0.0):
    """Save a snapshot of the scene in a file or in memory.

    Parameters
    -----------
    scene : Scene() or vtkRenderer
        Scene instance
    fname : str or None
        Save PNG file. If None return only an array without saving PNG.
    size : (int, int)
        ``(width, height)`` of the window. Default is (300, 300).
    offscreen : bool
        Default True. Go stealth mode no window should appear.
    order_transparent : bool
        Default False. Use depth peeling to sort transparent objects.
        If True also enables anti-aliasing.

    stereo: string
        Set the stereo type. Default is 'off'. Other types include:

        * 'opengl': OpenGL frame-sequential stereo. Referred to as
          'CrystalEyes' by VTK.
        * 'anaglyph': For use with red/blue glasses. See VTK docs to
          use different colors.
        * 'interlaced': Line interlaced.
        * 'checkerboard': Checkerboard interlaced.
        * 'left': Left eye only.
        * 'right': Right eye only.
        * 'horizontal': Side-by-side.

    multi_samples : int
        Number of samples for anti-aliazing (Default 8).
        For no anti-aliasing use 0.
    max_peels : int
        Maximum number of peels for depth peeling (Default 4).
    occlusion_ratio : float
        Occlusion ration for depth peeling (Default 0 - exact image).

    Returns
    -------
    arr : ndarray
        Color array of size (width, height, 3) where the last dimension
        holds the RGB values.

    """
    width, height = size

    render_window = RenderWindow()
    if offscreen:
        render_window.SetOffScreenRendering(1)
    if stereo.lower() != 'off':
        enable_stereo(render_window, stereo)
    render_window.AddRenderer(scene)
    render_window.SetSize(width, height)

    if order_transparent:
        antialiasing(scene, render_window, multi_samples, max_peels,
                     occlusion_ratio)

    render_window.Render()

    window_to_image_filter = WindowToImageFilter()
    window_to_image_filter.SetInput(render_window)
    window_to_image_filter.Update()

    vtk_image = window_to_image_filter.GetOutput()
    h, w, _ = vtk_image.GetDimensions()
    vtk_array = vtk_image.GetPointData().GetScalars()
    components = vtk_array.GetNumberOfComponents()
    arr = numpy_support.vtk_to_numpy(vtk_array).reshape(w, h, components)

    if fname is None:
        return arr

    save_image(arr, fname)
    return arr
Beispiel #2
0
    def __init__(self, scene=None, title='FURY', size=(300, 300),
                 png_magnify=1, reset_camera=True, order_transparent=False,
                 interactor_style='custom', stereo='off',
                 multi_samples=8, max_peels=4, occlusion_ratio=0.0):
        """Manage the visualization pipeline.

        Parameters
        ----------
        scene : Scene() or vtkRenderer()
            The scene that holds all the actors.
        title : string
            A string for the window title bar.
        size : (int, int)
            ``(width, height)`` of the window. Default is (300, 300).
        png_magnify : int
            Number of times to magnify the screenshot. This can be used to save
            high resolution screenshots when pressing 's' inside the window.
        reset_camera : bool
            Default is True. You can change this option to False if you want to
            keep the camera as set before calling this function.
        order_transparent : bool
            True is useful when you want to order transparent
            actors according to their relative position to the camera. The
            default option which is False will order the actors according to
            the order of their addition to the Scene().
        interactor_style : str or vtkInteractorStyle
            If str then if 'trackball' then vtkInteractorStyleTrackballCamera()
            is used, if 'image' then vtkInteractorStyleImage() is used (no
            rotation) or if 'custom' then CustomInteractorStyle is used.
            Otherwise you can input your own interactor style.
        stereo: string
            Set the stereo type. Default is 'off'. Other types include:

            * 'opengl': OpenGL frame-sequential stereo. Referred to as
              'CrystalEyes' by VTK.
            * 'anaglyph': For use with red/blue glasses. See VTK docs to
              use different colors.
            * 'interlaced': Line interlaced.
            * 'checkerboard': Checkerboard interlaced.
            * 'left': Left eye only.
            * 'right': Right eye only.
            * 'horizontal': Side-by-side.

        multi_samples : int
            Number of samples for anti-aliazing (Default 8).
            For no anti-aliasing use 0.
        max_peels : int
            Maximum number of peels for depth peeling (Default 4).
        occlusion_ratio : float
            Occlusion ration for depth peeling (Default 0 - exact image).

        Attributes
        ----------
        scene : Scene() or vtkRenderer()
        iren : vtkRenderWindowInteractor()
        style : vtkInteractorStyle()
        window : vtkRenderWindow()

        Methods
        -------
        initialize()
        render()
        start()
        add_window_callback()

        Examples
        --------
        >>> from fury import actor, window
        >>> scene = window.Scene()
        >>> scene.add(actor.axes())
        >>> showm = window.ShowManager(scene)
        >>> # showm.initialize()
        >>> # showm.render()
        >>> # showm.start()

        """
        if scene is None:
            scene = Scene()
        self.scene = scene
        self.title = title
        self.size = size
        self.png_magnify = png_magnify
        self.reset_camera = reset_camera
        self.order_transparent = order_transparent
        self.interactor_style = interactor_style
        self.stereo = stereo
        self.timers = []

        if self.reset_camera:
            self.scene.ResetCamera()

        self.window = RenderWindow()

        if self.stereo.lower() != 'off':
            enable_stereo(self.window, self.stereo)

        self.window.AddRenderer(scene)

        self.window.SetSize(size[0], size[1])

        if self.order_transparent:
            occlusion_ratio = occlusion_ratio or 0.1
            antialiasing(self.scene, self.window,
                         multi_samples=0, max_peels=max_peels,
                         occlusion_ratio=occlusion_ratio)

        if self.interactor_style == 'image':
            self.style = InteractorStyleImage()
        elif self.interactor_style == 'trackball':
            self.style = InteractorStyleTrackballCamera()
        elif self.interactor_style == 'custom':
            self.style = CustomInteractorStyle()
        else:
            self.style = interactor_style

        self.iren = RenderWindowInteractor()
        self.style.SetCurrentRenderer(self.scene)
        # Hack: below, we explicitly call the Python version of SetInteractor.
        self.style.SetInteractor(self.iren)
        self.iren.SetInteractorStyle(self.style)
        self.iren.SetRenderWindow(self.window)
Beispiel #3
0
def record(scene=None, cam_pos=None, cam_focal=None, cam_view=None,
           out_path=None, path_numbering=False, n_frames=1, az_ang=10,
           magnification=1, size=(300, 300), reset_camera=True,
           screen_clip=False, stereo='off', verbose=False):
    """Record a video of your scene.

    Records a video as a series of ``.png`` files of your scene by rotating the
    azimuth angle az_angle in every frame.

    Parameters
    -----------
    scene : Scene() or vtkRenderer() object
        Scene instance
    cam_pos : None or sequence (3,), optional
        Camera's position. If None then default camera's position is used.
    cam_focal : None or sequence (3,), optional
        Camera's focal point. If None then default camera's focal point is
        used.
    cam_view : None or sequence (3,), optional
        Camera's view up direction. If None then default camera's view up
        vector is used.
    out_path : str, optional
        Output path for the frames. If None a default fury.png is created.
    path_numbering : bool
        When recording it changes out_path to out_path + str(frame number)
    n_frames : int, optional
        Number of frames to save, default 1
    az_ang : float, optional
        Azimuthal angle of camera rotation.
    magnification : int, optional
        How much to magnify the saved frame. Default is 1. A value greater
        than 1 increases the quality of the image. However, the output
        size will be larger. For example, 200x200 image with magnification
        of 2 will be a 400x400 image.
    size : (int, int)
        ``(width, height)`` of the window. Default is (300, 300).
    screen_clip: bool
        Clip the png based on screen resolution. Default is False.
    reset_camera : bool
        If True Call ``scene.reset_camera()``. Otherwise you need to set the
         camera before calling this function.
    stereo: string
        Set the stereo type. Default is 'off'. Other types include:

        * 'opengl': OpenGL frame-sequential stereo. Referred to as
          'CrystalEyes' by VTK.
        * 'anaglyph': For use with red/blue glasses. See VTK docs to
          use different colors.
        * 'interlaced': Line interlaced.
        * 'checkerboard': Checkerboard interlaced.
        * 'left': Left eye only.
        * 'right': Right eye only.
        * 'horizontal': Side-by-side.

    verbose : bool
        print information about the camera. Default is False.

    Examples
    ---------
    >>> from fury import window, actor
    >>> scene = window.Scene()
    >>> a = actor.axes()
    >>> scene.add(a)
    >>> # uncomment below to record
    >>> # window.record(scene)
    >>> # check for new images in current directory

    """
    if scene is None:
        scene = Scene()

    renWin = RenderWindow()

    renWin.SetOffScreenRendering(1)
    renWin.SetBorders(screen_clip)
    renWin.AddRenderer(scene)
    renWin.SetSize(size[0], size[1])
    iren = RenderWindowInteractor()
    iren.SetRenderWindow(renWin)

    # scene.GetActiveCamera().Azimuth(180)

    if reset_camera:
        scene.ResetCamera()

    if stereo.lower() != 'off':
        enable_stereo(renWin, stereo)

    renderLarge = RenderLargeImage()
    renderLarge.SetInput(scene)
    renderLarge.SetMagnification(magnification)
    renderLarge.Update()

    ang = 0

    if cam_pos is not None:
        cx, cy, cz = cam_pos
        scene.GetActiveCamera().SetPosition(cx, cy, cz)
    if cam_focal is not None:
        fx, fy, fz = cam_focal
        scene.GetActiveCamera().SetFocalPoint(fx, fy, fz)
    if cam_view is not None:
        ux, uy, uz = cam_view
        scene.GetActiveCamera().SetViewUp(ux, uy, uz)

    cam = scene.GetActiveCamera()
    if verbose:
        print('Camera Position (%.2f, %.2f, %.2f)' % cam.GetPosition())
        print('Camera Focal Point (%.2f, %.2f, %.2f)' % cam.GetFocalPoint())
        print('Camera View Up (%.2f, %.2f, %.2f)' % cam.GetViewUp())

    for i in range(n_frames):
        scene.GetActiveCamera().Azimuth(ang)
        renderLarge = RenderLargeImage()
        renderLarge.SetInput(scene)
        renderLarge.SetMagnification(magnification)
        renderLarge.Update()

        if path_numbering:
            if out_path is None:
                filename = str(i).zfill(6) + '.png'
            else:
                filename = out_path + str(i).zfill(6) + '.png'
        else:
            if out_path is None:
                filename = 'fury.png'
            else:
                filename = out_path

        arr = numpy_support.vtk_to_numpy(renderLarge.GetOutput().GetPointData()
                                         .GetScalars())
        w, h, _ = renderLarge.GetOutput().GetDimensions()
        components = renderLarge.GetOutput().GetNumberOfScalarComponents()
        arr = arr.reshape((h, w, components))
        save_image(arr, filename)

        ang = +az_ang
Beispiel #4
0
class ShowManager(object):
    """Class interface between the scene, the window and the interactor."""

    def __init__(self, scene=None, title='FURY', size=(300, 300),
                 png_magnify=1, reset_camera=True, order_transparent=False,
                 interactor_style='custom', stereo='off',
                 multi_samples=8, max_peels=4, occlusion_ratio=0.0):
        """Manage the visualization pipeline.

        Parameters
        ----------
        scene : Scene() or vtkRenderer()
            The scene that holds all the actors.
        title : string
            A string for the window title bar.
        size : (int, int)
            ``(width, height)`` of the window. Default is (300, 300).
        png_magnify : int
            Number of times to magnify the screenshot. This can be used to save
            high resolution screenshots when pressing 's' inside the window.
        reset_camera : bool
            Default is True. You can change this option to False if you want to
            keep the camera as set before calling this function.
        order_transparent : bool
            True is useful when you want to order transparent
            actors according to their relative position to the camera. The
            default option which is False will order the actors according to
            the order of their addition to the Scene().
        interactor_style : str or vtkInteractorStyle
            If str then if 'trackball' then vtkInteractorStyleTrackballCamera()
            is used, if 'image' then vtkInteractorStyleImage() is used (no
            rotation) or if 'custom' then CustomInteractorStyle is used.
            Otherwise you can input your own interactor style.
        stereo: string
            Set the stereo type. Default is 'off'. Other types include:

            * 'opengl': OpenGL frame-sequential stereo. Referred to as
              'CrystalEyes' by VTK.
            * 'anaglyph': For use with red/blue glasses. See VTK docs to
              use different colors.
            * 'interlaced': Line interlaced.
            * 'checkerboard': Checkerboard interlaced.
            * 'left': Left eye only.
            * 'right': Right eye only.
            * 'horizontal': Side-by-side.

        multi_samples : int
            Number of samples for anti-aliazing (Default 8).
            For no anti-aliasing use 0.
        max_peels : int
            Maximum number of peels for depth peeling (Default 4).
        occlusion_ratio : float
            Occlusion ration for depth peeling (Default 0 - exact image).

        Attributes
        ----------
        scene : Scene() or vtkRenderer()
        iren : vtkRenderWindowInteractor()
        style : vtkInteractorStyle()
        window : vtkRenderWindow()

        Methods
        -------
        initialize()
        render()
        start()
        add_window_callback()

        Examples
        --------
        >>> from fury import actor, window
        >>> scene = window.Scene()
        >>> scene.add(actor.axes())
        >>> showm = window.ShowManager(scene)
        >>> # showm.initialize()
        >>> # showm.render()
        >>> # showm.start()

        """
        if scene is None:
            scene = Scene()
        self.scene = scene
        self.title = title
        self.size = size
        self.png_magnify = png_magnify
        self.reset_camera = reset_camera
        self.order_transparent = order_transparent
        self.interactor_style = interactor_style
        self.stereo = stereo
        self.timers = []

        if self.reset_camera:
            self.scene.ResetCamera()

        self.window = RenderWindow()

        if self.stereo.lower() != 'off':
            enable_stereo(self.window, self.stereo)

        self.window.AddRenderer(scene)

        self.window.SetSize(size[0], size[1])

        if self.order_transparent:
            occlusion_ratio = occlusion_ratio or 0.1
            antialiasing(self.scene, self.window,
                         multi_samples=0, max_peels=max_peels,
                         occlusion_ratio=occlusion_ratio)

        if self.interactor_style == 'image':
            self.style = InteractorStyleImage()
        elif self.interactor_style == 'trackball':
            self.style = InteractorStyleTrackballCamera()
        elif self.interactor_style == 'custom':
            self.style = CustomInteractorStyle()
        else:
            self.style = interactor_style

        self.iren = RenderWindowInteractor()
        self.style.SetCurrentRenderer(self.scene)
        # Hack: below, we explicitly call the Python version of SetInteractor.
        self.style.SetInteractor(self.iren)
        self.iren.SetInteractorStyle(self.style)
        self.iren.SetRenderWindow(self.window)

    def initialize(self):
        """Initialize interaction."""
        self.iren.Initialize()

    def render(self):
        """Render only once."""
        self.window.Render()

    def start(self):
        """Start interaction."""
        try:
            self.render()
            if self.title.upper() == "FURY":
                self.window.SetWindowName(self.title + " " + fury_version)
            else:
                self.window.SetWindowName(self.title)
            self.iren.Start()
        except AttributeError:
            self.__init__(self.scene, self.title, size=self.size,
                          png_magnify=self.png_magnify,
                          reset_camera=self.reset_camera,
                          order_transparent=self.order_transparent,
                          interactor_style=self.interactor_style)
            self.initialize()
            self.render()
            if self.title.upper() == "FURY":
                self.window.SetWindowName(self.title + " " + fury_version)
            else:
                self.window.SetWindowName(self.title)
            self.iren.Start()

        self.window.RemoveRenderer(self.scene)
        self.scene.SetRenderWindow(None)
        self.window.Finalize()
        del self.iren
        del self.window

    def record_events(self):
        """Record events during the interaction.

        The recording is represented as a list of VTK events that happened
        during the interaction. The recorded events are then returned.

        Returns
        -------
        events : str
            Recorded events (one per line).

        Notes
        -----
        Since VTK only allows recording events to a file, we use a
        temporary file from which we then read the events.

        """
        with InTemporaryDirectory():
            filename = "recorded_events.log"
            recorder = InteractorEventRecorder()
            recorder.SetInteractor(self.iren)
            recorder.SetFileName(filename)

            def _stop_recording_and_close(_obj, _evt):
                if recorder:
                    recorder.Stop()
                self.iren.TerminateApp()

            self.iren.AddObserver("ExitEvent", _stop_recording_and_close)

            recorder.EnabledOn()
            recorder.Record()

            self.initialize()
            self.render()
            self.iren.Start()
            # Deleting this object is the unique way
            # to close the file.
            recorder = None
            # Retrieved recorded events.
            with open(filename, 'r') as f:
                events = f.read()
        return events

    def record_events_to_file(self, filename="record.log"):
        """Record events during the interaction.

        The recording is represented as a list of VTK events
        that happened during the interaction. The recording is
        going to be saved into `filename`.

        Parameters
        ----------
        filename : str
            Name of the file that will contain the recording (.log|.log.gz).

        """
        events = self.record_events()

        # Compress file if needed
        if filename.endswith(".gz"):
            with gzip.open(filename, 'wb') as fgz:
                fgz.write(asbytes(events))
        else:
            with open(filename, 'w') as f:
                f.write(events)

    def play_events(self, events):
        """Play recorded events of a past interaction.

        The VTK events that happened during the recorded interaction will be
        played back.

        Parameters
        ----------
        events : str
            Recorded events (one per line).

        """
        recorder = InteractorEventRecorder()
        recorder.SetInteractor(self.iren)

        recorder.SetInputString(events)
        recorder.ReadFromInputStringOn()
        self.initialize()
        # self.render()
        recorder.Play()

        # self.window.RemoveRenderer(self.scene)
        # self.scene.SetRenderWindow(None)

        # Finalize seems very important otherwise
        # the recording window will not close.
        self.window.Finalize()
        self.exit()
        # print('After Finalize and Exit')

        # del self.iren
        # del self.window

    def play_events_from_file(self, filename):
        """Play recorded events of a past interaction.

        The VTK events that happened during the recorded interaction will be
        played back from `filename`.

        Parameters
        ----------
        filename : str
            Name of the file containing the recorded events (.log|.log.gz).

        """
        # Uncompress file if needed.
        if filename.endswith(".gz"):
            with gzip.open(filename, 'r') as f:
                events = f.read()
        else:
            with open(filename) as f:
                events = f.read()

        self.play_events(events)

    def add_window_callback(self, win_callback,
                            event=Command.ModifiedEvent):
        """Add window callbacks."""
        self.window.AddObserver(event, win_callback)
        self.window.Render()

    def add_timer_callback(self, repeat, duration, timer_callback):
        self.iren.AddObserver("TimerEvent", timer_callback)

        if repeat:
            timer_id = self.iren.CreateRepeatingTimer(duration)
        else:
            timer_id = self.iren.CreateOneShotTimer(duration)
        self.timers.append(timer_id)

    def add_iren_callback(self, iren_callback, event="MouseMoveEvent"):
        self.iren.AddObserver(event, iren_callback)

    def destroy_timer(self, timer_id):
        self.iren.DestroyTimer(timer_id)
        del self.timers[self.timers.index(timer_id)]

    def destroy_timers(self):
        for timer_id in self.timers:
            self.destroy_timer(timer_id)

    def exit(self):
        """Close window and terminate interactor."""
        # if is_osx and self.timers:
            # OSX seems to not destroy correctly timers
            # segfault 11 appears sometimes if we do not do it manually.

        # self.iren.GetRenderWindow().Finalize()
        self.iren.TerminateApp()
        self.destroy_timers()
        self.timers.clear()

    def save_screenshot(self, fname, magnification=1, size=None, stereo=None):
        """Save a screenshot of the current window in the specified filename.

        Parameters
        ----------
        fname : str or None
            File name where to save the screenshot.
        magnification : int, optional
            Applies a magnification factor to the scene before taking the
            screenshot which improves the quality. A value greater than 1
            increases the quality of the image. However, the output size will
            be larger. For example, 200x200 image with magnification of 2 will
            result in a 400x400 image. Default is 1.
        size : tuple of 2 ints, optional
            Size of the output image in pixels. If None, the size of the scene
            will be used. If magnification > 1, then the size will be
            determined by the magnification factor. Default is None.
        stereo : str, optional
            Set the type of stereo for the screenshot. Supported values are:

                * 'opengl': OpenGL frame-sequential stereo. Referred to as
                  'CrystalEyes' by VTK.
                * 'anaglyph': For use with red/blue glasses. See VTK docs to
                  use different colors.
                * 'interlaced': Line interlaced.
                * 'checkerboard': Checkerboard interlaced.
                * 'left': Left eye only.
                * 'right': Right eye only.
                * 'horizontal': Side-by-side.

        """
        if size is None:
            size = self.size
        if stereo is None:
            stereo = self.stereo.lower()
        record(scene=self.scene, out_path=fname, magnification=magnification,
               size=size, stereo=stereo)