Vous avez reçu un message "Your GitLab account has been locked ..." ? Pas d'inquiétude : lisez cet article https://docs.gricad-pages.univ-grenoble-alpes.fr/help/unlock/

Commit 8846432d authored by Edward Andò's avatar Edward Andò
Browse files

Resolves #178 -- mask coverage implemented correctly inn grid()

parent 847e927e
Pipeline #49353 passed with stages
in 23 minutes and 25 seconds
......@@ -102,11 +102,10 @@ if mpiRank == boss or not mpi:
else:
im1mask = None
# Automatically set the mimnum mask volume per correlation window as 50% occupancy
MIN_VX = minSubVolume = int(((1+min(args.HWS)*2)**3) * 0.5)
firstCorrelation = True
# Loop over input images
for im2number in range(1, len(args.inFiles)):
# Variables to track last correlation in order to ask MPI workers to hang up
......@@ -136,10 +135,6 @@ if mpiRank == boss or not mpi:
im2 = im2[numpy.newaxis, ...]
nodePositions, nodesDim = spam.DIC.grid.makeGrid(im1.shape, args.NS)
#print(nodesDim)
# HACK -- a gigantic one
#nodePositions =numpy.array([[280,150,115]])/2
#nodesDim = numpy.array([[1,1,1]])
# Initialise field of Fs with the identity matrix
PhiField = numpy.zeros((nodePositions.shape[0], 4, 4))
......@@ -339,6 +334,7 @@ if mpiRank == boss or not mpi:
maxIterations=args.GRID_POINT_MAX_ITERATIONS,
deltaPhiMin=args.GRID_POINT_MIN_PHI_CHANGE,
im1mask=im1mask,
minMaskCoverage = args.GRID_POINT_MASK_COVERAGE,
interpolationOrder=args.GRID_POINT_INTERPOLATION_ORDER,
greyThreshold=[args.GREY_LOW_THRESH, args.GREY_HIGH_THRESH],
mpi=mpi)
......
......@@ -422,7 +422,7 @@ class TestFunctionDVC(unittest.TestCase):
searchRange={"zRange": [0, 0], "yRange": [-3, 3], "xRange": [-3, 3]},
im1mask=numpy.ones_like(im),
PhiField=numpy.zeros((nodePositions.shape[0], 4, 4)),
minSubVolume=0.5,
minMaskCoverage=0.5,
greyThreshold=[-numpy.inf, numpy.inf])
self.assertEqual(ps2["PhiField"][:, 0, -1].sum(), 0)
......@@ -446,7 +446,7 @@ class TestFunctionDVC(unittest.TestCase):
maxIterations=100,
deltaPhiMin=0.001,
interpolationOrder=1,
minSubVolume=0.5, im1mask=numpy.ones_like(im),
minMaskCoverage=0.5, im1mask=numpy.ones_like(im),
greyThreshold=[-numpy.inf, numpy.inf])
self.assertEqual(subPix["PhiField"][:, 0, -1].sum(), 0)
......
......@@ -86,7 +86,7 @@ def makeGrid(imageSize, nodeSpacing):
return nodePositions, nodesDim
def pixelSearchOnGrid(im1, im2, nodePositions, halfWindowSize, searchRange, PhiField=None, minSubVolume=None, im1mask=None, greyThreshold=[-numpy.inf, numpy.inf], mpi=False):
def pixelSearchOnGrid(im1, im2, nodePositions, halfWindowSize, searchRange, PhiField=None, minMaskCoverage=0.5, im1mask=None, greyThreshold=[-numpy.inf, numpy.inf], mpi=False):
"""
This function handles grid-based local correlation, offering an initial rough dispalcement-only guess.
At the moment matching of windows is done with a Normalised-Correlation-Coefficient approach.
......@@ -117,10 +117,9 @@ def pixelSearchOnGrid(im1, im2, nodePositions, halfWindowSize, searchRange, PhiF
Currently, only the translational components of F will be taken into account.
Default = No displacement
minSubVolume : int, optional
minMaskCoverage : float, optional
Minimum number of pixels in a subvolume for it to be correlated (only considered in the case of im1mask).
Expressed as a % of subvolume volume.
Default = 50% of subvolume
Default = 0.5
im1mask : 3D boolean numpy array, optional
A mask for im1 which is true in the zones to correlate.
......@@ -146,7 +145,7 @@ def pixelSearchOnGrid(im1, im2, nodePositions, halfWindowSize, searchRange, PhiF
For each node, the NCC score obtained
"""
def getImagettes(nodeNumber, nodePositions, PhiField, searchRange, halfWindowSize, im1, im2, minSubVolume, greyThreshold):
def getImagettes(nodeNumber, nodePositions, PhiField, searchRange, halfWindowSize, im1, im2, minMaskVolume, greyThreshold):
returnStatus = 2
initialDisplacement = PhiField[nodeNumber, 0:3, 3].astype(int)
......@@ -174,7 +173,7 @@ def pixelSearchOnGrid(im1, im2, nodePositions, halfWindowSize, searchRange, PhiF
# Make sure imagette is not 0-dimensional in any dimension
if numpy.all(numpy.array(imagette1.shape) > 0):
if numpy.nanmean(imagette1) > greyThreshold[0] and numpy.nanmean(imagette1) < greyThreshold[1] and len(imagette1.ravel()) > minSubVolume:
if numpy.nanmean(imagette1) > greyThreshold[0] and numpy.nanmean(imagette1) < greyThreshold[1] and len(imagette1.ravel()) > minMaskVolume:
# Slice for image 2
# TODO: Check we extraced what we asked for -- could put displacements off at the boundaries
# could even give a bad return status for this condition...
......@@ -187,7 +186,7 @@ def pixelSearchOnGrid(im1, im2, nodePositions, halfWindowSize, searchRange, PhiF
# Extract it...
imagette2 = im2[subVolSlice2]
# Failed minSubVolume or greylevel condition
# Failed minMaskVolume or greylevel condition
else:
returnStatus = -5
imagette1 = None
......@@ -229,11 +228,10 @@ def pixelSearchOnGrid(im1, im2, nodePositions, halfWindowSize, searchRange, PhiF
if type(halfWindowSize) == int or type(halfWindowSize) == float:
halfWindowSize = [halfWindowSize] * 3
# Check minSubVolume
if minSubVolume is None:
minSubVolume = int(((1 + min(halfWindowSize) * 2)**3) * 0.5)
else:
minSubVolume = int(((1 + min(halfWindowSize) * 2)**3) * minSubVolume)
# Check minMaskVolume
minMaskVolume = int(minMaskCoverage * (1+halfWindowSize[0]*2)*
(1+halfWindowSize[1]*2)*
(1+halfWindowSize[2]*2))
# Check F field
if PhiField is None:
......@@ -264,7 +262,7 @@ def pixelSearchOnGrid(im1, im2, nodePositions, halfWindowSize, searchRange, PhiF
# Get the next node off the queue
nodeNumber = q.get()
imagetteReturns = getImagettes(nodeNumber, nodePositions, PhiField, searchRange, halfWindowSize, im1, im2, minSubVolume, greyThreshold)
imagetteReturns = getImagettes(nodeNumber, nodePositions, PhiField, searchRange, halfWindowSize, im1, im2, minMaskVolume, greyThreshold)
if imagetteReturns['returnStatus'] == 2:
if mpi:
......@@ -333,7 +331,7 @@ def pixelSearchOnGrid(im1, im2, nodePositions, halfWindowSize, searchRange, PhiF
'pixelSearchCC': pixelSearchCC}
def registerOnGrid(im1, im2, nodePositions, halfWindowSize, PhiField=None, margin=None, maxIterations=None, deltaPhiMin=None, interpolationOrder=None, minSubVolume=None, im1mask=None, greyThreshold=[-numpy.inf, numpy.inf], mpi=False, killWorkersWhenDone=True):
def registerOnGrid(im1, im2, nodePositions, halfWindowSize, PhiField=None, margin=None, maxIterations=None, deltaPhiMin=None, interpolationOrder=None, minMaskCoverage=None, im1mask=None, greyThreshold=[-numpy.inf, numpy.inf], mpi=False, killWorkersWhenDone=True):
"""
This function handles grid-based local correlation, performing a "register" subpixel refinement.
Here we minimise a residual which is the difference between im1 and im2.
......@@ -354,33 +352,34 @@ def registerOnGrid(im1, im2, nodePositions, halfWindowSize, PhiField=None, margi
The subvolume will be 2*halfWindowSize + 1 pixels on each side.
A general recommendation is to make this half the node spacing
PhiField : nPoints*4*4 numpy array, optional (default = No displacement)
Optional field of ``F`` transformation operators defined for each node
PhiField : nPoints*4*4 numpy array, optional
Optional field of Phi deformation functions defined for each node
Default = None
margin : int or list, optional (default = None (use ``register``'s default))
margin : int or list, optional
Margin to extract for subpixel interpolation
Default = None (use ``register``'s default)
maxIterations : int, optional (default = None (use ``register``'s default))
Number of iterations for subpixel refinement
deltaPhiMin : float, optional (default = None (use ``register``'s default))
deltaPhiMin : float, optional
Stop iterating when norm of F gets below this value
Default = None (use ``register``'s default)
interpolationOrder : int, optional (default = None (use ``register``'s default))
interpolationOrder : int, optional
Greyscale interpolation order
Default = None (use ``register``'s default)
minSubVolume : int, optional (default = 50% of subvolume)
minMaskCoverage : float, optional
Minimum number of pixels in a subvolume for it to be correlated (only considered in the case of im1mask).
Expressed as a % of subvolume volume
Default = 0.5
im1mask : 3D boolean numpy array, optional (default = None)
im1mask : 3D boolean numpy array, optional
A mask for the whole of im1 which is true in the zones to correlate.
This is NOT used to mask the image, but to detect subvolumes that
Fall inside the mask (see minSubVolume for proportion)
im2mask : 3D boolean numpy array, optional (default = None)
A mask for the whole of im2 which is true in the zones to correlate.
This is IS used to mask the image, in LucasKanade
Fall inside the mask (see minMaskVolume for proportion)
Default = None
greyThreshold : list of two floats, optional
Threshold for the mean greylevel in each im1 subvolume.
......@@ -426,7 +425,7 @@ def registerOnGrid(im1, im2, nodePositions, halfWindowSize, PhiField=None, margi
numberOfNodes = nodePositions.shape[0]
def getImagettes(nodeNumber, im1, im2, PhiField, nodePositions, margin, halfWindowSize, greyThreshold, im1mask):
def getImagettes(nodeNumber, im1, im2, PhiField, nodePositions, margin, halfWindowSize, greyThreshold, im1mask, minMaskVolume):
# Initialise defaults
imagette1mask = None
PhiInit = None
......@@ -447,7 +446,7 @@ def registerOnGrid(im1, im2, nodePositions, halfWindowSize, PhiField=None, margi
# Check Mask volume condition
if im1mask is not None:
imagette1mask = im1mask[subVolSlice1]
maskVolCondition = imagette1mask.sum() > minSubVolume
maskVolCondition = imagette1mask.sum() > minMaskVolume
else:
maskVolCondition = True
......@@ -525,11 +524,10 @@ def registerOnGrid(im1, im2, nodePositions, halfWindowSize, PhiField=None, margi
if type(halfWindowSize) == int or type(halfWindowSize) == float:
halfWindowSize = [halfWindowSize] * 3
# Check minSubVolume
if minSubVolume is None:
minSubVolume = int(((1 + min(halfWindowSize) * 2)**3) * 0.5)
else:
minSubVolume = int(((1 + min(halfWindowSize) * 2)**3) * minSubVolume)
# Check minMaskVolume
minMaskVolume = int(minMaskCoverage * (1+halfWindowSize[0]*2)*
(1+halfWindowSize[1]*2)*
(1+halfWindowSize[2]*2))
# Check F field
if PhiField is None:
......@@ -562,7 +560,7 @@ def registerOnGrid(im1, im2, nodePositions, halfWindowSize, PhiField=None, margi
# Get the next node off the queue
nodeNumber = q.get()
imagetteReturns = getImagettes(nodeNumber, im1, im2, PhiField, nodePositions, margin, halfWindowSize, greyThreshold, im1mask)
imagetteReturns = getImagettes(nodeNumber, im1, im2, PhiField, nodePositions, margin, halfWindowSize, greyThreshold, im1mask, minMaskVolume)
if imagetteReturns['returnStatus'] == 2:
if mpi:
......
......@@ -221,6 +221,13 @@ def ldicParser(parser):
dest='GRID_POINT_INTERPOLATION_ORDER',
help="Interpolation order for grid-point registration. Default = 1")
parser.add_argument('-gpmc',
'--grid-point-mask-coverage',
type=float,
default=0.5,
dest='GRID_POINT_MASK_COVERAGE',
help="In case a mask is defined, tolerance for a subvolume's pixels to be masked before it is skipped with RS=-5. Default = 0.5")
parser.add_argument('-sef',
'--series-Ffile',
action="store_true",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment