Skip to content

Commit

Permalink
ENH: Add lung orientation.
Browse files Browse the repository at this point in the history
  • Loading branch information
ntustison committed Sep 25, 2023
1 parent 74b63f1 commit 8bc86ec
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 57 deletions.
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export(brainTumorSegmentation)
export(categorical_focal_gain)
export(categorical_focal_loss)
export(cerebellumMorphology)
export(checkXrayLungOrientation)
export(claustrumSegmentation)
export(convOutputLength)
export(convertCoordinates)
Expand Down
134 changes: 134 additions & 0 deletions R/chexnet.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#' Check x-ray lung orientation.
#'
#' Check the correctness of image orientation, i.e., flipped left-right, up-down,
#' or both. If True, attempts to correct before returning corrected image. Otherwise
#' it returns NULL.
#'
#' @param image input 3-D lung image.
#' @param antsxnetCacheDirectory destination directory for storing the downloaded
#' template and model weights. Since these can be resused, if
#' \code{is.null(antsxnetCacheDirectory)}, these data will be downloaded to the
#' subdirectory ~/.keras/ANTsXNet/.
#' @param verbose print progress.
#' @return segmentation and probability images
#' @author Tustison NJ
#' @examples
#' \dontrun{
#' library( ANTsRNet )
#' }
#' @import keras
#' @export
checkXrayLungOrientation <- function( image,
antsxnetCacheDirectory = NULL,
verbose = FALSE )
{
if( image@dimension != 2 )
{
stop( "ImageDimension must be equal to 2.")
}

resampledImageSize <- c( 224, 224 )
if( any( dim( image ) != resampledImageSize ) )
{
if( verbose )
{
cat( "Resampling image to ", resampledImageSize, "\n" )
}
resampledImage <- resampleImage( image, resampledImageSize, useVoxels = TRUE )
}
else
{
resampledImage <- antsImageClone( image )
}

model <- createResNetModel2D( c( resampledImageSize, 1 ),
numberOfClassificationLabels = 3,
mode = "classification",
layers = c( 1, 2, 3, 4 ),
residualBlockSchedule = c( 2, 2, 2, 2 ),
lowestResolution = 64,
cardinality = 1,
squeezeAndExcite = FALSE )

weightsFileName <- getPretrainedNetwork( "xrayLungOrientation",
antsxnetCacheDirectory = antsxnetCacheDirectory )
model$load_weights( weightsFileName )

imageMin <- min( resampledImage )
imageMax <- max( resampledImage )
normalizedImage <- antsImageClone( resampledImage )
normalizedImage <- ( normalizedImage - imageMin ) / ( imageMax - imageMin )

batchX <- array( data = as.array( normalizedImage ), dim = c( 1, resampledImageSize, 1 ) )
batchY <- model %>% predict( batchX, verbose = verbose )

# batchY is a 3-element array:
# batchY[0] = Pr(image is correctly oriented)
# batchY[1] = Pr(image is flipped up/down)
# batchY[2] = Pr(image is flipped left/right)

if( batchY[1, 1] > 0.5 )
{
return( NULL )
} else {
if( verbose )
{
message( "Possible incorrect orientation. Attempting to correct." )
}
normalizedImageArray <- as.array( normalizedImage )
imageUpDown <- as.antsImage( normalizedImageArray[,dim( normalizedImageArray )[2]:1],
origin = antsGetOrigin( resampledImage ),
spacing = antsGetSpacing( resampledImage ),
direction = antsGetDirection( resampledImage ) )
imageLeftRight <- as.antsImage( normalizedImageArray[dim( normalizedImageArray )[1]:1,],
origin = antsGetOrigin( resampledImage ),
spacing = antsGetSpacing( resampledImage ),
direction = antsGetDirection( resampledImage ) )
imageBoth <- as.antsImage( ( normalizedImageArray[,dim( normalizedImageArray )[2]:1] )[dim( normalizedImageArray )[1]:1,],
origin = antsGetOrigin( resampledImage ),
spacing = antsGetSpacing( resampledImage ),
direction = antsGetDirection( resampledImage ) )

batchX <- array( data = 0, dim = c( 3, resampledImageSize, 1 ) )
batchX[1,,,1] <- as.array( imageUpDown )
batchX[2,,,1] <- as.array( imageLeftRight )
batchX[3,,,1] <- as.array( imageBoth )

batchY <- model %>% predict( batchX, verbose = verbose )

imageArray <- as.array( image )
orientedImage <- NULL
if( batchY[1, 1] > batchY[2, 1] && batchY[1, 1] > batchY[3, 1] )
{
if( verbose )
{
message( "Image is flipped up-down." )
}
orientedImage <- as.antsImage( imageArray[,dim( imageArray )[2]:1],
origin = antsGetOrigin( image ),
spacing = antsGetSpacing( image ),
direction = antsGetDirection( image ) )
} else if( batchY[2, 1] > batchY[1, 1] && batchY[2, 1] > batchY[3, 1] ) {
if( verbose )
{
message( "Image is flipped right-left." )
}
orientedImage <- as.antsImage( imageArray[dim( imageArray )[1]:1,],
origin = antsGetOrigin( image ),
spacing = antsGetSpacing( image ),
direction = antsGetDirection( image ) )
} else {
if( verbose )
{
message( "Image is flipped up-down and right-left." )
}
orientedImage <- as.antsImage( ( imageArray[,dim( imageArray )[2]:1] )[dim( imageArray )[1]:1,],
origin = antsGetOrigin( image ),
spacing = antsGetSpacing( image ),
direction = antsGetDirection( image ) )
}

return( orientedImage )
}
}

5 changes: 3 additions & 2 deletions R/getPretrainedNetwork.R
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ getPretrainedNetwork <- function(
"xrayLungOrientation",
"xrayLungExtraction",
"chexnetClassification",
"wholeHeadInpaintingT1",
"chexnetANTsXNetClassification",
"wholeHeadInpaintingFLAIR",
"wholeHeadInpaintingPatchBasedT1",
"wholeHeadInpaintingPatchBasedFLAIR",
Expand Down Expand Up @@ -223,7 +223,8 @@ getPretrainedNetwork <- function(
tidsQualityAssessment = "https://figshare.com/ndownloader/files/35295391",
xrayLungOrientation = "https://figshare.com/ndownloader/files/41965821",
xrayLungExtraction = "https://figshare.com/ndownloader/files/41965818",
chexnetClassification = "",
chexnetClassification = "https://figshare.com/ndownloader/files/42423522",
chexnetANTsXNetClassification = "https://figshare.com/ndownloader/files/42428943",
wholeHeadInpaintingT1 = "https://figshare.com/ndownloader/files/39255422",
wholeHeadInpaintingFLAIR = "https://figshare.com/ndownloader/files/39255419",
wholeHeadInpaintingPatchBasedT1 = "https://figshare.com/ndownloader/files/39337442",
Expand Down
83 changes: 33 additions & 50 deletions docs/pkgdown.css
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,8 @@ img.icon {
float: right;
}

/* Ensure in-page images don't run outside their container */
.contents img {
img {
max-width: 100%;
height: auto;
}

/* Fix bug in bootstrap (only seen in firefox) */
Expand All @@ -80,26 +78,29 @@ dd {
/* Section anchors ---------------------------------*/

a.anchor {
display: none;
margin-left: 5px;
width: 20px;
height: 20px;
margin-left: -30px;
display:inline-block;
width: 30px;
height: 30px;
visibility: hidden;

background-image: url(./link.svg);
background-repeat: no-repeat;
background-size: 20px 20px;
background-position: center center;
}

h1:hover .anchor,
h2:hover .anchor,
h3:hover .anchor,
h4:hover .anchor,
h5:hover .anchor,
h6:hover .anchor {
display: inline-block;
.hasAnchor:hover a.anchor {
visibility: visible;
}

@media (max-width: 767px) {
.hasAnchor:hover a.anchor {
visibility: hidden;
}
}


/* Fixes for fixed navbar --------------------------*/

.contents h1, .contents h2, .contents h3, .contents h4 {
Expand Down Expand Up @@ -263,26 +264,31 @@ table {

/* Syntax highlighting ---------------------------------------------------- */

pre, code, pre code {
pre {
word-wrap: normal;
word-break: normal;
border: 1px solid #eee;
}

pre, code {
background-color: #f8f8f8;
color: #333;
}
pre, pre code {
white-space: pre-wrap;
word-break: break-all;
overflow-wrap: break-word;
}

pre {
border: 1px solid #eee;
pre code {
overflow: auto;
word-wrap: normal;
white-space: pre;
}

pre .img, pre .r-plt {
pre .img {
margin: 5px 0;
}

pre .img img, pre .r-plt img {
pre .img img {
background-color: #fff;
display: block;
height: auto;
}

code a, pre a {
Expand All @@ -299,8 +305,9 @@ a.sourceLine:hover {
.kw {color: #264D66;} /* keyword */
.co {color: #888888;} /* comment */

.error {font-weight: bolder;}
.warning {font-weight: bolder;}
.message { color: black; font-weight: bolder;}
.error { color: orange; font-weight: bolder;}
.warning { color: #6A0366; font-weight: bolder;}

/* Clipboard --------------------------*/

Expand Down Expand Up @@ -358,27 +365,3 @@ mark {
content: "";
}
}

/* Section anchors ---------------------------------
Added in pandoc 2.11: https://github.com/jgm/pandoc-templates/commit/9904bf71
*/

div.csl-bib-body { }
div.csl-entry {
clear: both;
}
.hanging-indent div.csl-entry {
margin-left:2em;
text-indent:-2em;
}
div.csl-left-margin {
min-width:2em;
float:left;
}
div.csl-right-inline {
margin-left:2em;
padding-left:1em;
}
div.csl-indent {
margin-left: 2em;
}
4 changes: 2 additions & 2 deletions docs/pkgdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
$(document).ready(function() {
var copyButton = "<button type='button' class='btn btn-primary btn-copy-ex' type = 'submit' title='Copy to clipboard' aria-label='Copy to clipboard' data-toggle='tooltip' data-placement='left auto' data-trigger='hover' data-clipboard-copy><i class='fa fa-copy'></i></button>";

$("div.sourceCode").addClass("hasCopyButton");
$(".examples, div.sourceCode").addClass("hasCopyButton");

// Insert copy buttons:
$(copyButton).prependTo(".hasCopyButton");
Expand All @@ -91,7 +91,7 @@
// Initialize clipboard:
var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', {
text: function(trigger) {
return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, "");
return trigger.parentNode.textContent;
}
});

Expand Down
4 changes: 2 additions & 2 deletions docs/pkgdown.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pandoc: '0'
pkgdown: 2.0.6
pkgdown: 1.6.1
pkgdown_sha: ~
articles: {}
last_built: 2023-09-09T00:57Z
last_built: 2023-09-25T22:03Z

34 changes: 34 additions & 0 deletions man/checkXrayLungOrientation.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/getPretrainedNetwork.Rd

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

0 comments on commit 8bc86ec

Please sign in to comment.