Skip to content

Commit

Permalink
Merge pull request #398 from ANTsX/NyulBspline
Browse files Browse the repository at this point in the history
ENH:  histogram matching Nyul/bspline variant w/ masking.
  • Loading branch information
ntustison authored Apr 13, 2024
2 parents 11d1799 + ca6c340 commit e40ee39
Show file tree
Hide file tree
Showing 19 changed files with 194 additions and 44 deletions.
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ export(hausdorffDistance)
export(hemodynamicRF)
export(histogramEqualizeImage)
export(histogramMatchImage)
export(histogramMatchImage2)
export(iBind)
export(iMath)
export(icawhiten)
Expand Down
96 changes: 96 additions & 0 deletions R/histogramMatchImage.R
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,99 @@ histogramMatchImage <- function(
)
return(outputImage)
}


#' Transform image intensities based on histogram mapping.
#'
#' Apply B-spline 1-D maps to an input image for intensity warping.
#'
#' @param sourceImage source image.
#' @param referenceImage reference image.
#' @param sourceMask source mask.
#' @param referenceMask reference mask.
#' @param matchPoints parametric points at which the intensity transform
#' displacements are specified between [0, 1]. Alternatively, a single
#' number can be given and the sequence is linearly spaced in [0, 1].
#' @param transformDomainSize Defines the sampling resolution of the B-spline warping.
#' @return warped intensity image
#' @author Tustison NJ
#' @examples
#'
#' library( ANTsR )
#' sourceImage <- antsImageRead(getANTsRData("r16"), 2)
#' referenceImage <- antsImageRead(getANTsRData("r64"), 2)
#' matchedImage <- histogramMatchImage2(sourceImage, referenceImage)
#' @export histogramMatchImage2
histogramMatchImage2 <- function( sourceImage, referenceImage,
sourceMask = NULL, referenceMask = NULL,
matchPoints = 64,
transformDomainSize = 255 )
{


if( length( matchPoints ) > 1 )
{
if( any( matchPoints < 0.0 ) || any( matchPoints > 1.0 ) )
{
stop( "If specifying matchPoints as a vector, values must be in the range [0, 1]." )
}
}

# Use entire image if mask isn't specified.
if( is.null( sourceMask ) )
{
sourceMask <- sourceImage * 0 + 1
}
if( is.null( referenceMask ) )
{
referenceMask <- referenceImage * 0 + 1
}

sourceArray <- as.array( sourceImage )
sourceMaskArray <- as.array( sourceMask )
sourceMaskedMin <- min( sourceArray[sourceMaskArray != 0] )
sourceMaskedMax <- max( sourceArray[sourceMaskArray != 0] )

referenceArray <- as.array( referenceImage )
referenceMaskArray <- as.array( referenceMask )

parametricPoints <- NULL
if( length( matchPoints ) > 1 )
{
parametricPoints <- matchPoints
} else {
parametricPoints <- seq( 0, 1, length.out = matchPoints )
}

sourceIntensityQuantiles <- quantile( sourceArray[sourceMaskArray != 0], probs = parametricPoints )
referenceIntensityQuantiles <- quantile( referenceArray[referenceMaskArray != 0], probs = parametricPoints )
displacements <- referenceIntensityQuantiles - sourceIntensityQuantiles

scatteredData <- matrix( displacements )
parametricData <- matrix( parametricPoints ) * ( sourceMaskedMax - sourceMaskedMin + sourceMaskedMin )

transformDomainOrigin <- sourceMaskedMin
transformDomainSpacing <- ( sourceMaskedMax - transformDomainOrigin ) / ( transformDomainSize - 1 )

bsplineHistogramTransform <- fitBsplineObjectToScatteredData( scatteredData, parametricData,
c( transformDomainOrigin ), c( transformDomainSpacing ), c( transformDomainSize ),
dataWeights = NULL, isParametricDimensionClosed = NULL, numberOfFittingLevels = 8,
meshSize = 1, splineOrder = 3 )

transformDomain <- seq( sourceMaskedMin, sourceMaskedMax, length.out = transformDomainSize )

transformedSourceArray <- as.array( sourceImage )
for( i in seq.int( length( transformDomain ) - 1 ) )
{
indices <- which( sourceArray >= transformDomain[i] & sourceArray < transformDomain[i+1] )
intensities <- sourceArray[indices]

alpha <- ( intensities - transformDomain[i] ) / ( transformDomain[i+1] - transformDomain[i] )
xfrm <- alpha * ( bsplineHistogramTransform[i+1, 1] - bsplineHistogramTransform[i, 1] ) + bsplineHistogramTransform[i, 1]
transformedSourceArray[indices] <- intensities + xfrm
}
transformedSourceImage <- as.antsImage( transformedSourceArray, reference = image )
transformedSourceImage[sourceMask == 0] <- sourceImage[sourceMask == 0]

return( transformedSourceImage )
}
4 changes: 3 additions & 1 deletion man/antsRegistration.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 27 additions & 27 deletions man/brackets.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/eanatDef.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/fitTimeVaryingTransformToPointSets.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions man/fitTransformToPairedPoints.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions man/histogramMatchImage2.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion man/image2ClusterImages.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/jointSmoothMatrixReconstruction.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/labelClusters.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/mild.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/milr.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/n3BiasFieldCorrection2.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/n4BiasFieldCorrection.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions man/simlr.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/smoothMatrixPrediction.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/sparseDistanceMatrix.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit e40ee39

Please sign in to comment.