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 d724e380 authored by cfouard's avatar cfouard
Browse files

FIXED Numerous vtk smart pointers were badly handled causing vicious memory leaks.

TODO The code convention has to be completed quickly and followed by the letter concerning vtk smart pointers ! Any vtkImageData * or vtkAnyFilter * causes memory bleed.

FIXED Disconnected vtk to itk pipeline for images created by itk actions to live their lives independently from the input image (had to be fixed in the Kitware bridge between vtk and itk).

git-svn-id: svn+ssh://scm.forge.imag.fr/var/lib/gforge/chroot/scmrepos/svn/camitk/trunk/camitk@2036 ec899d31-69d1-42ba-9299-647d76f65fb3
parent 7025aaf1
......@@ -47,8 +47,8 @@ ManualThreshold::ManualThreshold(ActionExtension * extension) : Action(extension
setName("Manual Threshold Filter");
setDescription("<br/>Sets all the pixels / voxels scalar value according to the following rules:\
<ul> \
<li>low threshold &lt; scalar value &lt; high threshold \=&gt; white (255) </li> \
<li>scalar value &lt; low threshold OR scalar value &gt; high threshold \=&gt; black (0)</li> \
<li>low threshold &lt; scalar value &lt; high threshold &gt; white (255) </li> \
<li>scalar value &lt; low threshold OR scalar value &gt; high threshold &gt; black (0)</li> \
</ul>");
setComponent("ImageComponent");
......
......@@ -38,6 +38,9 @@
#include <itkVTKImageToImageFilter.h>
#include <itkOtsuThresholdImageFilter.h>
// Tmp Include
#include <vtkSmartPointer.h>
#include <vtkImageThreshold.h>
using namespace camitk;
......@@ -94,9 +97,166 @@ void OtsuFilter::process(ImageComponent * comp) {
this->insideValue = property("Inside value").toInt();
this->outsideValue = property("Outside value").toInt();
// ITK filter implementation using templates
/*
// V01: Only VTK, no pipeline cutting
// 1- Closing threshold image first
// a)If you close first threshold image -> memory of the threshold image is freed
// b)If then, you close the original image -> memory of the original image is freed
// 2- Closing original image first
// a) If you first close original image -> no memory is freed
// (the threshold image is still linked to the original image via the pipeline)
// b) If you then close the threshold image -> memory of both images is freed
vtkSmartPointer<vtkImageData> inputImage = comp->getImageData();
vtkSmartPointer<vtkImageData> outputImage = implementProcess (inputImage);
vtkSmartPointer<vtkImageData> outputImage = NULL;
vtkSmartPointer<vtkImageThreshold> imageThreshold = vtkSmartPointer<vtkImageThreshold>::New();
imageThreshold->SetInput(inputImage);
unsigned char lower = 100;
unsigned char upper = 200;
imageThreshold->ThresholdBetween(lower, upper);
imageThreshold->ReplaceInOn();
imageThreshold->SetInValue(insideValue);
imageThreshold->ReplaceOutOn();
imageThreshold->SetOutValue(outsideValue);
imageThreshold->Update();
outputImage = imageThreshold->GetOutput();
QString newName;
QTextStream(&newName) << comp->getName() << "_otsu";
new ImageComponent(outputImage, newName);
Application::refresh();
*/
/*
// V02: Only VTK, pipeline cutting by deep copy
// 1- Closing threshold image first
// a)If you close first threshold image -> memory of the threshold image is freed
// b)If then, you close the original image -> memory of the original image is freed
// 2- Closing original image first
// a) If you first close original image -> memory of the original image is freed
// (the threshold image is no more linked to the original image via the pipeline)
// b) If you then close the threshold image -> memory of the threshold image is freed
vtkSmartPointer<vtkImageData> inputImage = comp->getImageData();
vtkSmartPointer<vtkImageData> outputImage = NULL;
vtkSmartPointer<vtkImageThreshold> imageThreshold = vtkSmartPointer<vtkImageThreshold>::New();
imageThreshold->SetInput(inputImage);
unsigned char lower = 100;
unsigned char upper = 200;
imageThreshold->ThresholdBetween(lower, upper);
imageThreshold->ReplaceInOn();
imageThreshold->SetInValue(insideValue);
imageThreshold->ReplaceOutOn();
imageThreshold->SetOutValue(outsideValue);
imageThreshold->Update();
outputImage = imageThreshold->GetOutput();
vtkSmartPointer<vtkImageData> result = vtkSmartPointer<vtkImageData>::New();
int extent[6];
outputImage->GetExtent(extent);
result->SetExtent(extent);
result->DeepCopy(outputImage);
result->Update();
QString newName;
QTextStream(&newName) << comp->getName() << "_otsu";
new ImageComponent(result, newName);
Application::refresh();
*/
/*
// V03: VTK and Itk Pipeline, trying to cut the pipeline by deep copy
// 1- Closing threshold image first
// a)If you close first threshold image -> memory of the threshold image is freed
// b)If then, you close the original image -> memory of the original image is NOT freed
// --> A counter from the pipeline remains on the original image
// 2- Closing original image first
// a) If you first close original image -> memory of the original image is NOT freed
// --> A counter from the pipeline remains on the original image
// b) If you then close the threshod image -> memory of the threshold image is freed
vtkSmartPointer<vtkImageData> inputImage = comp->getImageData();
vtkSmartPointer<vtkImageData> outputImage = implementProcess(inputImage);
vtkSmartPointer<vtkImageData> result = vtkSmartPointer<vtkImageData>::New();
int extent[6];
outputImage->GetExtent(extent);
result->SetExtent(extent);
result->DeepCopy(outputImage);
result->Update();
QString newName;
QTextStream(&newName) << comp->getName() << "_otsu";
new ImageComponent(result, newName);
Application::refresh();
*/
/*
// V04: VTK and Itk Pipeline, trying to cut the pipeline by deep copy and pointers
// ==> The worse: the original image is never freed...
// 1- Closing threshold image first
// a)If you close first threshold image -> memory of the threshold image is freed
// b)If then, you close the original image -> memory of the original image is NOT freed
// --> A counter from the pipeline remains on the original image
// 2- Closing original image first
// a) If you first close original image -> memory of the original image is NOT freed
// --> A counter from the pipeline remains on the original image
// b) If you then close the threshod image -> memory of the threshold image is freed
vtkSmartPointer<vtkImageData> inputImage = comp->getImageData();
vtkSmartPointer<vtkImageData> outputImage = implementProcess(inputImage);
vtkSmartPointer<vtkImageData> result = vtkSmartPointer<vtkImageData>::New();
int extent[6];
outputImage->GetExtent(extent);
result->SetExtent(extent);
result->DeepCopy(outputImage);
result->Update();
QString newName;
QTextStream(&newName) << comp->getName() << "_otsu";
new ImageComponent(result, newName);
Application::refresh();
*/
/*
// V05: VTK and Itk Pipeline, trying to cut the pipeline by 2 deep copies (argh !)
// ==> One of the created copies is never deleted !
// 1- Closing threshold image first
// a)If you close first threshold image -> memory of the threshold image is freed
// But NOT the memory of its copy !
// b)If then, you close the original image -> memory of the original image is freed
// 2- Closing original image first
// a) If you first close original image -> memory of the original image is freed
// b) If you then close the threshod image -> memory of the threshold image is freed
// But NOT the memory of its copy !
vtkSmartPointer<vtkImageData> inputImage = vtkSmartPointer<vtkImageData>::New();
int extentInput[6];
comp->getImageData()->GetExtent(extentInput);
inputImage->SetExtent(extentInput);
inputImage->DeepCopy(comp->getImageData());
inputImage->Update();
vtkSmartPointer<vtkImageData> outputImage = implementProcess(inputImage);
inputImage = NULL;
vtkSmartPointer<vtkImageData> result = vtkSmartPointer<vtkImageData>::New();
int extent[6];
outputImage->GetExtent(extent);
result->SetExtent(extent);
result->DeepCopy(outputImage);
result->Update();
outputImage = NULL;
QString newName;
QTextStream(&newName) << comp->getName() << "_otsu";
new ImageComponent(result, newName);
result = NULL;
Application::refresh();
*/
// V06: VTK and Itk Pipeline, trying to cut the pipeline by 2 shallow copies (bof...)
// ==> One of the created copies is never deleted !
// 1- Closing threshold image first
// a)If you close first threshold image -> memory of the threshold image is freed
// But NOT the memory of its copy !
// b)If then, you close the original image -> memory of the original image is freed
// 2- Closing original image first
// a) If you first close original image -> memory of the original image is freed
// b) If you then close the threshod image -> memory of the threshold image is freed
// But NOT the memory of its copy !
vtkSmartPointer<vtkImageData> inputImage = comp->getImageData();
vtkSmartPointer<vtkImageData> outputImage = implementProcess(inputImage);
QString newName;
QTextStream(&newName) << comp->getName() << "_otsu";
new ImageComponent(outputImage, newName);
......@@ -109,8 +269,7 @@ void OtsuFilter::process(ImageComponent * comp) {
// ITK filter implementation
template <class InputPixelType, class OutputPixelType, const int dim>
vtkSmartPointer<vtkImageData> OtsuFilter::itkProcess(vtkSmartPointer<vtkImageData> img) {
vtkSmartPointer<vtkImageData> result = vtkSmartPointer<vtkImageData>::New();
// --------------------- Filters declaration and creation ----------------------
// Define ITK input and output image types with respect to the instanciation
// types of the tamplate.
......@@ -123,14 +282,14 @@ vtkSmartPointer<vtkImageData> OtsuFilter::itkProcess(vtkSmartPointer<vtkImageDat
// Declare and create your own private ITK filter here...
typedef itk::OtsuThresholdImageFilter<InputImageType, OutputImageType> FilterType;
typename FilterType::Pointer filter = FilterType::New();
typename itk::SmartPointer<FilterType> filter = FilterType::New();
// In the same way, once the image is filtered, we need to convert it again to
// VTK format to give it to CamiTK.
typedef itk::ImageToVTKImageFilter<OutputImageType> itkToVtkFilterType;
typename itkToVtkFilterType::Pointer itkToVtkFilter = itkToVtkFilterType::New();
// ------------------------- WRITE YOUR CODE HERE ----------------------------------
// To update CamiTK progress bar while filtering, add an ITK observer to the filters.
ItkProgressObserver::Pointer observer = ItkProgressObserver::New();
// ITK observers generally give values between 0 and 1, and CamiTK progress bar
......@@ -140,23 +299,26 @@ vtkSmartPointer<vtkImageData> OtsuFilter::itkProcess(vtkSmartPointer<vtkImageDat
// --------------------- Plug filters and parameters ---------------------------
// From VTK to ITK
vtkToItkFilter->SetInput(img);
// For the filter itself
filter->SetInput(vtkToItkFilter->GetOutput());
filter->AddObserver ( itk::ProgressEvent(), observer );
filter->SetOutsideValue(this->outsideValue);
filter->SetInsideValue(this->insideValue);
// ------------------------- WRITE YOUR CODE HERE ----------------------------------
// From ITK to VTK
// Change the following line to put your filter instead of vtkToItkFilter
filter->Update();
itkToVtkFilter->SetInput(filter->GetOutput());
// --------------------- Actually execute all filters parts --------------------
itkToVtkFilter->Update();
//this->usedThreshold = (double) filter->GetThreshold();
QObject::setProperty("Computed threshold:", (double) filter->GetThreshold());
// --------------------- Create and return a copy (the filters will be deleted)--
vtkImageData * resultImage = itkToVtkFilter->GetOutput();
vtkSmartPointer<vtkImageData> resultImage = itkToVtkFilter->GetOutput();
vtkSmartPointer<vtkImageData> result = vtkSmartPointer<vtkImageData>::New();
int extent[6];
resultImage->GetExtent(extent);
result->SetExtent(extent);
......@@ -165,11 +327,9 @@ vtkSmartPointer<vtkImageData> OtsuFilter::itkProcess(vtkSmartPointer<vtkImageDat
// Set CamiTK progress bar back to zero (the processing filter is over)
observer->Reset();
//this->usedThreshold = (double) filter->GetThreshold();
QObject::setProperty("Computed threshold:", (double) filter->GetThreshold());
observer = NULL;
return result;
}
......@@ -99,7 +99,7 @@ DicomComponent::DicomComponent(DicomSerie* dicomSerie) throw(AbortException) : I
// TODO read the tag (0018, 5100) Patient position
// create image data corresponding to the component
imageReader = vtkGDCMImageReader::New();
imageReader = vtkSmartPointer<vtkGDCMImageReader>::New();
if(fileNamesSorted->GetSize() == 1)
imageReader->SetFileName(fileNamesSorted->GetValue(0));
else
......@@ -115,7 +115,7 @@ DicomComponent::DicomComponent(DicomSerie* dicomSerie) throw(AbortException) : I
double *spacing = imageReader->GetDataSpacing();
// Update Z Spacing using a VTK pipeline
vtkSmartPointer<vtkImageChangeInformation> imageInfoChanger = vtkImageChangeInformation::New();
vtkSmartPointer<vtkImageChangeInformation> imageInfoChanger = vtkSmartPointer<vtkImageChangeInformation>::New();
imageInfoChanger->SetInput(rawData); //translatedData);
/// DEBUG
......@@ -155,8 +155,8 @@ DicomComponent::DicomComponent(DicomSerie* dicomSerie) throw(AbortException) : I
DicomComponent::~DicomComponent() {
if(serie)
delete serie;
if(imageReader)
imageReader->Delete();
// if(imageReader)
// imageReader->Delete();
}
// --------------- updateLUT -------------------
......
......@@ -67,7 +67,7 @@ private:
*
* @note This class allows to make the bridge between GDCM and CamiTK.
*/
vtkGDCMImageReader* imageReader;
vtkSmartPointer<vtkGDCMImageReader> imageReader;
/**
* @brief Update the LUT of the image by reading the good information from the DICOM headers.
......
......@@ -107,6 +107,9 @@ void VtkImageComponent::createComponent(const QString& filename) {
}
setImageData(image, false, orientation, rotationMatrix);
image = NULL;
reader = NULL;
}
catch (AbortException e) {
......
......@@ -86,6 +86,7 @@ Slice::Slice(vtkSmartPointer<vtkImageData> volume, SliceOrientation orientation,
/* Destructor */
Slice::~Slice() {
// Let's unreference vtkSmartPointers
originalVolume = NULL;
lut = NULL;
imgToMapFilter = NULL;
......
......@@ -99,6 +99,8 @@ ImageComponent::~ImageComponent() {
if (selectionView != NULL) {
delete selectionView;
}
originalImageData = NULL;
}
// -------------------- init --------------------
......@@ -222,6 +224,7 @@ void ImageComponent::setImageData(vtkSmartPointer<vtkImageData> anImageData,
this->initialOrientation = initialOrientation;
originalImageData = NULL;
vtkSmartPointer<vtkImageData> inputImage = NULL;
if (copy) {
// We need to use a shall because of some strange behaviour of mingw
......@@ -231,22 +234,22 @@ void ImageComponent::setImageData(vtkSmartPointer<vtkImageData> anImageData,
// (equivalent of ITK DisconnectPipeline()...)
// Note : this (i.e disconnect/deepcopy/shallowcopy) should not have to be done
// in the components...
originalImageData = vtkImageData::New();
originalImageData->ShallowCopy(anImageData);
inputImage = vtkSmartPointer<vtkImageData>::New();
inputImage->ShallowCopy(anImageData);
} else
originalImageData = anImageData;
inputImage = anImageData;
// 1. Get / compute the initial translation of the image
double t_x, t_y, t_z;
originalImageData->GetOrigin(t_x, t_y, t_z);
vtkSmartPointer<vtkTransform> initialTranslation = vtkTransform::New();
inputImage->GetOrigin(t_x, t_y, t_z);
vtkSmartPointer<vtkTransform> initialTranslation = vtkSmartPointer<vtkTransform>::New();
initialTranslation->Identity();
initialTranslation->Translate(t_x, t_y, t_z);
initialTranslation->Update();
// 2. Get the orientation of the image
double* imgSpacing = originalImageData->GetSpacing();
int* imgDims = originalImageData->GetDimensions();
double* imgSpacing = inputImage->GetSpacing();
int* imgDims = inputImage->GetDimensions();
double dims[3];
dims[0] = imgSpacing[0] * imgDims[0];
dims[1] = imgSpacing[1] * imgDims[1];
......@@ -259,28 +262,29 @@ void ImageComponent::setImageData(vtkSmartPointer<vtkImageData> anImageData,
addProperty(orientationProperty);
// 4. Store the Translation * orientation -> RAI = initialImageDataTransform
initialImageDataTransform = vtkTransform::New();
vtkSmartPointer<vtkMatrix4x4> initialImageDataMatrix = vtkMatrix4x4::New();
initialImageDataTransform = vtkSmartPointer<vtkTransform>::New();
vtkSmartPointer<vtkMatrix4x4> initialImageDataMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
vtkMatrix4x4::Multiply4x4(initialTranslation->GetMatrix(), orientationToRAIMatrix, initialImageDataMatrix);
initialImageDataTransform->SetMatrix(initialImageDataMatrix);
// 5. Store the rotation * translation * orientation -> RAI = initialFrameTransform
initialFrameTransform = vtkTransform::New();
vtkSmartPointer<vtkMatrix4x4> initialFrameMatrix = vtkMatrix4x4::New();
if(!initialRotationMatrix){
initialRotationMatrix = vtkMatrix4x4::New();
initialRotationMatrix->Identity();
}
initialFrameTransform = vtkSmartPointer<vtkTransform>::New();
vtkSmartPointer<vtkMatrix4x4> initialFrameMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
rotationMatrix = initialRotationMatrix;
vtkMatrix4x4::Multiply4x4(initialRotationMatrix, initialTranslation->GetMatrix(), initialFrameMatrix);
if(!rotationMatrix){
rotationMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
rotationMatrix->Identity();
}
vtkMatrix4x4::Multiply4x4(rotationMatrix, initialTranslation->GetMatrix(), initialFrameMatrix);
vtkMatrix4x4::Multiply4x4(initialFrameMatrix, orientationToRAIMatrix, initialFrameMatrix);
initialFrameTransform->SetMatrix(initialFrameMatrix);
// 6. Apply initialImageDataTransform to the image data
vtkSmartPointer<vtkImageReslice> imageResliceFilter = vtkSmartPointer<vtkImageReslice>::New();
imageResliceFilter->SetInput(anImageData);
imageResliceFilter->SetInput(inputImage);
imageResliceFilter->SetOutputDimensionality(3);
imageResliceFilter->SetResliceAxes(initialImageDataTransform->GetMatrix());
imageResliceFilter->Update();
originalImageData = imageResliceFilter->GetOutput();
originalImageData->Update();
......@@ -293,6 +297,10 @@ void ImageComponent::setImageData(vtkSmartPointer<vtkImageData> anImageData,
updatedTransform->SetMatrix(updatedMatrix);
setTransform(updatedTransform);
// Clean smart pointers
inputImage = NULL;
imageResliceFilter = NULL;
// Build default lookup table
initLookupTable();
......@@ -307,7 +315,7 @@ void ImageComponent::setImageData(vtkSmartPointer<vtkImageData> anImageData,
void ImageComponent::prepareForSaving() {
// 1. Put back image data to its original state
vtkSmartPointer<vtkMatrix4x4> backToOriginalImageDataMatrix = vtkMatrix4x4::New();
vtkSmartPointer<vtkMatrix4x4> backToOriginalImageDataMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
backToOriginalImageDataMatrix->DeepCopy(initialImageDataTransform->GetMatrix());
backToOriginalImageDataMatrix->Invert();
vtkSmartPointer<vtkImageReslice> backToOrigingImageDataFilter = vtkSmartPointer<vtkImageReslice>::New();
......@@ -319,21 +327,21 @@ void ImageComponent::prepareForSaving() {
// 2. Retrieve the matrice of the user Muser which has been applied to the initial frame
// Assuming Mframe = MinitFrame * Muser
vtkSmartPointer<vtkMatrix4x4> initialFrameMatrixInverse = vtkMatrix4x4::New();
vtkSmartPointer<vtkMatrix4x4> initialFrameMatrixInverse = vtkSmartPointer<vtkMatrix4x4>::New();
initialFrameMatrixInverse->DeepCopy(initialFrameTransform->GetMatrix());
initialFrameMatrixInverse->Invert();
const vtkSmartPointer<vtkTransform> frame = getTransform();
vtkSmartPointer<vtkMatrix4x4> frameMatrix = frame->GetMatrix();
vtkSmartPointer<vtkMatrix4x4> userMatrix = vtkMatrix4x4::New();
vtkSmartPointer<vtkMatrix4x4> userMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
vtkMatrix4x4::Multiply4x4(initialFrameMatrixInverse, frameMatrix , userMatrix);
vtkSmartPointer<vtkTransform> userTransform = vtkTransform::New();
vtkSmartPointer<vtkTransform> userTransform = vtkSmartPointer<vtkTransform>::New();
userTransform->SetMatrix(userMatrix);
// 3. Retrieve the translation of the user matrix and apply it to the image data
// This way, the translation will be saved under the Offset tag
double pos[3];
userTransform->GetPosition(pos);
vtkSmartPointer<vtkTransform> translationTransform = vtkTransform::New();
vtkSmartPointer<vtkTransform> translationTransform = vtkSmartPointer<vtkTransform>::New();
translationTransform->Identity();
translationTransform->Translate(pos[0], pos[1], pos[2]);
translationTransform->Update();
......@@ -350,7 +358,7 @@ void ImageComponent::prepareForSaving() {
(userMatrix->GetElement(1,1) != 1) ||
(userMatrix->GetElement(2,2) != 1) ){
rotationMatrix = vtkMatrix4x4::New();
rotationMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
rotationMatrix->DeepCopy(userMatrix);
rotationMatrix->SetElement(0, 3, 0.0);
rotationMatrix->SetElement(1, 3, 0.0);
......
......@@ -33,7 +33,7 @@ VTKImageToImageFilter<TOutputImage>
::VTKImageToImageFilter()
{
m_Exporter = vtkImageExport::New();
m_Exporter = vtkSmartPointer<vtkImageExport>::New();
m_Importer = ImporterFilterType::New();
......@@ -79,7 +79,10 @@ void
VTKImageToImageFilter<TOutputImage>
::SetInput( vtkSmartPointer<vtkImageData> inputImage )
{
m_Exporter->SetInput( inputImage );
// Artificially cut the pipeline...
vtkSmartPointer<vtkImageData> inputBis = vtkSmartPointer<vtkImageData>::New();
inputBis->ShallowCopy(inputImage);
m_Exporter->SetInput( inputBis );
}
......
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