Source code for spam.measurements.porosityField
# Library of SPAM functions for measuring a porosity field
# Copyright (C) 2020 SPAM Contributors
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
import matplotlib.pyplot as plt
import numpy
import spam.DIC.grid as grid
from spam.measurements.measurementsToolkit import (
porosityFieldBinary as porosityFieldBinaryCPP,
)
[docs]
def porosityField(
image,
poreValue=None,
solidValue=None,
maskValue=None,
nodeSpacing="auto",
hws=10,
showGraph=False,
):
"""
This function calculates a porosity field on a greyscale image, outputting a field in % porosity.
A list of half-window sizes can be given, allowing for porosity measurement stability to to evaluate easily.
Parameters
----------
image : 3D numpy array
poreValue : float
The grey value corresponding to the peak of the pores.
Grey values of this value as considered 100% pore.
In the case of 2 peaks in the pores (having water and air), should put the principal one.
solidValue : float
The grey value corresponding to the peak of the solids.
Grey values of this value as considered 100% solid.
maskValue : float, optional
Indicate whether there is a special value in the input image
that corrseponds to a mask which indicates voxels that are not taken
into account in the porosity calculation.
Default = None
hws : int or list, optional
half-window size for cubic measurement window
Default = 10
nodeSpacing : int, optional
spacing of nodes in pixels
Default = 10 pixels
showGraph : bool, optional
If a list of hws is input, show a graph of the porosity evolution
Default = False
Returns
-------
3D (or 4D) numpy array for constant half-window size (list of half-window sizes)
"""
# The C function for porosity needs an 8-bit image with greyvalues
if poreValue is None or solidValue is None:
print(
"spam.measurements.porosityField(): Need to give me the greyvalue of the pores and solids"
)
return
if poreValue == solidValue:
print(
"spam.measurements.porosityField(): Need to give me the correct greyvalue of the pores and solids, where greyvalue of pores always smaller than that of solids"
)
return
imPorosity = numpy.zeros_like(image, dtype="<u1")
# Rescale image to imPorosity between poreValue and solidValue, !
if poreValue < solidValue:
imPorosity[image > poreValue] = (
numpy.true_divide(100, solidValue - poreValue)
) * (solidValue - image[image > poreValue])
imPorosity[image <= poreValue] = 100
imPorosity[image >= solidValue] = 0
if poreValue > solidValue:
imPorosity[image > solidValue] = (
numpy.true_divide(100, poreValue - solidValue)
) * (poreValue - image[image > solidValue])
imPorosity[image <= solidValue] = 100
imPorosity[image >= poreValue] = 0
# If a mask value is given, apply it
if maskValue is not None:
imPorosity[image == maskValue] = 255
if nodeSpacing == "auto":
nodeSpacing = min(image.shape) / 2
# if hws == "auto": 10
if type(hws) == int:
hws = [hws]
points, layout = grid.makeGrid(imPorosity.shape, nodeSpacing)
pointsArray = []
hwsArray = []
for p in points:
for i in hws:
pointsArray.append(p)
hwsArray.append(i)
pointsArray = numpy.array(pointsArray).astype("<i4")
hwsArray = numpy.array(hwsArray).astype("<i4")
porosities = numpy.zeros_like(hwsArray, dtype="<f4")
# call C function on scaled 8 bit image
porosityFieldBinaryCPP(imPorosity, pointsArray, hwsArray, porosities)
if len(hws) == 1:
porosities = porosities.reshape((layout[0], layout[1], layout[2]))
else:
porosities = porosities.reshape((layout[0], layout[1], layout[2], len(hws)))
if showGraph is True:
for z in range(porosities.shape[0]):
for y in range(porosities.shape[1]):
for x in range(porosities.shape[2]):
plt.plot(hws, porosities[z, y, x, :])
plt.xlabel("Half-window size")
plt.ylabel("Porosity (%)")
plt.show()
return porosities