VTK学习笔记(十四)vtkImageData缩放到指定尺寸

VTK学习笔记(十四)vtkImageData缩放到指定尺寸

  • 1、vtkSmartPointer智能指针返回
  • 2、vtkSmartPointer作为参数返回
  • 3、使用vtkImageResize
  • 4、设置插值方式

1、vtkSmartPointer智能指针返回

其实主要想说以下智能指针的使用。
当所有过程写在主函数中时运行正确。
但当用函数传递vtkImage指针时出现问题,可以通过编译但运行时提示试图访问未授权的内存地址。
子函数内部的vtkImageData指针在return到主函数的时候"Out of Scope"引用计数变成0。
在子函数内部不应直接对将要返回到主函数的指针赋值,而是使用DeepCopy功能。

#include 
#include 
#include 
#include 

// MyFunction函数:演示智能指针可以作为函数返回值
vtkSmartPointer<vtkImageData> MyFunction()
{
    vtkSmartPointer<vtkImageData> myObject = vtkSmartPointer<vtkImageData>::New();
    std::cout<<"MyFunction::myObject reference count = "<<myObject->GetReferenceCount()<<std::endl;
    return myObject;
}

//测试文件:data/VTK-logo.bmp
int main(int argc, char* argv[])
{

    //演示引用计数:
    vtkSmartPointer<vtkBMPReader> reader = vtkSmartPointer<vtkBMPReader>::New();
    reader->SetFileName("C:\\Users\\Administrator\\Desktop\\vtk1\\Examples\\Examples\\Chap02\\data\\VTK-logo.bmp");
    reader->Update();

    std::cout<<"Reference Count of reader->GetOutput (Before Assignment) = "
        <<reader->GetOutput()->GetReferenceCount()<<std::endl;

    vtkSmartPointer<vtkImageData> image1 = reader->GetOutput();
    std::cout<<"Reference Count of reader->GetOutput (Assign to image1) = "
        <<reader->GetOutput()->GetReferenceCount()<<std::endl;
    std::cout<<"Reference Count of image1 = "
        <<image1->GetReferenceCount()<<std::endl;

    vtkSmartPointer<vtkImageData> image2 = reader->GetOutput();
    std::cout<<"Reference Count of reader->GetOutput (Assign to image2) = "
        <<reader->GetOutput()->GetReferenceCount()<<std::endl;
    std::cout<<"Reference Count of image2 = "
        <<image2->GetReferenceCount()<<std::endl;
    //

    //
    //演示智能指针可以作为函数返回值
    //由于函数MyFunction()的返回值是通过拷贝的方式,
    //将数据赋予调用的变量,因此该数据的引用计数保持不变
    std::cout<<"myObject reference count = "
        <<MyFunction()->GetReferenceCount()<<std::endl;

    vtkSmartPointer<vtkImageData> MyImageData = MyFunction();
    std::cout<<"MyFunction return value reference count = "
        <<MyFunction()->GetReferenceCount()<<std::endl;

    std::cout<<"MyImageData reference count = "
        <<MyImageData->GetReferenceCount()<<std::endl;
    //

    //
    //如果没有给对象分配内存,仍然可以使用智能指针:
    vtkSmartPointer<vtkBMPReader> Reader = vtkSmartPointer<vtkBMPReader>::New();
    vtkImageData* pd = Reader->GetOutput();
    //

    system("pause");
    return EXIT_SUCCESS;
}

引用计数概念:
引用计数是一个简单 的垃圾回收机制。
只要其他对象引用某对象,这个对象的引用计数就会增加1,当最后所有引用该对象的对象都移除之后,这个对象自动析构。
在vtk当中这样的好处是可以实现数据的共享而不用复制,可以节省内存。

image1->GetReferenceCount();//该方法可以获得当前对象的引用计数

一旦某个对象的引用计数等于0,就表明没有别的对象再引用他了,他的使命也就结束了,程序会自动析构这个对象。

智能指针:
智能指针可以自动管理引用计数的增加和减少,若检测到某对象的引用计数减少为0,则会自动释放给对象的资源。
这又要回到vtk中创建对象的方式上了:
vtk有两种创建对象的方式:

1、使用vtkObjectBase里的静态成员函数New(),再用Delete()方法析构。
2、使用智能指针的方式vtkSmartPointer < T >的方式。
对于第一种方式创建的对象是程序员再堆上创建的对象,这个对象并不会自动析构,不关编译器的事情(编译器只管栈上的事情),所以在程序的最后必须调用Delete()方法,使得引用计数减一。

vtkBMPReader* reader = vtkBMPReader::New();
....
reader->Delete();//这里并没有直接析构这个对象,而是使引用计数减一。

对于第二种方式,不用手动调用Delete()方法,因为引用计数的减少和增加都是智能指针自动完成的。
使用智能指针就需要包含智能指针的头文件vtkSmartPointer.h。vtkSmartPointer是一个模板类所需要的参数就是待创建的对象的类名。
必须写成一下形式:

vtkSmartPointer<vtkBMPReader> reader = vtkSmartPointer<vtkBMPReader>::New();

不能写成:

vtkSmartPointer<vtkBMPReader> reader = vtkBMPReader::New();

这样编译没问题,但是程序退出的时候智能指针无法自动释放该对象的内存。出现内存泄漏。
所以不能把对象的原始指针赋值给智能指针。

参考:vtk智能指针->对智能指针的理解和使用
参考:c++ 智能指针用法详解

2、vtkSmartPointer作为参数返回

void qSlicerArielSegmentationModuleWidgetPrivate::vtkresampleTotargetsize(
    vtkImageData* input, int targetsize[3], vtkSmartPointer<vtkImageData>& output)
{
  int dims[3];
  int dims1[3];
  input->GetDimensions(dims);
  vtkNew<vtkImageResample> resample;
  std::vector<float> factor(3, 0.0f);
  factor[0] = float(targetsize[0]) / dims[0];
  factor[1] = float(targetsize[1]) / dims[1];
  factor[2] = float(targetsize[2]) / dims[2];
  resample->SetInputData(input);
  resample->SetAxisMagnificationFactor(0, factor[0]);
  resample->SetAxisMagnificationFactor(1, factor[1]);
  resample->SetAxisMagnificationFactor(2, factor[2]);
  resample->SetInterpolationModeToCubic();
  resample->Update();
  return output->DeepCopy(resample->GetOutput());
}

当然这段代码并不完美,不能按指定的尺寸返回。

3、使用vtkImageResize

下面是一个使用vtkImageResize 实现的resize操作,但是还不清楚怎么设置插值方式。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

int main(int argc, char* argv[])
{
  vtkNew<vtkNamedColors> colors;

  vtkSmartPointer<vtkImageData> imageData;
  string fileName = "";
  string dstfileName = "";
  int newSize[3] = {200, 10, 20};
  int windowFunction = 0;

  // Verify input arguments
  // e.g. Gourds2.jpg 1280 1024 5
  if (argc > 1)
  {
    // Read the image
      fileName = argv[1];

      // Read the data
      //vtkSmartPointer reader;
      vtkSmartPointer<vtkImageData> input;
      vtkSmartPointer <vtkNIFTIImageReader> niftireader = vtkSmartPointer<vtkNIFTIImageReader>::New();
      niftireader->SetFileName(fileName.c_str());
      niftireader->Update();
      input = niftireader->GetOutput();
      //reader = niftireader;

    imageData = niftireader->GetOutput();

    if (argc > 4)
    {
      newSize[0] = atoi(argv[2]);
      newSize[1] = atoi(argv[3]);
      newSize[2] = atoi(argv[4]);
    }
    if (argc > 5)
    {
      windowFunction = atoi(argv[5]);
    }
    if (argc > 6)
    {
        dstfileName = argv[6];
    }
  }
 
  vtkNew<vtkImageSincInterpolator> interpolator;
  interpolator->UseWindowParameterOn();
  if (windowFunction >= 0 && windowFunction <= 10)
  {
    interpolator->SetWindowFunction(windowFunction);
  }

  vtkNew<vtkImageResize> resize;
  resize->SetInputData(imageData);
  //resize->SetInterpolator(interpolator);
  resize->SetOutputDimensions(newSize[0], newSize[1], newSize[2]);
  //resize->InterpolateOn();
  resize->Update();
  vtkSmartPointer<vtkNIFTIImageWriter> envImageWriter = vtkSmartPointer<vtkNIFTIImageWriter>::New();
  envImageWriter->SetInputData(resize->GetOutput());
  envImageWriter->SetFileName(dstfileName.c_str());
  envImageWriter->Write();

  return EXIT_SUCCESS;
}



resize前尺寸 144144192
VTK学习笔记(十四)vtkImageData缩放到指定尺寸_第1张图片

resize后尺寸144144224.

VTK学习笔记(十四)vtkImageData缩放到指定尺寸_第2张图片

4、设置插值方式

  vtkNew<vtkImageInterpolator> interpolator;
  interpolator->SetInterpolationModeToNearest();

其他插值方式

void vtkImageInterpolator::SetInterpolationMode	(int mode);

void vtkImageInterpolator::SetInterpolationModeToNearest()	
void vtkImageInterpolator::SetInterpolationModeToLinear	()	
void vtkImageInterpolator::SetInterpolationModeToCubic()	

获取插值方式

int vtkImageInterpolator::GetInterpolationMode();
const char* vtkImageInterpolator::GetInterpolationModeAsString();

参考:vtkImageInterpolator Class Reference

你可能感兴趣的:(VTK,VTK)