Skip to content

Speckle pattern generation module#181

Open
WieraB wants to merge 19 commits intodevfrom
wb-dev
Open

Speckle pattern generation module#181
WieraB wants to merge 19 commits intodevfrom
wb-dev

Conversation

@WieraB
Copy link

@WieraB WieraB commented Nov 3, 2025

Speckle generation module consisting of the following:

  1. A general speckle generation function
  2. Diagnostics functions calculating statistics and creating plots
  3. Six usage examples corresponding to the various methods which could be applied to pattern generation
  4. Tests
  5. Updated docs

JoelPhys and others added 15 commits August 1, 2025 15:28
QOL and bugfixes following 2D DIC workshop
…clude speckle gen, and added specklegen tests.
…nction, 2.Converted number of periods into a speckle size, add random seed setting in Perlin/fractal noise, 3. Split diagnostics function into just stats and everything chart-related, let the diagnostics function return the plot handle as well. - Created function descriptions in a standard format. - Added an option to create a speckle pattern by first creating a regular circle pattern and then randomly perturbating speckles.
@WieraB WieraB changed the base branch from main to dev November 11, 2025 14:38
@ScepticalRabbit
Copy link
Collaborator

ScepticalRabbit commented Jan 23, 2026

@WieraB have we merged in the latest version of dev into this to update everything? Should be my massive refactor from me and some DIC stuff from Joel

#===============================================================================

import pyvale.verif.specklegold as specklegold
import pyvale.verif.specklegneconst as specklegneconst
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth quickly fixing the typo here "specklegenconst" - should be gen I think for consistency with the rest of the package

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've merged dev into wb-dev now. Also, I amended the typo.

@ScepticalRabbit
Copy link
Collaborator

The docs don't seem to be adding the specklegen module to the side menu and the examples aren't listed on the page - probably something needs to be added to the rst.
Screenshot from 2026-01-24 19-44-31

@WieraB
Copy link
Author

WieraB commented Jan 25, 2026

@ScepticalRabbit

The docs don't seem to be adding the specklegen module to the side menu and the examples aren't listed on the page - probably something needs to be added to the rst.

I think I fixed it now. The changes in .gitignore merged with wb-dev made git ignore examples_specklegen.rst, I commented out one line in .gitignore, which I think isn't necessary now.

sigma = 4.0
reduce_overlap = False
type_gen = "random_disks"
output_path = "src/pyvale/examples/specklegen/output/ex1a"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As default we should probably be using pathlib and Path objects to manage all directories. If you look at some of the sensor sim examples we create a standard directory called 'pyvale-output' in the current working directory:

output_path = Path.cwd() / "pyvale-output"
if not output_path.is_dir():
    output_path.mkdir(parents=True, exist_ok=True)


print('Start')

assert theme in ['black_on_white', 'white_on_black'], "Theme should be either 'black_on_white' or 'white_on_black'."
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to restrict the options a user can select I would probably use and enum:

import enum

class Theme(enum.Enum):
    BLACK_ON_WHITE = enum.auto()

subfolder = f"/{type_gen}_{speckle_size}_{screen_size_width}_{screen_size_height}_{bit_depth}_{theme}_{seed}_{sigma}_{reduce_overlap}"
print(subfolder)
save_path = output_path + subfolder
if not os.path.exists(save_path):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above about pathlib

# We now generate the speckle pattern using the specified parameters.
# The background and foreground colours are set based on the chosen theme and bit depth.

speckle_area = np.pi * (speckle_size / 2) ** 2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 3 calculations should probably be automated for the user and hidden within the generate_speckles function - the user should only need to specify the black-white ratio and all these calculations are done for them in the function


print("")
print('Starting speckle pattern diagnostics...')
results = specklegen.speckle_pattern_statistics(image, dynamic_range)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably easier for the user to just specify the number of bits and the dynamic range is calculated in the function.

plt.rc('text', usetex=True)
fontsize1= 17

fig, axes = plt.subplots(1, 1, figsize=(7.0, 5.0))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the sensor sim module (probably moving to the python common module soon) we have a standard dataclass for formatting plots: https://github.com/Computer-Aided-Validation-Laboratory/pyvale/blob/main/src/pyvale/sensorsim/visualopts.py.

Have a look at some of the plotting functions for the sensor sim module and see if you can make it consistent across modules.

print("")
print('Starting speckle pattern diagnostics...')
results = specklegen.speckle_pattern_statistics(image, dynamic_range)
plots = specklegen.speckle_pattern_plots(image, dynamic_range, save_path)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also include the images in the docs

Optimal parameters for horisontal Gaussian fit.
popt_V : array
Optimal parameters for vertical Gaussian fit.
h_profile : np.ndarray
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the docstring I will generally try and make sure I list what the dimensions of the array mean - here is it just: shape=(num_px_y,num_px_x)?

sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import pyvale.specklegen as specklegen

width_range = np.arange(10, 1000, 250)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

by convention constants outside of functions should be in CAPS. That being said there is an easier way to send a consistent set of variables to all functions using @pytest.fixture. See examples here:https://github.com/Computer-Aided-Validation-Laboratory/pyvale/blob/main/tests/mooseherder/mooseherd_test.py

if dist_sq <= radius_sq:
assert img[y, x] == fg_colour

@pytest.mark.parametrize("total_speckles", total_speckles_range)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally I would only use parametrize if I was wanting to test multiple combinations of variables. If you are only testing one variable combination like you have here then you want pytest.fixture. For an example of when to use parameterize see:

@pytest.mark.parametrize(
('n_para','expected'),
(
(0, 1),
(-1,1),
(2.5,2),
(os.cpu_count()+1,os.cpu_count()) # type: ignore
)
)
def test_set_num_para_sims(n_para: int, expected: int, herd: MooseHerd):
herd.set_num_para_sims(n_para)
assert herd._n_para_sims == expected

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants