<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Generator" content="Microsoft Word 14 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri","sans-serif";}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-priority:99;
color:purple;
text-decoration:underline;}
span.E-MailFormatvorlage17
{mso-style-type:personal-compose;
font-family:"Calibri","sans-serif";
color:windowtext;}
.MsoChpDefault
{mso-style-type:export-only;
font-family:"Calibri","sans-serif";}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-US" link="blue" vlink="purple">
<div class="WordSection1">
<p class="MsoNormal">Hello everyone,<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I tried to use the GPUDemonsRegistrationFilter for image registration, but experienced some problems when trying to perform multiple registrations in a row. As far as I can tell, there seems to be a memory leak caused by the registration.
After a few registrations, depending on the image size, I get an OpenCL Error : CL_MEM_OBJECT_ALLOCATION_FAILURE.<o:p></o:p></p>
<p class="MsoNormal">Using nvidia-smi confirms that more and more GPU memory is allocated with each run.<o:p></o:p></p>
<p class="MsoNormal">Using the ITK debug output, I noticed that the GPUImages aren’t destroyed at the end of the function, because they still have a reference count, while all the other objects are destroyed.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I was able to reproduce this error with the following code (mainly copied from the example):<o:p></o:p></p>
<p class="MsoNormal">#include "itkGPUDemonsRegistrationFilter.h"<o:p></o:p></p>
<p class="MsoNormal">#include "itkHistogramMatchingImageFilter.h"<o:p></o:p></p>
<p class="MsoNormal">#include "itkCastImageFilter.h"<o:p></o:p></p>
<p class="MsoNormal">#include "itkWarpImageFilter.h"<o:p></o:p></p>
<p class="MsoNormal">#include "itkLinearInterpolateImageFunction.h"<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">#include "itkImportImageFilter.h"<o:p></o:p></p>
<p class="MsoNormal">#include "itkImageFileReader.h"<o:p></o:p></p>
<p class="MsoNormal">#include "itkImageFileWriter.h"<o:p></o:p></p>
<p class="MsoNormal">#include "itkCommand.h"<o:p></o:p></p>
<p class="MsoNormal">#include "itkSmartPointer.h"<o:p></o:p></p>
<p class="MsoNormal">#include "itkTimeProbe.h"<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">#include "itkGPUImage.h"<o:p></o:p></p>
<p class="MsoNormal">#include "itkGPUKernelManager.h"<o:p></o:p></p>
<p class="MsoNormal">#include "itkGPUContextManager.h"<o:p></o:p></p>
<p class="MsoNormal">#include "itkGPUDemonsRegistrationFilter.h"<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">void DIF(){<o:p></o:p></p>
<p class="MsoNormal"> bool debug = false;<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> //Fill some arrays with bogus<o:p></o:p></p>
<p class="MsoNormal"> const unsigned int Dimension = 3;<o:p></o:p></p>
<p class="MsoNormal"> typedef float PixelType;<o:p></o:p></p>
<p class="MsoNormal"> unsigned int width = 100;<o:p></o:p></p>
<p class="MsoNormal"> unsigned int height = 100;<o:p></o:p></p>
<p class="MsoNormal"> unsigned int slices = 10;<o:p></o:p></p>
<p class="MsoNormal"> unsigned int nump = width * height * slices;<o:p></o:p></p>
<p class="MsoNormal"> PixelType *FixedImageArray = new PixelType[nump];<o:p></o:p></p>
<p class="MsoNormal"> PixelType *MovingImageArray = new PixelType[nump];<o:p></o:p></p>
<p class="MsoNormal"> for (unsigned int i = 0; i < nump;++i){<o:p></o:p></p>
<p class="MsoNormal"> FixedImageArray[i] = i % 5;<o:p></o:p></p>
<p class="MsoNormal"> MovingImageArray[i] = i % 6;<o:p></o:p></p>
<p class="MsoNormal"> }<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> //Import those arrays as images<o:p></o:p></p>
<p class="MsoNormal"> typedef itk::Image< PixelType, Dimension > FixedImageType;<o:p></o:p></p>
<p class="MsoNormal"> typedef itk::Image< PixelType, Dimension > MovingImageType;<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> typedef itk::ImportImageFilter<PixelType, Dimension> FixedImportFilterType;<o:p></o:p></p>
<p class="MsoNormal"> typedef itk::ImportImageFilter<PixelType, Dimension> MovingImportFilterType;<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> FixedImportFilterType::Pointer FixedImportFilter = FixedImportFilterType::New();<o:p></o:p></p>
<p class="MsoNormal"> if (debug) FixedImportFilter->DebugOn();<o:p></o:p></p>
<p class="MsoNormal"> MovingImportFilterType::Pointer MovingImportFilter = MovingImportFilterType::New();<o:p></o:p></p>
<p class="MsoNormal"> if (debug) MovingImportFilter->DebugOn();<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> FixedImportFilterType::IndexType start;<o:p></o:p></p>
<p class="MsoNormal"> start[0] = 0;<o:p></o:p></p>
<p class="MsoNormal"> start[1] = 0;<o:p></o:p></p>
<p class="MsoNormal"> start[2] = 0;<o:p></o:p></p>
<p class="MsoNormal"> FixedImportFilterType::SizeType size;<o:p></o:p></p>
<p class="MsoNormal"> size[0] = width;<o:p></o:p></p>
<p class="MsoNormal"> size[1] = height;<o:p></o:p></p>
<p class="MsoNormal"> size[2] = slices;<o:p></o:p></p>
<p class="MsoNormal"> FixedImportFilterType::RegionType region;<o:p></o:p></p>
<p class="MsoNormal"> region.SetSize(size);<o:p></o:p></p>
<p class="MsoNormal"> region.SetIndex(start);<o:p></o:p></p>
<p class="MsoNormal"> FixedImportFilter->SetRegion(region);<o:p></o:p></p>
<p class="MsoNormal"> double origin[3];<o:p></o:p></p>
<p class="MsoNormal"> origin[0] = 0.0;<o:p></o:p></p>
<p class="MsoNormal"> origin[1] = 0.0;<o:p></o:p></p>
<p class="MsoNormal"> origin[2] = 0.0;<o:p></o:p></p>
<p class="MsoNormal"> FixedImportFilter->SetOrigin(origin);<o:p></o:p></p>
<p class="MsoNormal"> double spacing[3];<o:p></o:p></p>
<p class="MsoNormal"> spacing[0] = 1;<o:p></o:p></p>
<p class="MsoNormal"> spacing[1] = 1;<o:p></o:p></p>
<p class="MsoNormal"> spacing[2] = 1;<o:p></o:p></p>
<p class="MsoNormal"> FixedImportFilter->SetSpacing(spacing);<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> MovingImportFilter->SetRegion(region);<o:p></o:p></p>
<p class="MsoNormal"> MovingImportFilter->SetOrigin(origin);<o:p></o:p></p>
<p class="MsoNormal"> MovingImportFilter->SetSpacing(spacing);<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> FixedImportFilter->SetImportPointer(FixedImageArray, width * height * slices, true);<o:p></o:p></p>
<p class="MsoNormal"> MovingImportFilter->SetImportPointer(MovingImageArray, width * height * slices, true);<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> FixedImageType::Pointer FixedImage = FixedImportFilter->GetOutput();<o:p></o:p></p>
<p class="MsoNormal"> if (debug) FixedImage->DebugOn();<o:p></o:p></p>
<p class="MsoNormal"> MovingImageType::Pointer MovingImage = MovingImportFilter->GetOutput();<o:p></o:p></p>
<p class="MsoNormal"> if (debug) MovingImage->DebugOn();<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> //convert to GPUImages<o:p></o:p></p>
<p class="MsoNormal"> typedef float InternalPixelType;<o:p></o:p></p>
<p class="MsoNormal"> typedef itk::GPUImage< InternalPixelType, Dimension > InternalImageType;<o:p></o:p></p>
<p class="MsoNormal"> typedef itk::CastImageFilter< FixedImageType,<o:p></o:p></p>
<p class="MsoNormal"> InternalImageType > FixedImageCasterType;<o:p></o:p></p>
<p class="MsoNormal"> typedef itk::CastImageFilter< MovingImageType,<o:p></o:p></p>
<p class="MsoNormal"> InternalImageType > MovingImageCasterType;<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> FixedImageCasterType::Pointer fixedImageCaster = FixedImageCasterType::New();<o:p></o:p></p>
<p class="MsoNormal"> if (debug) fixedImageCaster->DebugOn();<o:p></o:p></p>
<p class="MsoNormal"> MovingImageCasterType::Pointer movingImageCaster = MovingImageCasterType::New();<o:p></o:p></p>
<p class="MsoNormal"> if (debug) movingImageCaster->DebugOn();<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> fixedImageCaster->SetInput(FixedImportFilter->GetOutput());<o:p></o:p></p>
<p class="MsoNormal"> movingImageCaster->SetInput(MovingImportFilter->GetOutput());<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> InternalImageType::Pointer GPUFixedImage = fixedImageCaster->GetOutput();<o:p></o:p></p>
<p class="MsoNormal"> if (debug) GPUFixedImage->DebugOn();<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> InternalImageType::Pointer GPUMovingImage = movingImageCaster->GetOutput();<o:p></o:p></p>
<p class="MsoNormal"> if (debug) GPUMovingImage->DebugOn();<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> GPUFixedImage->Update();<o:p></o:p></p>
<p class="MsoNormal"> GPUMovingImage->Update();<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> //Perform GPU Demons Registration<o:p></o:p></p>
<p class="MsoNormal"> typedef itk::Vector< float, Dimension > VectorPixelType;<o:p></o:p></p>
<p class="MsoNormal"> typedef itk::GPUImage< VectorPixelType, Dimension > DeformationFieldType;<o:p></o:p></p>
<p class="MsoNormal"> typedef itk::GPUDemonsRegistrationFilter<<o:p></o:p></p>
<p class="MsoNormal"> InternalImageType,<o:p></o:p></p>
<p class="MsoNormal"> InternalImageType,<o:p></o:p></p>
<p class="MsoNormal"> DeformationFieldType> RegistrationFilterType;<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> RegistrationFilterType::Pointer filter = RegistrationFilterType::New();<o:p></o:p></p>
<p class="MsoNormal"> if (debug) filter->DebugOn();<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> filter->SetFixedImage( GPUFixedImage );<o:p></o:p></p>
<p class="MsoNormal"> filter->SetMovingImage( GPUMovingImage );<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> filter->SetNumberOfIterations( 1 );<o:p></o:p></p>
<p class="MsoNormal"> filter->SetStandardDeviations( 1.0 );<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal"> filter->Update();<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">int main(int argc, char **argv){<o:p></o:p></p>
<p class="MsoNormal"> unsigned int numiter = 100000;<o:p></o:p></p>
<p class="MsoNormal"> for (unsigned int i = 0; i < numiter; ++i){<o:p></o:p></p>
<p class="MsoNormal"> DIF();<o:p></o:p></p>
<p class="MsoNormal"> std::cout << "ITERATION: " << i << std::endl;<o:p></o:p></p>
<p class="MsoNormal"> }<o:p></o:p></p>
<p class="MsoNormal">}<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">I am using a GeForce GTS 450 with driver version 319.37 under OpenSUSE 12.2 with ITK 4.4.2.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Thank you for your help.<o:p></o:p></p>
<p class="MsoNormal">Kind regards,<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">Stephan<o:p></o:p></p>
</div>
</body>
</html>