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 all 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
1 change: 1 addition & 0 deletions docs/examples/_valid_examples.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ files = [
"viz_emwave_animation.py",
"viz_helical_motion.py",
"viz_play_video.py",
"viz_play_cube.py",
"viz_dt_ellipsoids.py"
]

Expand Down
108 changes: 108 additions & 0 deletions docs/examples/viz_play_cube.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"""
=======================================================
Play video on a Cube
=======================================================

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 actor, window
import numpy as np
import cv2

#########################################################################
# The 6 sources for the video, can be URL or directory paths on your machine.
# There'll be a significant delay if your internet connectivity is poor,
# use local directory paths for fast rendering.
sources = [
'https://commondatastorage.googleapis.com/gtv-videos-bucket/'
+ 'sample/BigBuckBunny.mp4',
'https://commondatastorage.googleapis.com/gtv-videos-bucket/'
+ 'sample/BigBuckBunny.mp4',
'https://commondatastorage.googleapis.com/gtv-videos-bucket/'
+ 'sample/BigBuckBunny.mp4',
'https://commondatastorage.googleapis.com/gtv-videos-bucket/'
+ 'sample/BigBuckBunny.mp4',
'https://commondatastorage.googleapis.com/gtv-videos-bucket/'
+ 'sample/BigBuckBunny.mp4',
'https://commondatastorage.googleapis.com/gtv-videos-bucket/'
+ 'sample/BigBuckBunny.mp4'
]

#########################################################################
# We are creating ``OpenCV videoCapture`` objects to capture frames from
# sources.
video_captures = [cv2.VideoCapture(source) for source in sources]

# rgb_images will store the RGB values of the frames.
rgb_images = []
for video_capture in video_captures:
_, bgr_image = video_capture.read()

# OpenCV reads in BGR, we are converting it to RGB.
rgb_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2RGB)
rgb_images.append(rgb_image)


########################################################################
# ``timer_callback`` gets called repeatedly to change texture.

def timer_callback(_caller, _timer_event):
rgb_images = []
for video_capture in video_captures:
# Taking the new frames
_, 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

for actor_, image in zip(cube, rgb_images):
# texture_update is a function to update the texture of an actor
actor.texture_update(actor_, image)

# you've to re-render the pipeline again to display the results
show_manager.render()

#######################################################################
# ``texture_on_cube`` is the function we use, the images are assigned in
# cubemap order.


"""
|----|
| +Y |
|----|----|----|----|
| -X | +Z | +X | -Z |
|----|----|----|----|
| -Y |
|----|
"""
######################################################################


cube = actor.texture_on_cube(*rgb_images, centers=(0, 0, 0))

# adding the returned Actors to scene
scene = window.Scene()
scene.add(*cube)

######################################################################
# ``ShowManager`` controls the frequency of changing textures.
# The video is rendered by changing textures very frequently.
show_manager = window.ShowManager(scene, size=(1280, 720), reset_camera=False)
show_manager.add_timer_callback(True, int(1/60), timer_callback)


######################################################################
# Flip it to ``True`` for video.
interactive = False
if interactive:
show_manager.start()

window.record(scene, size=(1280, 720), out_path='viz_play_cube.png')
96 changes: 96 additions & 0 deletions fury/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,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,97 @@ def uncertainty_cone(
angles = main_dir_uncertainty(evals, evecs, signal, sigma, b_matrix)

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


def texture_on_cube(negx, negy, negz, posx, posy, posz, centers=(0, 0, 0)):
"""Map RGB or RGBA textures on a cube

Parameters
----------
negx : ndarray
Input 2D RGB or RGBA array.
negy : ndarray
Input 2D RGB or RGBA array.
negz : ndarray
Input 2D RGB or RGBA array.
posx : ndarray
Input 2D RGB or RGBA array.
posy : ndarray
Input 2D RGB or RGBA array.
posz : ndarray
Input 2D RGB or RGBA array.
centers : tuple (3,), optional
The X, Y and Z coordinate of the cube.

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

Returns
-------
actors : list[Actor]
A list of 6 Actor objects, one for each face of the cube, in order.

"""
plane_objects = [PlaneSource() for _ in range(6)]
robinroy03 marked this conversation as resolved.
Show resolved Hide resolved

center_x, center_y, center_z = centers
plane_centers = [
(-0.5 + center_x, 0 + center_y, 0 + center_z),
(0 + center_x, -0.5 + center_y, 0 + center_z),
(0 + center_x, 0 + center_y, -0.5 + center_z),
(0.5 + center_x, 0 + center_y, 0 + center_z),
(0 + center_x, 0.5 + center_y, 0 + center_z),
(0 + center_x, 0 + center_y, 0.5 + center_z)
]

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(
plane_objects,
plane_centers,
plane_normals
):
plane.SetCenter(*center)
plane.SetNormal(*normal)

image_grids = [negx, negy, negz, posx, posy, posz]
image_data_objects = [
numpy_to_vtk_image_data(grid) for grid in image_grids
]
robinroy03 marked this conversation as resolved.
Show resolved Hide resolved

texture_objects = [Texture() for _ in range(6)]
for image_data, texture in zip(
image_data_objects,
texture_objects
):
texture.SetInputDataObject(image_data)

polydatamapper_objects = [PolyDataMapper() for _ in range(6)]
for mapper, plane in zip(
polydatamapper_objects,
plane_objects
):
mapper.SetInputConnection(plane.GetOutputPort())

actor_objects = [Actor() for _ in range(6)]
for actor, mapper, texture in zip(
actor_objects,
polydatamapper_objects,
texture_objects
):
actor.SetMapper(mapper)
actor.SetTexture(texture)

return actor_objects
2 changes: 2 additions & 0 deletions fury/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@
TexturedSphereSource = fsvtk.vtkTexturedSphereSource
#: class for RegularPolygonSource
RegularPolygonSource = fsvtk.vtkRegularPolygonSource
#: class for PlaneSource
PlaneSource = fsvtk.vtkPlaneSource

##############################################################
# vtkCommonDataModel Module
Expand Down
35 changes: 35 additions & 0 deletions fury/tests/test_actors.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,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 Actor

# Allow import, but disable doctests if we don't have dipy
from fury.optpkg import optional_package
Expand Down Expand Up @@ -1879,3 +1880,37 @@ 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_texture_on_cube(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.texture_on_cube(arr_white,
arr_red,
arr_green,
arr_blue,
arr_yellow,
arr_aqua,
(1, 2, 3))

# testing whether 6 VTK Planes are returned
assert len(cube) == 6 and isinstance(cube[0], Actor)

# testing whether the colors render as required (testing only 1)
scene = window.Scene()
scene.add(cube[5])

pic1 = window.snapshot(scene)
res1 = window.analyze_snapshot(im=pic1, colors=[
(0, 255, 255), (255, 255, 255)
])

npt.assert_equal(res1.colors_found, [True, False])
Loading