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

Enhanced image polishment #163

Draft
wants to merge 39 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
65f07af
Finished the first version of enhanced image module
zhang-yuanrui Oct 4, 2024
f44b11d
Add a part name parameter to remove all hardcode
zhang-yuanrui Oct 4, 2024
19b6b6d
Reformat. Remove functions only for testing
zhang-yuanrui Oct 4, 2024
8bbede5
Simplify the code
zhang-yuanrui Oct 4, 2024
b9799cc
Merge branch 'main' of github.com:ansys/pydynamicreporting into feat/…
zhang-yuanrui Oct 9, 2024
fecbd74
Merge branch 'main' into feat/yuanrui/enhanced_images
zhang-yuanrui Oct 9, 2024
22ba889
Mark helper functions by appending '_'
zhang-yuanrui Oct 9, 2024
62e0ea8
Merge branch 'feat/yuanrui/enhanced_images' of github.com:ansys/pydyn…
zhang-yuanrui Oct 9, 2024
a72e6bd
Check package dependency
zhang-yuanrui Oct 9, 2024
07bb501
Backup _test_enhanced_images.py
zhang-yuanrui Oct 10, 2024
dc07365
properly teardown for in-mem version
zhang-yuanrui Oct 10, 2024
e4a7767
Switch to returning a buffer instead of an image
zhang-yuanrui Oct 11, 2024
b72274e
Finish testing.
zhang-yuanrui Oct 11, 2024
08f89db
Merge branch 'main' of github.com:ansys/pydynamicreporting into feat/…
zhang-yuanrui Oct 11, 2024
a1dfbf2
Add vtk and dpf dependency
zhang-yuanrui Oct 15, 2024
36b45b8
Merge branch 'main' of github.com:ansys/pydynamicreporting into feat/…
zhang-yuanrui Oct 15, 2024
a8c1936
Finish the initial test script for enhanced images
zhang-yuanrui Oct 15, 2024
622f1b5
Enable the test to install required packages
zhang-yuanrui Oct 16, 2024
6142549
reformat
zhang-yuanrui Oct 16, 2024
468e02b
Add # pragma: no cover; make all the helper functions under the modul…
zhang-yuanrui Oct 16, 2024
7c39895
Add a try catch block to bypass the test if there is no DPF server av…
zhang-yuanrui Oct 16, 2024
cea61fb
terminate the testing program if DPF server is not set
zhang-yuanrui Oct 16, 2024
143dd0a
Return None when DPF server is not found in the testing process
zhang-yuanrui Oct 16, 2024
cdab4b4
Remove unecessary import; Add pytest.mark decorations
zhang-yuanrui Oct 16, 2024
58715c8
Upgrade setuptools
zhang-yuanrui Oct 16, 2024
9844d92
skip 3.12
zhang-yuanrui Oct 17, 2024
fe4850b
rm a test file
zhang-yuanrui Oct 17, 2024
1fa7c40
Exclude dpf-core for python 3.12
zhang-yuanrui Oct 17, 2024
e23254c
Upgrade numpy for testing
zhang-yuanrui Oct 17, 2024
5af384c
Upgrade numpy in test
zhang-yuanrui Oct 17, 2024
d5eef71
Remove constraint for dpf-core
zhang-yuanrui Oct 17, 2024
95f835f
ignore extra testing files for enhanced images
zhang-yuanrui Oct 18, 2024
b26b23d
Move numpy version back to 1.25.1 and limit pyvista, vtk, dpf-core to…
zhang-yuanrui Oct 18, 2024
5719097
Remove numpy in [test]
zhang-yuanrui Oct 18, 2024
cbbbe54
Allow pyvista, vtk and dpf-core to run with python 3.12
zhang-yuanrui Oct 18, 2024
b603ec1
uncomment need smoke test
zhang-yuanrui Oct 21, 2024
314bb2e
Merge branch 'main' of github.com:ansys/pydynamicreporting into feat/…
zhang-yuanrui Oct 22, 2024
8fa2c35
1. Set background color to white. 2. Tracking the pick data in enhanc…
zhang-yuanrui Oct 22, 2024
ca2d00b
Support rotation by user inputting
zhang-yuanrui Oct 24, 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
72 changes: 47 additions & 25 deletions src/ansys/dynamicreporting/core/utils/enhanced_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@
from PIL import Image, TiffImagePlugin
import numpy as np

# import vtk
# from vtk.util.numpy_support import vtk_to_numpy
# from ansys.dpf import core as dpf
# from ansys.dpf.core import vtk_helper

try:
import vtk
from vtk.util.numpy_support import vtk_to_numpy
Expand All @@ -40,7 +35,11 @@
if HAS_VTK and HAS_DPF: # pragma: no cover

def generate_enhanced_image_as_tiff(
model: dpf.Model, var_field: dpf.Field, part_name: str, output_file_name: str
model: dpf.Model,
var_field: dpf.Field,
part_name: str,
output_file_name: str,
rotation: Tuple[float, float, float] = (0.0, 0.0, 0.0),
):
"""
Generate an enhanced image in the format of TIFF file on disk given DPF inputs.
Expand All @@ -55,12 +54,17 @@ def generate_enhanced_image_as_tiff(
part_name: str
The name of the part. It will showed on the interactive enhanced image in ADR.
output_file_name: str
output TIFF file name with extension of .tiff or .tif
output TIFF file name with extension of .tiff or .tif.
rotation: Tuple[float, float, float]
Rotation degrees about X, Y, Z axes. Note not in radians.
"""
_generate_enhanced_image(model, var_field, part_name, output_file_name)
_generate_enhanced_image(model, var_field, part_name, output_file_name, rotation)

def generate_enhanced_image_in_memory(
model: dpf.Model, var_field: dpf.Field, part_name: str
model: dpf.Model,
var_field: dpf.Field,
part_name: str,
rotation: Tuple[float, float, float] = (0.0, 0.0, 0.0),
) -> io.BytesIO:
"""
Generate an enhanced image as a PIL Image object given DPF inputs.
Expand All @@ -74,6 +78,8 @@ def generate_enhanced_image_in_memory(
the variable in interest to visualize in an enhanced image.
part_name: str
The name of the part. It will showed on the interactive enhanced image in ADR.
rotation: Tuple[float, float, float]
Rotation degrees about X, Y, Z axes. Note not in radians.

Returns
-------
Expand All @@ -83,12 +89,12 @@ def generate_enhanced_image_in_memory(
"""
# Create an in-memory bytes buffer
buffer = io.BytesIO()
_generate_enhanced_image(model, var_field, part_name, buffer)
_generate_enhanced_image(model, var_field, part_name, buffer, rotation)
buffer.seek(0)
return buffer

def _setup_render_routine(
poly_data: vtk.vtkPolyData,
poly_data: vtk.vtkPolyData, rotation: Tuple[float, float, float] = (0.0, 0.0, 0.0)
) -> Tuple[vtk.vtkRenderer, vtk.vtkRenderWindow]:
"""
Set up VTK render routine, including mapper, actor, renderer and render window.
Expand Down Expand Up @@ -117,12 +123,17 @@ def _setup_render_routine(
renderer.ResetCamera()
render_window.AddRenderer(renderer)
renderer.AddActor(actor)
actor.RotateX(rotation[0])
actor.RotateY(rotation[1])
actor.RotateZ(rotation[2])

renderer.SetBackground(1, 1, 1)

# Uncomment the following 2 lines to get an interactor
# render_window_interactor = vtk.vtkRenderWindowInteractor()
# render_window_interactor.SetRenderWindow(render_window)

return renderer, render_window # , render_windowdow_interactor
return renderer, render_window # , render_windodow_interactor

def _get_vtk_scalar_mode(poly_data: vtk.vtkPolyData, var_name: str) -> int:
"""
Expand Down Expand Up @@ -236,6 +247,16 @@ def _get_rgb_value(render_window: vtk.vtkRenderWindow) -> np.ndarray:

return np_array

def _add_pick_data(poly_data: vtk.vtkPolyData, part_id: int):
arr = vtk.vtkFloatArray()
arr.SetName("Pick Data")
arr.SetNumberOfComponents(1)
num_points = poly_data.GetNumberOfPoints()
arr.SetNumberOfTuples(num_points)
for i in range(num_points):
arr.SetValue(i, part_id)
poly_data.GetPointData().AddArray(arr)

def _render_pick_data(
poly_data: vtk.vtkPolyData, renderer: vtk.vtkRenderer, render_window: vtk.vtkRenderWindow
) -> np.ndarray:
Expand Down Expand Up @@ -362,7 +383,11 @@ def _form_enhanced_image(
)

def _generate_enhanced_image(
model: dpf.Model, var_field: dpf.Field, part_name: str, output: Union[str, io.BytesIO]
model: dpf.Model,
var_field: dpf.Field,
part_name: str,
output: Union[str, io.BytesIO],
rotation: Tuple[float, float, float] = (0.0, 0.0, 0.0),
) -> Tuple[Dict, np.ndarray, np.ndarray, np.ndarray]:
"""
Esstential helper function for DPF inputs. Generate json metadata, rgb buffer, pick
Expand All @@ -388,29 +413,26 @@ def _generate_enhanced_image(
# Get components for metadata
var_unit: str = var_field.unit
var_name = var_field.name
var_meshed_region = var_field.meshed_region
dpf_unit_system = model.metadata.result_info.unit_system_name
unit_system_to_name = dpf_unit_system.split(":", 1)[0]

mats: dpf.PropertyField = var_meshed_region.property_field("mat") # Pick data
meshed_region = model.metadata.meshed_region # Whole mesh region

# Convert DPF to a pyvista UnstructuredGrid, which inherits from vtk
grid = vtk_helper.dpf_mesh_to_vtk(var_meshed_region)
# Add pick data
grid = vtk_helper.append_field_to_grid(mats, var_meshed_region, grid, "Pick Data")
grid = vtk_helper.dpf_mesh_to_vtk(meshed_region)
# Add variable data
grid = vtk_helper.append_field_to_grid(var_field, var_meshed_region, grid, var_name)
grid = vtk_helper.append_field_to_grid(var_field, meshed_region, grid, var_name)

# Create a vtkGeometryFilter to convert UnstructuredGrid to PolyData
geometry_filter = vtk.vtkGeometryFilter()
geometry_filter.SetInputData(grid)
geometry_filter.Update()
poly_data = geometry_filter.GetOutput()
_add_pick_data(poly_data, 1) # Todo: optimize hardcoded part ID

renderer, render_window = _setup_render_routine(poly_data)
renderer, render_window = _setup_render_routine(poly_data, rotation)
rgb_buffer = _get_rgb_value(render_window)
pick_buffer = _render_pick_data(grid, renderer, render_window)
var_buffer = _render_var_data(grid, renderer, render_window, var_name)
pick_buffer = _render_pick_data(poly_data, renderer, render_window)
var_buffer = _render_var_data(poly_data, renderer, render_window, var_name)

# Todo: automatic colorby_var support
# global colorby_var_id
Expand All @@ -425,14 +447,14 @@ def _generate_enhanced_image(
"parts": [
{
"name": part_name,
"id": str(mats.data[0]),
"id": 1, # Todo: optimize hardcoded part ID
"colorby_var": "1.0", # colorby_var
}
],
"variables": [
{
"name": var_name,
"id": str(mats.data[0]),
"id": 1, # Todo: optimize hardcoded part ID
"pal_id": "1", # colorby_var_int,
"unit_dims": "",
"unit_system_to_name": unit_system_to_name,
Expand Down
Loading