High Point Density
Simple Stretch Revisited
capped out at 250 points — the most x values that stay integer-safe
at factor_x = 1.02, within the image's own margins. Subpixel
Accuracy removed that ceiling: once tracking
doesn't need its answer to be a whole pixel, x doesn't need to be a
multiple of 50 either. This page pushes all the way to VIC-2D's own
density — 5 pixels apart, the same 53x54, 2862-point grid Verification
Against VIC-2D and
Subpixel Accuracy both already used.
Tracking at Full Density
from dictk.grid import generate, locate_subpixel
points = generate(
origin=PixelCoordinate(x=18, y=16),
count_x=53,
count_y=54,
spacing_x=5,
spacing_y=5,
)
found = locate_subpixel(
reference_image=reference_image,
current_image=current_image,
reference_points=points,
kernel_margin_width=20,
kernel_margin_height=20,
search_margin_width=48,
search_margin_height=52,
upsample_factor=10,
)
2862 points tracked
Strain at Full Density
Same recipe as Simple Stretch Revisited: dictk.grid.elements
for connectivity (2756 elements this time, not 196), then
gauss_point_log_strains/gauss_point_coordinates
at each of the resulting 11024 Gauss points. Node numbers stay off —
2862 of them would be unreadable:
from dictk.element import gauss_point_coordinates, gauss_point_log_strains
from dictk.grid import elements
from dictk.plot import element_strain_plot
element_indices = elements(count_x=53, count_y=54)
values = []
coordinates = []
for element in element_indices:
reference_corners = [points[i] for i in element]
current_corners = [found[i] for i in element]
strains = gauss_point_log_strains(
reference_points=reference_corners, current_points=current_corners
)
values.extend(strain[0, 0] for strain in strains)
coordinates.extend(gauss_point_coordinates(points=current_corners))
element_strain_plot(
points=found,
elements=element_indices,
coordinates=coordinates,
values=values,
label=r"Log Strain, $E_{11}$",
path="high_point_density_strain_gauss_points.png",
)
element_strain_plot(
points=found,
elements=element_indices,
coordinates=coordinates,
values=values,
label=r"Log Strain, $E_{11}$",
image=current_image,
path="high_point_density_strain_on_current.png",
)
current_image.A Real Trade-Off, Not a Bug
2862-point, 5px-spacing mesh: mean = 0.0200 (true value 0.0198), but std = 0.0155, range [-0.0160, 0.0771]
The mean is accurate. The spread is not small. Unlike Simple Stretch Revisited's perfectly uniform result, individual elements here scatter well beyond the true value — some report negative strain, some report nearly 4 times the true value.
This isn't a tracking bug. Log strain is, in effect, a finite
difference: , a displacement difference
divided by element size . Subpixel Accuracy's
own measurement found locate_subpixel's residual error is small in
absolute terms — a few hundredths of a pixel, on average — but at 5
pixels of element spacing, that same absolute error is a much larger
fraction of than it was at Simple Stretch Revisited's 50-pixel
spacing. The smaller the element, the more a fixed amount of tracking
noise gets amplified into strain noise. Checked directly, not just
argued:
| Element spacing | Mean E11 | Std E11 |
|---|---|---|
| 5px | 0.01988 | 0.01544 |
| 10px | 0.01997 | 0.01247 |
| 20px | 0.02003 | 0.00988 |
| 40px | 0.01999 | 0.00318 |
Standard deviation falls as element spacing grows — the same tracking
noise, spread over a larger , moves less of the resulting strain.
This is exactly why VIC-2D and other commercial DIC packages offer a
strain window — averaging displacement over several subsets before
computing strain, trading spatial resolution for strain precision.
dictk doesn't implement that averaging yet. This page's own dense
mesh is accurate on average and honestly noisy point to point, not
silently smoothed into looking better than the underlying tracking
supports.
Point count, tracking accuracy, and now strain precision have all been
free variables throughout Simple Stretch, Subpixel Accuracy, and this
page. How dictk's own tracking time scales as point count grows —
across sequential, threaded, and multi-process execution — is
Parallelization's own question, still not
attempted here either.