pyvale 2025.5.3__cp311-cp311-musllinux_1_2_i686.whl → 2025.7.1__cp311-cp311-musllinux_1_2_i686.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of pyvale might be problematic. Click here for more details.

Files changed (98) hide show
  1. pyvale/__init__.py +12 -0
  2. pyvale/blendercalibrationdata.py +3 -1
  3. pyvale/blenderscene.py +7 -5
  4. pyvale/blendertools.py +27 -5
  5. pyvale/camera.py +1 -0
  6. pyvale/cameradata.py +3 -0
  7. pyvale/camerasensor.py +147 -0
  8. pyvale/camerastereo.py +4 -4
  9. pyvale/cameratools.py +23 -61
  10. pyvale/cython/rastercyth.c +1657 -1352
  11. pyvale/cython/rastercyth.cpython-311-i386-linux-musl.so +0 -0
  12. pyvale/cython/rastercyth.py +71 -26
  13. pyvale/data/DIC_Challenge_Star_Noise_Def.tiff +0 -0
  14. pyvale/data/DIC_Challenge_Star_Noise_Ref.tiff +0 -0
  15. pyvale/data/plate_hole_def0000.tiff +0 -0
  16. pyvale/data/plate_hole_def0001.tiff +0 -0
  17. pyvale/data/plate_hole_ref0000.tiff +0 -0
  18. pyvale/data/plate_rigid_def0000.tiff +0 -0
  19. pyvale/data/plate_rigid_def0001.tiff +0 -0
  20. pyvale/data/plate_rigid_ref0000.tiff +0 -0
  21. pyvale/dataset.py +96 -6
  22. pyvale/dic/cpp/dicbruteforce.cpp +370 -0
  23. pyvale/dic/cpp/dicfourier.cpp +648 -0
  24. pyvale/dic/cpp/dicinterpolator.cpp +559 -0
  25. pyvale/dic/cpp/dicmain.cpp +215 -0
  26. pyvale/dic/cpp/dicoptimizer.cpp +675 -0
  27. pyvale/dic/cpp/dicrg.cpp +137 -0
  28. pyvale/dic/cpp/dicscanmethod.cpp +677 -0
  29. pyvale/dic/cpp/dicsmooth.cpp +138 -0
  30. pyvale/dic/cpp/dicstrain.cpp +383 -0
  31. pyvale/dic/cpp/dicutil.cpp +563 -0
  32. pyvale/dic2d.py +164 -0
  33. pyvale/dic2dcpp.cpython-311-i386-linux-musl.so +0 -0
  34. pyvale/dicchecks.py +476 -0
  35. pyvale/dicdataimport.py +247 -0
  36. pyvale/dicregionofinterest.py +887 -0
  37. pyvale/dicresults.py +55 -0
  38. pyvale/dicspecklegenerator.py +238 -0
  39. pyvale/dicspecklequality.py +305 -0
  40. pyvale/dicstrain.py +387 -0
  41. pyvale/dicstrainresults.py +37 -0
  42. pyvale/errorintegrator.py +10 -8
  43. pyvale/examples/basics/ex1_1_basicscalars_therm2d.py +124 -113
  44. pyvale/examples/basics/ex1_2_sensormodel_therm2d.py +124 -132
  45. pyvale/examples/basics/ex1_3_customsens_therm3d.py +199 -195
  46. pyvale/examples/basics/ex1_4_basicerrors_therm3d.py +125 -121
  47. pyvale/examples/basics/ex1_5_fielderrs_therm3d.py +145 -141
  48. pyvale/examples/basics/ex1_6_caliberrs_therm2d.py +96 -101
  49. pyvale/examples/basics/ex1_7_spatavg_therm2d.py +109 -105
  50. pyvale/examples/basics/ex2_1_basicvectors_disp2d.py +92 -91
  51. pyvale/examples/basics/ex2_2_vectorsens_disp2d.py +96 -90
  52. pyvale/examples/basics/ex2_3_sensangle_disp2d.py +88 -89
  53. pyvale/examples/basics/ex2_4_chainfielderrs_disp2d.py +172 -171
  54. pyvale/examples/basics/ex2_5_vectorfields3d_disp3d.py +88 -86
  55. pyvale/examples/basics/ex3_1_basictensors_strain2d.py +90 -90
  56. pyvale/examples/basics/ex3_2_tensorsens2d_strain2d.py +93 -91
  57. pyvale/examples/basics/ex3_3_tensorsens3d_strain3d.py +172 -160
  58. pyvale/examples/basics/ex4_1_expsim2d_thermmech2d.py +154 -148
  59. pyvale/examples/basics/ex4_2_expsim3d_thermmech3d.py +249 -231
  60. pyvale/examples/dic/ex1_region_of_interest.py +98 -0
  61. pyvale/examples/dic/ex2_plate_with_hole.py +149 -0
  62. pyvale/examples/dic/ex3_plate_with_hole_strain.py +93 -0
  63. pyvale/examples/dic/ex4_dic_blender.py +95 -0
  64. pyvale/examples/dic/ex5_dic_challenge.py +102 -0
  65. pyvale/examples/imagedef2d/ex_imagedef2d_todisk.py +4 -2
  66. pyvale/examples/renderblender/ex1_1_blenderscene.py +152 -105
  67. pyvale/examples/renderblender/ex1_2_blenderdeformed.py +151 -100
  68. pyvale/examples/renderblender/ex2_1_stereoscene.py +183 -116
  69. pyvale/examples/renderblender/ex2_2_stereodeformed.py +185 -112
  70. pyvale/examples/renderblender/ex3_1_blendercalibration.py +164 -109
  71. pyvale/examples/renderrasterisation/ex_rastenp.py +74 -35
  72. pyvale/examples/renderrasterisation/ex_rastercyth_oneframe.py +6 -13
  73. pyvale/examples/renderrasterisation/ex_rastercyth_static_cypara.py +2 -2
  74. pyvale/examples/renderrasterisation/ex_rastercyth_static_pypara.py +2 -4
  75. pyvale/imagedef2d.py +3 -2
  76. pyvale/imagetools.py +137 -0
  77. pyvale/rastercy.py +34 -4
  78. pyvale/rasternp.py +300 -276
  79. pyvale/rasteropts.py +58 -0
  80. pyvale/renderer.py +47 -0
  81. pyvale/rendermesh.py +52 -62
  82. pyvale/renderscene.py +51 -0
  83. pyvale/sensorarrayfactory.py +2 -2
  84. pyvale/sensortools.py +19 -35
  85. pyvale/simcases/case21.i +1 -1
  86. pyvale/simcases/run_1case.py +8 -0
  87. pyvale/simtools.py +2 -2
  88. pyvale/visualsimplotter.py +180 -0
  89. {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/METADATA +11 -57
  90. {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/RECORD +96 -56
  91. {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/WHEEL +1 -1
  92. pyvale.libs/libgcc_s-887de51c.so.1 +0 -0
  93. pyvale.libs/libgomp-24921df4.so.1.0.0 +0 -0
  94. pyvale.libs/libstdc++-d6415257.so.6.0.33 +0 -0
  95. pyvale/examples/visualisation/ex1_1_plot_traces.py +0 -102
  96. pyvale/examples/visualisation/ex2_1_animate_sim.py +0 -89
  97. {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/licenses/LICENSE +0 -0
  98. {pyvale-2025.5.3.dist-info → pyvale-2025.7.1.dist-info}/top_level.txt +0 -0
@@ -4,125 +4,192 @@
4
4
  # Copyright (C) 2025 The Computer Aided Validation Team
5
5
  # ==============================================================================
6
6
 
7
+ """
8
+ Blender example: Creating a scene with stereo DIC
9
+ -------------------------------------------------
10
+
11
+ This example takes you through creating a scene and adding all the necessary
12
+ objects required to represent a stereo DIC setup (two cameras, lighting and
13
+ sample). This example will then show you how to render a static image of this
14
+ scene.
15
+
16
+ Test case: mechanical analysis of a plate with a hole loaded in tension.
17
+ """
7
18
  import numpy as np
8
19
  from scipy.spatial.transform import Rotation
9
20
  from pathlib import Path
10
21
  import pyvale
11
22
  import mooseherder as mh
12
23
 
13
- def main() -> None:
14
- data_path = pyvale.DataSet.render_mechanical_3d_path()
15
- sim_data = mh.ExodusReader(data_path).read_all_sim_data()
16
-
17
- disp_comps = ("disp_x","disp_y", "disp_z")
18
-
19
- # Scale m -> mm
20
- # NOTE: All lengths are to be specified in mm
21
- sim_data = pyvale.scale_length_units(sim_data,disp_comps,1000.0)
22
-
23
- render_mesh = pyvale.create_render_mesh(sim_data,
24
- ("disp_y","disp_x"),
25
- sim_spat_dim=3,
26
- field_disp_keys=disp_comps)
27
-
28
- # Set the save path
29
- # --------------------------------------------------------------------------
30
- # All the files saved will be saved to a subfolder within this specified
31
- # base directory.
32
- # This base directory can be specified by:
33
- base_dir = Path.cwd()
34
- # If no base directory is specified, it will be set as your home directory
35
-
36
- # Creating the scene
37
- # --------------------------------------------------------------------------
38
- scene = pyvale.BlenderScene()
39
-
40
- part = scene.add_part(render_mesh, sim_spat_dim=3)
41
- # Set the part location
42
- part_location = np.array([0, 0, 0])
43
- pyvale.BlenderTools.move_blender_obj(part=part, pos_world=part_location)
44
- # Set part rotation
45
- part_rotation = Rotation.from_euler("xyz", [0, 0, 0])
46
- pyvale.BlenderTools.rotate_blender_obj(part=part, rot_world=part_rotation)
47
-
48
- # Add the stereo camera system
49
- cam_data_0 = pyvale.CameraData(pixels_num=np.array([1540, 1040]),
50
- pixels_size=np.array([0.00345, 0.00345]),
51
- pos_world=np.array([0, 0, 400]),
52
- rot_world=Rotation.from_euler("xyz", [0, 0, 0]),
53
- roi_cent_world=(0, 0, 0),
54
- focal_length=15.0)
55
- # Set this to "symmetric" to get a symmetric stereo system or set this to
56
- # "faceon" to get a face-on stereo system
57
- stereo_setup = "faceon"
58
- if stereo_setup == "symmetric":
59
- stereo_system = pyvale.CameraTools.symmetric_stereo_cameras(
60
- cam_data_0=cam_data_0,
61
- stereo_angle=15.0)
62
- if stereo_setup == "faceon":
63
- stereo_system = pyvale.CameraTools.faceon_stereo_cameras(
64
- cam_data_0=cam_data_0,
65
- stereo_angle=15.0)
66
-
67
- cam0, cam1 = scene.add_stereo_system(stereo_system)
68
-
69
- # Generate calibration file
70
- stereo_system.save_calibration(base_dir)
71
-
72
- # Add the light
73
- light_data = pyvale.BlenderLightData(type=pyvale.BlenderLightType.POINT,
74
- pos_world=(0, 0, 400),
75
- rot_world=Rotation.from_euler("xyz",
76
- [0, 0, 0]),
77
- energy=1)
78
- light = scene.add_light(light_data)
79
-
80
- # The light can also be moved and rotated:
81
- light.location = (0, 0, 410)
82
- light.rotation_euler = (0, 0, 0) # NOTE: The default is an XYZ Euler angle
83
-
84
- # Apply the speckle pattern
85
- material_data = pyvale.BlenderMaterialData()
86
- speckle_path = pyvale.DataSet.dic_pattern_5mpx_path()
87
- # NOTE: If you wish to use a bigger camera, you will need to generate a
88
- # bigger speckle pattern generator
89
-
90
- mm_px_resolution = pyvale.CameraTools.calculate_mm_px_resolution(cam_data_0)
91
- scene.add_speckle(part=part,
92
- speckle_path=speckle_path,
93
- mat_data=material_data,
94
- mm_px_resolution=mm_px_resolution)
95
-
96
- # Rendering image
97
- # --------------------------------------------------------------------------
98
- # Set this to True to render image of the current scene
99
- render_opts = True
100
- if render_opts:
101
- # NOTE: If no save directory is specified, this is where the images will
102
- # be saved
103
- render_data = pyvale.RenderData(cam_data=(stereo_system.cam_data_0,
104
- stereo_system.cam_data_1),
105
- base_dir=base_dir,
106
- threads=8)
107
- # NOTE: The number of threads used to render the images is set within
108
- # RenderData, it is defaulted to 4 threads
109
-
110
- scene.render_single_image(stage_image=False,
111
- render_data=render_data)
112
- # NOTE: If bounce_image is set to True, the image will be saved to disk,
113
- # converted to an array, deleted and the image array will be returned.
114
-
115
- print()
116
- print(80*"-")
117
- print("Save directory of the image:", (render_data.base_dir / "blenderimages"))
118
- print(80*"-")
119
- print()
120
-
121
- # Save Blender file
122
- # --------------------------------------------------------------------------
123
- # The file that will be saved is a Blender project file. This can be opened
124
- # with the Blender GUI to view the scene.
125
- pyvale.BlenderTools.save_blender_file(base_dir=base_dir)
126
-
127
- if __name__ == "__main__":
128
- main()
24
+ # %%
25
+ # The simulation results are loaded in here in the same way as the previous
26
+ # example. As mentioned this `data_path` can be replaced with your own MOOSE
27
+ # simulation output in exodus format (*.e).
28
+
29
+ data_path = pyvale.DataSet.render_mechanical_3d_path()
30
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
31
+
32
+ # %%
33
+ # This is then scaled to mm, as all lengths in Blender are to be set in mm.
34
+ # The `SimData` object is then converted into a `RenderMeshData` object, as
35
+ # this skins the mesh ready to be imported into Blender.
36
+ # The `disp_comps` are the expected direction of displacement. Since this is a
37
+ # 3D deformation test case, displacement is expected in the x, y and z directions.
38
+
39
+ disp_comps = ("disp_x","disp_y", "disp_z")
40
+ sim_data = pyvale.scale_length_units(scale=1000.0,
41
+ sim_data=sim_data,
42
+ disp_comps=disp_comps)
43
+
44
+ render_mesh = pyvale.create_render_mesh(sim_data,
45
+ ("disp_y","disp_x"),
46
+ sim_spat_dim=3,
47
+ field_disp_keys=disp_comps)
48
+
49
+ # %%
50
+ # Firstly, a save path must be set.
51
+ # In order to do this a base path must be set. Then all the generated files will
52
+ # be saved to a subfolder within this specified base directory
53
+ # (e.g. blenderimages).
54
+ # If no base directory is specified, it will be set as your home directory.
55
+
56
+ base_dir = Path.cwd()
57
+
58
+ # %%
59
+ # Creating the scene
60
+ # ^^^^^^^^^^^^^^^^^^
61
+ # In order to create a DIC setup in Blender, first a scene must be created.
62
+ # A scene is initialised using the `BlenderScene` class. All the subsequent
63
+ # objects and actions necessary are then methods of this class.
64
+ scene = pyvale.BlenderScene()
65
+
66
+ # %%
67
+ # The next thing that can be added to the scene is a sample.
68
+ # This is done by passing in the `RenderMeshData` object.
69
+ # It should be noted that the mesh will be centred on the origin to allow for
70
+ # the cameras to be centred on the mesh.
71
+ # Once the part is added to the Blender scene, it can be both moved and rotated.
72
+
73
+ part = scene.add_part(render_mesh, sim_spat_dim=3)
74
+ # Set the part location
75
+ part_location = np.array([0, 0, 0])
76
+ pyvale.BlenderTools.move_blender_obj(part=part, pos_world=part_location)
77
+ # Set part rotation
78
+ part_rotation = Rotation.from_euler("xyz", [0, 0, 0], degrees=True)
79
+ pyvale.BlenderTools.rotate_blender_obj(part=part, rot_world=part_rotation)
80
+
81
+ # %%
82
+ # The cameras can then be initialised. A stereo camera system is defined by a
83
+ # `CameraStereo` object, which contains the intrinsic parameters of both cameras
84
+ # as well as the extrinsic parameters between them.
85
+ # There are two ways to initialise a `CameraStereo` object.
86
+ # One way is to specify the camera parameters separately for each camera, create
87
+ # a `CameraStereo` object, and then add the stereo system using the
88
+ # `add_stereo_system` method.
89
+ # The other method is to use a convenience function, as shown below.
90
+ # This requires you to first initialise one camera. Then you can choose between
91
+ # either a face-on or symmetric stereo system. Then, either of the
92
+ # `symmetric_stereo_cameras` or `faceon_stereo_cameras` functions can be used to
93
+ # initialise a `CameraStereo` object. The only input required to these functions
94
+ # are the camera parameters for the first camera, and the desired stereo angle
95
+ # between the two. The cameras can then be added to the Blender scene using the
96
+ # `add_stereo_system` method.
97
+
98
+ cam_data_0 = pyvale.CameraData(pixels_num=np.array([1540, 1040]),
99
+ pixels_size=np.array([0.00345, 0.00345]),
100
+ pos_world=np.array([0, 0, 400]),
101
+ rot_world=Rotation.from_euler("xyz", [0, 0, 0]),
102
+ roi_cent_world=(0, 0, 0),
103
+ focal_length=15.0)
104
+ # Set this to "symmetric" to get a symmetric stereo system or set this to
105
+ # "faceon" to get a face-on stereo system
106
+ stereo_setup = "faceon"
107
+ if stereo_setup == "symmetric":
108
+ stereo_system = pyvale.CameraTools.symmetric_stereo_cameras(
109
+ cam_data_0=cam_data_0,
110
+ stereo_angle=15.0)
111
+ if stereo_setup == "faceon":
112
+ stereo_system = pyvale.CameraTools.faceon_stereo_cameras(
113
+ cam_data_0=cam_data_0,
114
+ stereo_angle=15.0)
115
+ cam0, cam1 = scene.add_stereo_system(stereo_system)
116
+
117
+ # %%
118
+ # Since this scene contains a stereo DIC system, a calibration file will be
119
+ # required to run the images through a DIC engine.
120
+ # A calibration file can be generated directly from the `CameraStereo` object.
121
+ # The calibration file will be saved in `YAML` format. However, if you wish to
122
+ # use MatchID to process the images, `save_calibration_mid` can be used instead
123
+ # to save the calibration in a format readable by MatchID.
124
+ # The calibration file will be saved to a sub-directory of the base directory
125
+ # called "calibration".
126
+ stereo_system.save_calibration(base_dir)
127
+
128
+ # %%
129
+ # A light can the be added to the scene.
130
+ # Blender offers different light types: Point, Sun, Spot and Area.
131
+ # The light can also be moved and rotated like the camera.
132
+
133
+ light_data = pyvale.BlenderLightData(type=pyvale.BlenderLightType.POINT,
134
+ pos_world=(0, 0, 400),
135
+ rot_world=Rotation.from_euler("xyz",
136
+ [0, 0, 0]),
137
+ energy=1)
138
+ light = scene.add_light(light_data)
139
+ light.location = (0, 0, 410)
140
+ light.rotation_euler = (0, 0, 0) # NOTE: The default is an XYZ Euler angle
141
+
142
+ # %%
143
+ # A speckle pattern can then be applied to the sample.
144
+ # Firstly, the material properties of the sample must be specified, but these
145
+ # will all be defaulted if no inputs are provided.
146
+ #The speckle pattern can then be specified by providing a path to an image file
147
+ # with the pattern.
148
+ # The mm/px resolution of the camera must also be specified in order to
149
+ # correctly scale the speckle pattern.
150
+ # It should be noted that for a bigger camera or sample you may need to generate
151
+ # a larger speckle pattern.
152
+
153
+ material_data = pyvale.BlenderMaterialData()
154
+ speckle_path = pyvale.DataSet.dic_pattern_5mpx_path()
155
+
156
+ mm_px_resolution = pyvale.CameraTools.calculate_mm_px_resolution(cam_data_0)
157
+ scene.add_speckle(part=part,
158
+ speckle_path=speckle_path,
159
+ mat_data=material_data,
160
+ mm_px_resolution=mm_px_resolution)
161
+
162
+ # %%
163
+ # Rendering a set of images
164
+ # ^^^^^^^^^^^^^^^^^^^^^^^^^
165
+ # Once all the objects have been added to the scene, a set of images can be
166
+ # rendered.Firstly, all the rendering parameters must be set, including
167
+ # parameters such as the number of threads to use.
168
+ # Differently to a 2D DIC system, both cameras' parameters must be specified in
169
+ # the `RenderData` object.
170
+
171
+ render_data = pyvale.RenderData(cam_data=(stereo_system.cam_data_0,
172
+ stereo_system.cam_data_1),
173
+ base_dir=base_dir,
174
+ threads=8)
175
+
176
+ # %%
177
+ # A single set of images of the scene can then be rendered.
178
+ # This will render a single image from each of the cameras.
179
+ # If `stage_image` is set to True, the image will be saved to disk, converted to
180
+ # an array, deleted and the image array will be returned. This is due to the
181
+ # fact that an image cannot be saved directly as an array through Blender.
182
+
183
+ scene.render_single_image(stage_image=False,
184
+ render_data=render_data)
185
+
186
+ # %%
187
+ # The rendered images will be saved to this filepath:
188
+
189
+ print("Save directory of the image:", (render_data.base_dir / "blenderimages"))
190
+
191
+ # %%
192
+ # There is also the option to save the scene as a Blender project file.
193
+ # This file can be opened with the Blender GUI to view the scene.
194
+
195
+ pyvale.BlenderTools.save_blender_file(base_dir)
@@ -4,128 +4,201 @@
4
4
  # Copyright (C) 2025 The Computer Aided Validation Team
5
5
  # ==============================================================================
6
6
 
7
+ """
8
+ Blender example: Deforming a sample with stereo DIC
9
+ ===================================================
10
+
11
+ This example takes you through creating stereo DIC scene, applying deformation
12
+ to the sample, and rendering images at each deformation timestep.
13
+
14
+ Test case: mechanical analysis of a plate with a hole loaded in tension.
15
+ """
16
+
7
17
  import numpy as np
8
18
  from scipy.spatial.transform import Rotation
9
19
  from pathlib import Path
10
20
  import pyvale
11
21
  import mooseherder as mh
12
22
 
13
- def main() -> None:
14
- data_path = pyvale.DataSet.render_mechanical_3d_path()
15
- sim_data = mh.ExodusReader(data_path).read_all_sim_data()
23
+ # %%
24
+ # The simulation results are loaded in here in the same way as the previous
25
+ # example. As mentioned this `data_path` can be replaced with your own MOOSE
26
+ # simulation output in exodus format (*.e).
16
27
 
17
- disp_comps = ("disp_x","disp_y", "disp_z")
28
+ data_path = pyvale.DataSet.render_mechanical_3d_path()
29
+ sim_data = mh.ExodusReader(data_path).read_all_sim_data()
18
30
 
19
- # Scale m -> mm
20
- # NOTE: All lengths are to be specified in mm
21
- sim_data = pyvale.scale_length_units(sim_data,disp_comps,1000.0)
31
+ # %%
32
+ # This is then scaled to mm, as all lengths in Blender are to be set in mm.
33
+ # The `SimData` object is then converted into a `RenderMeshData` object, as
34
+ # this skins the mesh ready to be imported into Blender.
35
+ # The `disp_comps` are the expected direction of displacement. Since this is a
36
+ # 3D deformation test case, displacement is expected in the x, y and z directions.
22
37
 
23
- render_mesh = pyvale.create_render_mesh(sim_data,
38
+ disp_comps = ("disp_x","disp_y", "disp_z")
39
+ sim_data = pyvale.scale_length_units(scale=1000.0,
40
+ sim_data=sim_data,
41
+ disp_comps=disp_comps)
42
+
43
+ render_mesh = pyvale.create_render_mesh(sim_data,
24
44
  ("disp_y","disp_x"),
25
45
  sim_spat_dim=3,
26
46
  field_disp_keys=disp_comps)
27
47
 
28
- # Set the save path
29
- # --------------------------------------------------------------------------
30
- # All the files saved will be saved to a subfolder within this specified
31
- # base directory.
32
- # This base directory can be specified by:
33
- base_dir = Path.cwd()
34
- # If no base directory is specified, it will be set as your home directory
35
-
36
- # Creating the scene
37
- # --------------------------------------------------------------------------
38
- scene = pyvale.BlenderScene()
39
-
40
- part = scene.add_part(render_mesh, sim_spat_dim=3)
41
- # Set the part location
42
- part_location = np.array([0, 0, 0])
43
- pyvale.BlenderTools.move_blender_obj(part=part, pos_world=part_location)
44
- # Set part rotation
45
- part_rotation = Rotation.from_euler("xyz", [0, 0, 0])
46
- pyvale.BlenderTools.rotate_blender_obj(part=part, rot_world=part_rotation)
47
-
48
- # Add the stereo camera system
49
- cam_data_0 = pyvale.CameraData(pixels_num=np.array([1540, 1040]),
50
- pixels_size=np.array([0.00345, 0.00345]),
51
- pos_world=np.array([0, 0, 400]),
52
- rot_world=Rotation.from_euler("xyz", [0, 0, 0]),
53
- roi_cent_world=(0, 0, 0),
54
- focal_length=15.0)
55
- # Set this to "symmetric" to get a symmetric stereo system or set this to
56
- # "faceon" to get a face-on stereo system
57
- stereo_setup = "faceon"
58
- if stereo_setup == "symmetric":
59
- stereo_system = pyvale.CameraTools.symmetric_stereo_cameras(
60
- cam_data_0=cam_data_0,
61
- stereo_angle=15.0)
62
- if stereo_setup == "faceon":
63
- stereo_system = pyvale.CameraTools.faceon_stereo_cameras(
64
- cam_data_0=cam_data_0,
65
- stereo_angle=15.0)
66
-
67
- cam0, cam1 = scene.add_stereo_system(stereo_system)
68
-
69
- # Generate calibration file
70
- stereo_system.save_calibration(base_dir)
71
-
72
- # Add the light
73
- light_data = pyvale.BlenderLightData(type=pyvale.BlenderLightType.POINT,
74
- pos_world=(0, 0, 400),
75
- rot_world=Rotation.from_euler("xyz",
76
- [0, 0, 0]),
77
- energy=1)
78
- light = scene.add_light(light_data)
79
-
80
- # The light can also be moved and rotated:
81
- light.location = (0, 0, 410)
82
- light.rotation_euler = (0, 0, 0) # NOTE: The default is an XYZ Euler angle
83
-
84
- # Apply the speckle pattern
85
- material_data = pyvale.BlenderMaterialData()
86
- speckle_path = pyvale.DataSet.dic_pattern_5mpx_path()
87
- # NOTE: If you wish to use a bigger camera, you will need to generate a
88
- # bigger speckle pattern generator
89
-
90
- mm_px_resolution = pyvale.CameraTools.calculate_mm_px_resolution(cam_data_0)
91
- scene.add_speckle(part=part,
92
- speckle_path=speckle_path,
93
- mat_data=material_data,
94
- mm_px_resolution=mm_px_resolution)
95
-
96
- # Deform and render images
97
- # --------------------------------------------------------------------------
98
- # Set this to True to render image of the deforming part
99
- render_opts = True
100
- if render_opts:
101
- # NOTE: If no save directory is specified, this is where the images will
102
- # be saved
103
- render_data = pyvale.RenderData(cam_data=(stereo_system.cam_data_0,
104
- stereo_system.cam_data_1),
105
- base_dir=base_dir,
106
- threads=8)
107
- # NOTE: The number of threads used to render the images is set within
108
- # RenderData, it is defaulted to 4 threads
109
-
110
- scene.render_deformed_images(render_mesh=render_mesh,
111
- sim_spat_dim=3,
112
- render_data=render_data,
113
- part=part,
114
- stage_image=False)
115
- # NOTE: If bounce_image is set to True, the image will be saved to disk,
116
- # converted to an array, deleted and the image array will be returned.
117
-
118
- print()
119
- print(80*"-")
120
- print("Save directory of the image:", (render_data.base_dir / "blenderimages"))
121
- print(80*"-")
122
- print()
123
-
124
- # Save Blender file
125
- # --------------------------------------------------------------------------
126
- # The file that will be saved is a Blender project file. This can be opened
127
- # with the Blender GUI to view the scene.
128
- pyvale.BlenderTools.save_blender_file(base_dir)
129
-
130
- if __name__ == "__main__":
131
- main()
48
+ # %%
49
+ # Firstly, a save path must be set.
50
+ # In order to do this a base path must be set. Then all the generated files will
51
+ # be saved to a subfolder within this specified base directory
52
+ # (e.g. blenderimages).
53
+ # If no base directory is specified, it will be set as your home directory.
54
+
55
+ base_dir = Path.cwd()
56
+
57
+ # %%
58
+ # Creating the scene
59
+ # ^^^^^^^^^^^^^^^^^^
60
+ # In order to create a DIC setup in Blender, first a scene must be created.
61
+ # A scene is initialised using the `BlenderScene` class. All the subsequent
62
+ # objects and actions necessary are then methods of this class.
63
+ scene = pyvale.BlenderScene()
64
+
65
+ # %%
66
+ # The next thing that can be added to the scene is a sample.
67
+ # This is done by passing in the `RenderMeshData` object.
68
+ # It should be noted that the mesh will be centred on the origin to allow for
69
+ # the cameras to be centred on the mesh.
70
+ # Once the part is added to the Blender scene, it can be both moved and rotated.
71
+
72
+ part = scene.add_part(render_mesh, sim_spat_dim=3)
73
+ # Set the part location
74
+ part_location = np.array([0, 0, 0])
75
+ pyvale.BlenderTools.move_blender_obj(part=part, pos_world=part_location)
76
+ # Set part rotation
77
+ part_rotation = Rotation.from_euler("xyz", [0, 0, 0], degrees=True)
78
+ pyvale.BlenderTools.rotate_blender_obj(part=part, rot_world=part_rotation)
79
+
80
+ # %%
81
+ # The cameras can then be initialised. A stereo camera system is defined by a
82
+ # `CameraStereo` object, which contains the intrinsic parameters of both cameras
83
+ # as well as the extrinsic parameters between them.
84
+ # There are two ways to initialise a `CameraStereo` object.
85
+ # One way is to specify the camera parameters separately for each camera, create
86
+ # a `CameraStereo` object, and then add the stereo system using the
87
+ # `add_stereo_system` method.
88
+ # The other method is to use a convenience function, as shown below.
89
+ # This requires you to first initialise one camera. Then you can choose between
90
+ # either a face-on or symmetric stereo system. Then, either of the
91
+ # `symmetric_stereo_cameras` or `faceon_stereo_cameras` functions can be used to
92
+ # initialise a `CameraStereo` object. The only input required to these functions
93
+ # are the camera parameters for the first camera, and the desired stereo angle
94
+ # between the two. The cameras can then be added to the Blender scene using the
95
+ # `add_stereo_system` method.
96
+
97
+ cam_data_0 = pyvale.CameraData(pixels_num=np.array([1540, 1040]),
98
+ pixels_size=np.array([0.00345, 0.00345]),
99
+ pos_world=np.array([0, 0, 400]),
100
+ rot_world=Rotation.from_euler("xyz", [0, 0, 0]),
101
+ roi_cent_world=(0, 0, 0),
102
+ focal_length=15.0)
103
+ # Set this to "symmetric" to get a symmetric stereo system or set this to
104
+ # "faceon" to get a face-on stereo system
105
+ stereo_setup = "faceon"
106
+ if stereo_setup == "symmetric":
107
+ stereo_system = pyvale.CameraTools.symmetric_stereo_cameras(
108
+ cam_data_0=cam_data_0,
109
+ stereo_angle=15.0)
110
+ if stereo_setup == "faceon":
111
+ stereo_system = pyvale.CameraTools.faceon_stereo_cameras(
112
+ cam_data_0=cam_data_0,
113
+ stereo_angle=15.0)
114
+ cam0, cam1 = scene.add_stereo_system(stereo_system)
115
+
116
+ # %%
117
+ # Since this scene contains a stereo DIC system, a calibration file will be
118
+ # required to run the images through a DIC engine.
119
+ # A calibration file can be generated directly from the `CameraStereo` object.
120
+ # The calibration file will be saved in `YAML` format. However, if you wish to
121
+ # use MatchID to process the images, `save_calibration_mid` can be used instead
122
+ # to save the calibration in a format readable by MatchID.
123
+ # The calibration file will be saved to a sub-directory of the base directory
124
+ # called "calibration".
125
+ stereo_system.save_calibration(base_dir)
126
+
127
+ # %%
128
+ # A light can the be added to the scene.
129
+ # Blender offers different light types: Point, Sun, Spot and Area.
130
+ # The light can also be moved and rotated like the camera.
131
+ light_data = pyvale.BlenderLightData(type=pyvale.BlenderLightType.POINT,
132
+ pos_world=(0, 0, 400),
133
+ rot_world=Rotation.from_euler("xyz",
134
+ [0, 0, 0]),
135
+ energy=1)
136
+ light = scene.add_light(light_data)
137
+ light.location = (0, 0, 410)
138
+ light.rotation_euler = (0, 0, 0) # NOTE: The default is an XYZ Euler angle
139
+
140
+ # Apply the speckle pattern
141
+ material_data = pyvale.BlenderMaterialData()
142
+ speckle_path = pyvale.DataSet.dic_pattern_5mpx_path()
143
+ # NOTE: If you wish to use a bigger camera, you will need to generate a
144
+ # bigger speckle pattern generator
145
+
146
+ # %%
147
+ # A speckle pattern can then be applied to the sample.
148
+ # Firstly, the material properties of the sample must be specified, but these
149
+ # will all be defaulted if no inputs are provided.
150
+ #The speckle pattern can then be specified by providing a path to an image file
151
+ # with the pattern.
152
+ # The mm/px resolution of the camera must also be specified in order to
153
+ # correctly scale the speckle pattern.
154
+ # It should be noted that for a bigger camera or sample you may need to generate
155
+ # a larger speckle pattern.
156
+
157
+ mm_px_resolution = pyvale.CameraTools.calculate_mm_px_resolution(cam_data_0)
158
+ scene.add_speckle(part=part,
159
+ speckle_path=speckle_path,
160
+ mat_data=material_data,
161
+ mm_px_resolution=mm_px_resolution)
162
+
163
+ # %%
164
+ # Deforming the sample and rendering images
165
+ # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
166
+ # Once all the objects have been added to the scene, the sample can be deformed,
167
+ # and images can be rendered.
168
+ # Firstly, all the rendering parameters must be set, including parameters such as
169
+ # the number of threads to use.
170
+ # Differently to a 2D DIC system, both cameras' parameters must be specified in
171
+ # the `RenderData` object.
172
+ render_data = pyvale.RenderData(cam_data=(stereo_system.cam_data_0,
173
+ stereo_system.cam_data_1),
174
+ base_dir=base_dir,
175
+ threads=8)
176
+
177
+ # %%
178
+ # A series of deformed images can then be rendered.
179
+ # This is done by passing in rendering parameters, as well as the
180
+ # `RenderMeshData` object, the part(sample) and the spatial dimension of the
181
+ # simulation.
182
+ # This will automatically deform the sample, and render images from each camera
183
+ # at each deformation timestep.
184
+ # If `stage_image` is set to True, the image will be saved to disk, converted to
185
+ # an array, deleted and the image array will be returned. This is due to the
186
+ # fact that an image cannot be saved directly as an array through Blender.
187
+
188
+ scene.render_deformed_images(render_mesh=render_mesh,
189
+ sim_spat_dim=3,
190
+ render_data=render_data,
191
+ part=part,
192
+ stage_image=False)
193
+
194
+ # %%
195
+ # The rendered image will be saved to this filepath:
196
+
197
+ print("Save directory of the image:", (render_data.base_dir / "blenderimages"))
198
+
199
+ # %%
200
+ # There is also the option to save the scene as a Blender project file.
201
+ # This file can be opened with the Blender GUI to view the scene.
202
+
203
+ pyvale.BlenderTools.save_blender_file(base_dir)
204
+