Weighted correlation#

Theory#

The weighted correlation characterises the average indicator \(\mathcal{I}\) around high weight factor \(\mathcal{W}\).

Mathematically the weighted correlation reads

\[\mathcal{P} (\Delta \vec{x}) = \frac{ \sum_i \mathcal{W}(\vec{x}_i) \; \mathcal{I}(\vec{x}_i + \Delta x) }{ \sum_i \mathcal{W}(\vec{x}_i) \; }\]

Additionally pixels can be masked, for instance to ignore \(\mathcal{I}\) everywhere where \(\mathcal{W}\) is non-zero. The masked correlation reads

\[\mathcal{P} (\Delta \vec{x}) = \frac{ \sum_{i}\; \mathcal{W} (\vec{x}_i) \; [ \mathcal{I} (1-\mathcal{M}) ] (\vec{x}_i + \Delta \vec{x}) \; }{ \sum_{i}\; \mathcal{W} (\vec{x}_i) \; (1-\mathcal{M})\, (\vec{x}_i + \Delta \vec{x}) \; }\]

where all pixels where \(\mathcal{M}(\vec{x}_i) = 1\) are ignored; all pixels for which \(\mathcal{M}(\vec{x}_i) = 0\) are considered as normal.

See also

  • T.W.J. de Geus, R.H.J. Peerlings, M.G.D. Geers (2015). Microstructural topology effects on the onset of ductile failure in multi-phase materials – A systematic computational approach. International Journal of Solids and Structures, 67–68, 326–339. doi: 10.1016/j.ijsolstr.2015.04.035, arXiv: 1604.02858

  • T.W.J. de Geus, C. Du, J.P.M. Hoefnagels, R.H.J. Peerlings, M.G.D. Geers (2016). Systematic and objective identification of the microstructure around damage directly from images.* Scripta Materialia, 113, 101–105. doi: 10.1016/j.scriptamat.2015.10.007, arXiv: 1604.03814

Note

The notation is short-hand for:

\[\mathcal{P} (\Delta \vec{x}) = \frac{ \sum_{i}\; \left[ \mathcal{W} (\vec{x}_i) \right] \; \left[ \mathcal{I}(\vec{x}_i + \Delta \vec{x}) (1-\mathcal{M})(\vec{x}_i + \Delta \vec{x}) \right] }{ \sum_{i}\; \left[ \mathcal{W} (\vec{x}_i) \right] \; \left[ 1-\mathcal{M}(\vec{x}_i + \Delta \vec{x}) \right] }\]

Example#

_images/W2.svg

Note

Like for the 2-point correlation, a mask can be used. Similarly, the average can be extended to that of an ensemble of images.

W2.py

import GooseEYE
import numpy as np
import prrng

# image + "damage" + correlation
# ------------------------------

# square grid of circles
N = 15
M = 500
row = np.linspace(0, M, N)
col = np.linspace(0, M, N)
row, col = np.meshgrid(row, col, indexing="ij")  # ('indexing' only for comparison with C++ code)
row = row.reshape(-1)
col = col.reshape(-1)
r = float(M) / float(N) / 4.0 * np.ones(N * N)

# random perturbation
rng = prrng.pcg32(0)
row += rng.normal(shape=[N * N], mu=0, sigma=M / N)
col += rng.normal(shape=[N * N], mu=0, sigma=M / N)
r *= rng.normal(shape=[N * N], mu=0, sigma=2) + 0.1

# generate image, extract 'volume-fraction' for plotting
img = GooseEYE.dummy_circles((M, M), np.round(row), np.round(col), np.round(r))
phi = np.mean(img)

# create 'damage' -> right of inclusion
col += 1.1 * r
r *= 0.4
W = GooseEYE.dummy_circles((M, M), np.round(row), np.round(col), np.round(r))
W[img == 1] = 0

# weighted correlation
WI = GooseEYE.W2((101, 101), W, img, fmask=W)

# gray-scale image + correlation
# ------------------------------

# convert to gray-scale image and introduce noise
Igr = np.array(img, copy=True).astype(float)
Igr += 0.1 * (2.0 * rng.random(Igr.shape) - 1.0) + 0.1
Igr /= 1.2

# mean intensity (for bounds)
Iav = np.mean(Igr)

# weighted correlation
WIgr = GooseEYE.W2((101, 101), W.astype(float), Igr, fmask=W)

Collapse to single point#

To calculate the probability of the inclusion directly next to a weight site (i.e. the red circles in the example above and below) the ‘collapsed correlation’ is calculated. The distance to the edge of the site, \(\vec{\delta}_i\) is therefore corrected for as follows:

\[\mathcal{P} (\Delta \vec{x}) = \frac{ \sum_{i}\; \mathcal{W} (\vec{x}_i) \; \mathcal{I} (\vec{x}_i + \Delta \vec{x} + \vec{\delta}_i) \; }{ \sum_{i}\; \mathcal{W} (\vec{x}_i) \; }\]

Similarly to the above, a mask may be introduced as follows:

\[\mathcal{P} (\Delta \vec{x}) = \frac{ \sum_{i}\; \mathcal{W} (\vec{x}_i) \; [ \mathcal{I} (1-\mathcal{M}) ] (\vec{x}_i + \Delta \vec{x} + \vec{\delta}_i) \; }{ \sum_{i}\; \mathcal{W} (\vec{x}_i) \; (1-\mathcal{M})\, (\vec{x}_i + \Delta \vec{x} + \vec{\delta}_i) \; }\]

See also

  • T.W.J. de Geus, C. Du, J.P.M. Hoefnagels, R.H.J. Peerlings, M.G.D. Geers (2016). Systematic and objective identification of the microstructure around damage directly from images.* Scripta Materialia, 113, 101–105. doi: 10.1016/j.scriptamat.2015.10.007, arXiv: 1604.03814

Example#

_images/W2c.svg

Note

Like for the 2-point correlation, a mask can be used. Similarly, the average can be extended to that of an ensemble of images.

W2c.py

import GooseEYE
import numpy as np
import prrng

# square grid of circles
N = 15
M = 500
row = np.linspace(0, M, N)
col = np.linspace(0, M, N)
row, col = np.meshgrid(row, col, indexing="ij")  # ('indexing' only for comparison with C++ code)
row = row.reshape(-1)
col = col.reshape(-1)
r = float(M) / float(N) / 4.0 * np.ones(N * N)

# random perturbation
rng = prrng.pcg32(0)
row += rng.normal([N * N], 0.0, float(M) / float(N))
col += rng.normal([N * N], 0.0, float(M) / float(N))
r *= rng.random([N * N]) * 2.0 + 0.1

# generate image, extract 'volume-fraction' for plotting
img = GooseEYE.dummy_circles((M, M), np.round(row), np.round(col), np.round(r))
phi = np.mean(img)

# create 'damage' -> right of inclusion
col += 1.1 * r
r *= 0.4
W = GooseEYE.dummy_circles((M, M), np.round(row), np.round(col), np.round(r))
W[img == 1] = 0

# compute individual damage clusters and their centers
labels = GooseEYE.clusters(W)
names = np.unique(labels)[1:]
cpos = GooseEYE.labels_centers(labels, names)
cpos = np.rint(cpos).astype(int)
cpos[:, 0] = np.clip(cpos[:, 0], 0, labels.shape[0] - 1)
cpos[:, 1] = np.clip(cpos[:, 1], 0, labels.shape[1] - 1)
index = np.ravel_multi_index(cpos.T, labels.shape)
centers = np.zeros_like(labels)
centers.flat[index] = names

# weighted correlation
WI = GooseEYE.W2((101, 101), W, img, fmask=W)

# collapsed weighted correlation
WIc = GooseEYE.W2c((101, 101), labels, centers, img, fmask=W)