Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Render a video on a Cube #322 #862

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
deb99c6
video on a cube
robinroy03 Feb 20, 2024
41848f7
import vtk through fury lib.py, added some comments on possible impro…
robinroy03 Feb 20, 2024
2773729
fixing pep8 one line at a time
robinroy03 Feb 20, 2024
6feeeb0
fixing pep8 one line at a time (part 2)
robinroy03 Feb 20, 2024
d4b3344
Merge branch 'fury-gl:master' into cube_viz
robinroy03 Mar 2, 2024
f58f41d
modified cube viz with different textures on all 6 sides
robinroy03 Mar 3, 2024
ed688ca
pep8 fix
robinroy03 Mar 3, 2024
1887ccb
pep8
robinroy03 Mar 3, 2024
5a7c6fc
textured cube final version without tests
robinroy03 Mar 10, 2024
6fc3dcd
tutorial for viz_play_cube
robinroy03 Mar 10, 2024
a351499
pep8 fix
robinroy03 Mar 10, 2024
78f8135
pep8
robinroy03 Mar 10, 2024
724ee56
modified to elininate circular import error, removed get_scene() beca…
robinroy03 Mar 11, 2024
6a84176
added tests and fixed some docstrings, also added to lib.py
robinroy03 Mar 12, 2024
f735ad9
using isintance for the type comparison
robinroy03 Mar 13, 2024
c141f31
Added center coordinate parameter, used util.py helper function to si…
robinroy03 Mar 15, 2024
1953851
Removed classes, made it functional. Changed the tests accordingly. M…
robinroy03 Mar 19, 2024
0367526
Merge branch 'fury-gl:master' into cube_viz
robinroy03 Mar 20, 2024
dc74532
fixed a coordinate bug, now it is perfectly aligned to the center
robinroy03 Mar 21, 2024
264721b
fixed docs, made it cleaner. Fixed uneven variable names for texture_…
robinroy03 Mar 21, 2024
20d668d
small typo fix
robinroy03 Mar 21, 2024
62ac13c
fixed the normal directions (it now points outwards, earlier it point…
robinroy03 Mar 21, 2024
faf40bf
Merge branch 'fury-gl:master' into cube_viz
robinroy03 May 1, 2024
b26842a
https version of videos, removed implementation note from docstring, …
robinroy03 May 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions docs/examples/viz_play_cube.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""
=======================================================
Play a video in the 3D world
=======================================================

The goal of this demo is to show how to visualize a video
on a cube by updating its textures.
robinroy03 marked this conversation as resolved.
Show resolved Hide resolved
"""

from fury import window, actor
import numpy as np
import cv2


def timer_callback(_caller, _timer_event):
rgb_images = []
for video_capture in video_captures:
_, bgr_image = video_capture.read()

# Condition used to stop rendering when the smallest video is over.
if isinstance(bgr_image, np.ndarray):
rgb_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB)
rgb_images.append(rgb_image)
else:
show_manager.exit()
return

cube.texture_update(
show_manager,
*rgb_images
)


# the 6 sources for the video, can be URL or directory links on your machine.
sources = [
'http://commondatastorage.googleapis.com/gtv-videos-bucket/'
+ 'sample/BigBuckBunny.mp4',
'http://commondatastorage.googleapis.com/gtv-videos-bucket/'
+ 'sample/BigBuckBunny.mp4',
'http://commondatastorage.googleapis.com/gtv-videos-bucket/'
+ 'sample/BigBuckBunny.mp4',
'http://commondatastorage.googleapis.com/gtv-videos-bucket/'
+ 'sample/BigBuckBunny.mp4',
'http://commondatastorage.googleapis.com/gtv-videos-bucket/'
+ 'sample/BigBuckBunny.mp4',
'http://commondatastorage.googleapis.com/gtv-videos-bucket/'
+ 'sample/BigBuckBunny.mp4'
robinroy03 marked this conversation as resolved.
Show resolved Hide resolved
]

video_captures = [cv2.VideoCapture(source) for source in sources]
rgb_images = []
for video_capture in video_captures:
_, bgr_image = video_capture.read()
rgb_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB)
rgb_images.append(rgb_image)
robinroy03 marked this conversation as resolved.
Show resolved Hide resolved

# Creating a TexturedCube with different textures on all 6 sides.
cube = actor.TexturedCube(*rgb_images)
scene = window.Scene()
cube_actor = cube.get_actor()
scene.add(cube_actor)
show_manager = window.ShowManager(scene, size=(1280, 720), reset_camera=False)
show_manager.add_timer_callback(True, int(1/60), timer_callback)
show_manager.start()
robinroy03 marked this conversation as resolved.
Show resolved Hide resolved
151 changes: 151 additions & 0 deletions fury/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
ConeSource,
ContourFilter,
CylinderSource,
PlaneSource,
DiskSource,
FloatArray,
Follower,
Expand Down Expand Up @@ -74,6 +75,7 @@
get_actor_from_primitive,
lines_to_vtk_polydata,
numpy_to_vtk_colors,
numpy_to_vtk_image_data,
repeat_sources,
rgb_to_vtk,
set_input,
Expand Down Expand Up @@ -3954,3 +3956,152 @@ def uncertainty_cone(
angles = main_dir_uncertainty(evals, evecs, signal, sigma, b_matrix)

return double_cone(centers, evecs, angles, colors, scales, opacity)


class TexturedCube:
robinroy03 marked this conversation as resolved.
Show resolved Hide resolved
"""Class to work with textured cube."""

def __init__(self,
negx,
negy,
negz,
posx,
posy,
posz,
center_x: int = 0,
center_y: int = 0,
center_z: int = 0,
):
"""Initializes a TexturedCube object.

Parameters
----------
negx : ndarray
Input 2D RGB or RGBA array. Dtype should be uint8.
negy : ndarray
Input 2D RGB or RGBA array. Dtype should be uint8.
negz : ndarray
Input 2D RGB or RGBA array. Dtype should be uint8.
posx : ndarray
Input 2D RGB or RGBA array. Dtype should be uint8.
posy : ndarray
Input 2D RGB or RGBA array. Dtype should be uint8.
posz : ndarray
Input 2D RGB or RGBA array. Dtype should be uint8.
center_x : int, optional
X-Coordinate of the cube.
center_y : int, optional
Y-Coordinate of the cube.
center_z : int, optional
Z-Coordinate of the cube.

|----|
| +Y |
|----|----|----|----|
| -X | +Z | +X | -Z |
|----|----|----|----|
| -Y |
|----|

"""

self.planes = [PlaneSource() for _ in range(6)]

self.plane_centers = [
(-0.5 + center_x, 0.5 + center_y, 0.5 + center_z),
(0 + center_x, 0 + center_y, 0.5 + center_z),
(0 + center_x, 0.5 + center_y, 0 + center_z),
(0.5 + center_x, 0.5 + center_y, 0.5 + center_z),
(0 + center_x, 1 + center_y, 0.5 + center_z),
(0 + center_x, 0.5 + center_y, 1 + center_z)
]

self.plane_normals = [
(1, 0, 0),
(0, 1, 0),
(0, 0, 1),
(1, 0, 0),
(0, 1, 0),
(0, 0, 1)
]

for plane, center, normal in zip(
self.planes,
self.plane_centers,
self.plane_normals
):
plane.SetCenter(*center)
plane.SetNormal(*normal)

self.image_grids = [negx, negy, negz, posx, posy, posz]

self.image_data_objs = [
numpy_to_vtk_image_data(grid) for grid in self.image_grids
]

self.texture_objects = [Texture() for _ in range(6)]

for image_data_obj, texture_object in zip(
self.image_data_objs,
self.texture_objects
):
texture_object.SetInputDataObject(image_data_obj)

self.polyDataMappers = [PolyDataMapper() for _ in range(6)]

for mapper, plane in zip(
self.polyDataMappers,
self.planes
):
mapper.SetInputConnection(plane.GetOutputPort())

self.actors = [Actor() for _ in range(6)]
for actor, mapper, texture_object in zip(
self.actors,
self.polyDataMappers,
self.texture_objects
):
actor.SetMapper(mapper)
actor.SetTexture(texture_object)

def get_actor(self):
"""Returns
-------
assembled_actor : Assembly

"""

assembled_actor = Assembly()
for actor_ in self.actors:
assembled_actor.AddPart(actor_)

return assembled_actor

def texture_update(self, show_manager, negx, negy, negz, posx, posy, posz):
"""Changes the texture of the cube.

Parameters
----------
show_manager : window.ShowManager
Input currently using ShowManager.
negx : ndarray
Input 2D RGB or RGBA array. Dtype should be uint8.
negy : ndarray
Input 2D RGB or RGBA array. Dtype should be uint8.
negz : ndarray
Input 2D RGB or RGBA array. Dtype should be uint8.
posx : ndarray
Input 2D RGB or RGBA array. Dtype should be uint8.
posy : ndarray
Input 2D RGB or RGBA array. Dtype should be uint8.
posz : ndarray
Input 2D RGB or RGBA array. Dtype should be uint8.

"""

self.image_grids = [negx, negy, negz, posx, posy, posz]

for actor_, image in zip(self.actors, self.image_grids):
texture_update(actor_, image)

show_manager.render()
4 changes: 4 additions & 0 deletions fury/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@
WindowToImageFilter = rcvtk.vtkWindowToImageFilter
#: class for InteractorStyle
InteractorStyle = rcvtk.vtkInteractorStyle
#: class for PropCollection
PropCollection = rcvtk.vtkPropCollection
#: class for PropPicker
PropPicker = rcvtk.vtkPropPicker
#: class for PointPicker
Expand Down Expand Up @@ -228,6 +230,8 @@
TexturedSphereSource = fsvtk.vtkTexturedSphereSource
#: class for RegularPolygonSource
RegularPolygonSource = fsvtk.vtkRegularPolygonSource
#: class for PlaneSource
PlaneSource = fsvtk.vtkPlaneSource

##############################################################
# vtkCommonDataModel Module
Expand Down
54 changes: 54 additions & 0 deletions fury/tests/test_actors.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from fury.actor import grid
from fury.decorators import skip_linux, skip_osx, skip_win
from fury.deprecator import ExpiredDeprecationError
from fury.lib import Assembly, PropCollection

# Allow import, but disable doctests if we don't have dipy
from fury.optpkg import optional_package
Expand Down Expand Up @@ -1881,3 +1882,56 @@ def test_actors_primitives_count():
primitives_count = test_case[2]
act = act_func(**args)
npt.assert_equal(primitives_count_from_actor(act), primitives_count)


def test_texturedcube(interactive=False):

arr_255 = np.full((720, 1280), 255, dtype=np.uint8)
arr_0 = np.full((720, 1280), 0, dtype=np.uint8)

arr_white = np.full((720, 1280, 3), 255, dtype=np.uint8)
arr_red = np.dstack((arr_255, arr_0, arr_0))
arr_green = np.dstack((arr_0, arr_255, arr_0))
arr_blue = np.dstack((arr_0, arr_0, arr_255))
arr_yellow = np.dstack((arr_255, arr_255, arr_0))
arr_aqua = np.dstack((arr_0, arr_255, arr_255))

cube = actor.TexturedCube(arr_white,
arr_red,
arr_green,
arr_blue,
arr_yellow,
arr_aqua,
1,
2,
3)

cube_actor = cube.get_actor()

# testing whether the returned is an Assembled Actor Object
assert isinstance(cube_actor, Assembly)

# testing whether there are 6 different planes
plane_actors = PropCollection()
cube_actor.GetActors(plane_actors)

assert plane_actors.GetNumberOfItems() == 6

# testing whether the texture is getting updated
def timer_callback(_caller, _timer_event):
rgb_images = [arr_aqua,
arr_yellow,
arr_blue,
arr_green,
arr_red,
arr_white]
cube.texture_update(show_manager, *rgb_images)

assert cube.image_grids == rgb_images
show_manager.exit()

scene = window.Scene()
scene.add(cube_actor)
show_manager = window.ShowManager(scene, reset_camera=False)
show_manager.add_timer_callback(True, int(1/60), timer_callback)
show_manager.start()
Loading