ITK学习笔记1:从一个简单的例子出发学习ITK

看完东灵的vtk的相关教程,接下来就是对itk的学习了。不过网上itk的学习资源还是零零散散的,还是需要自己进行整合。

项目地址: Alxemade/ITKLearning

1. 参考资源

  1. CSDN: ljp1919的专栏-ITK学习笔记
  2. CSDN: rabbitbride的专栏-ITK医学图像处理
  3. CSDN: inter_peng的专栏-ITK学习
  4. CSDN: 本blog的医学图像处理算法汇总
  5. ITK官方例子
  6. ITK Software Guide
  7. ITK 4.13.0 Documentation
  8. Insight Journal (ISSN 2327-770X)
  9. 知乎:VTK ITK OPENCV,从图像处理的角度来说,哪种用的人多?

先把这些资源稍微整理一下,以后自己查找起来也是很方便的。

2. 从一个简单的例子出发

按照之前学习vtk的套路,我们首先也是编写CmakeLists和cpp文件,然后使用cmake软件进行编译,然后再在vs2017里面进行编译我们文件,其实方法是一样的。这里具体的步骤就不太详细介绍了,这里贴出代码。

2.1 源程序

   这里实现的功能也是非常简单的,就是使用itk读取一幅图像,然后在保存一幅图像。

2.1.1 CmakeLists文件

cmake_minimum_required(VERSION 2.8)

project(ITKImageReader)

find_package(ITK REQUIRED)

include(${ITK_USE_FILE})

add_executable(${PROJECT_NAME} ITKImageReader.cpp)

target_link_libraries(${PROJECT_NAME} ${ITK_LIBRARIES})

这里代码没有什么好解释的,常规操作。文件名是ITKImageReader ,可以参考之前的东灵的文章以及cmake的基本语法。

2.1.2 CPP文件

#include <itkImage.h>
#include <itkImageFileReader.h>
#include <itkImageFileWriter.h> 
 
int main(int argc, char* argv[]) 
{ 
	const unsigned int Dimension = 2;                                          //定义图像维数 
	//typedef unsigned char                                     PixelType;      //定义像素类型 
	typedef itk::RGBPixel< unsigned char >   PixelType;  
	typedef itk::Image< PixelType, 2 >       ImageType; 
	typedef itk::ImageFileReader< ImageType >  ReaderType;  
	typedef itk::ImageFileWriter< ImageType >  WriterType;  
	ReaderType::Pointer reader = ReaderType::New();  
	WriterType::Pointer writer = WriterType::New(); 
 
	reader->SetFileName("E:\\XC\\itk\\Examples\\Demo1_itkImageReader\\bin\\hua.jpg");   
	writer->SetFileName( "E:\\XC\\itk\\Examples\\Demo1_itkImageReader\\bin\\hua2.jpg");  
 
	ImageType::Pointer image = reader->GetOutput();  
	writer->SetInput( image );  

	writer->Update();  //  Aliased to the Write() method to be consistent with the rest of the pipeline.
 
	return 0; 
}

虽然代码不是太长,但是乍一看还是觉得挺复杂的,这里听我给您娓娓道来。

前面几行没什么好说的,主要是包含一些头文件,然后我们着重从第9行开始。如果c++大牛可以不用看下面的内容了,个人还是在c++的摸索的路上~

注解:
   9-12行其实功能大抵是相同的,无非就是定义一些类型。看懂代码最好的方法就是进入它的定义然后理解代码。所以我们进入第9行RGBPixel定义:
在这里插入图片描述

这里一看原来RGNPixel是在itk这个命名空间里啊,所以如果想要访问它自然使用itk::RGBPixel,关于命名空间的使用,可以参考我之前的博文C++学习笔记1–命名空间的使用, 看了大概就会明白是怎么一回事了,这里使用公共的itk,应该是命名空间的扩充。 紧接着,我们在看57,58行代码,这里是一个模板类,使用默认参数unsigned short, 代码class ITK_TEMPLATE_EXPORT RGBPixel:public FixedArray< TComponent, 3 > 还是一个类模板继承类模板的情况,这个可以参考这篇博客模板类的继承,所以我们使用<unsigned char>来实例化一个模板,最后利用关键字typedef取一个别名。后面的10-12类似的操作。

   13-17行定义二个SmartPointer变量读取指定路径数据。
   19-22 读取并写入图像数据。

2.2 一句有趣的代码

在阅读ITK的源码的过程中,发现里面存在大量的模板类,一个继承一个,有点头大。在其中,发现有一句挺有意思的,这里贴出来,一起学习一下。

在这里插入图片描述这里比如第91行代码:
typedef typename TOutputImage::SizeType SizeType; 这里typedef用法不用多说, 就是给变量取一个别名。但是为什么还需要出现一个typename自己就不是很明白了。在一番google之后,也是大概了解为什么这么用。

  在类外部访问类中的名称时,可以使用类作用域操作符,形如MyClass::name的调用通常存在三种:静态数据成员、静态成员函数和嵌套类型:

struct MyClass {
    static int A;
    static int B();
    typedef int C;
}

MyClass::A, MyClass::B, MyClass::C分别对应着上面三种。

所以在模板类的使用情况下, 只有在等到模板实例化的情况是编译器才会知道具体是什么类型的数据,这里使用typename真正目的就是让编译器知道这是一种数据类型,而不是静态成员函数或者静态成员变量。推荐两篇介绍这个比较好的文章。

  1. 知无涯之C++ typename的起源与用法
  2. stackoverflow: How to use typename in c++? [duplicate]

3. 结果

我们读入hua.jpg最后就是在当前目录下也生成了一幅hua2.jpg文件。
在这里插入图片描述

真的当看代码有疑惑的时候,还是需要刨根问底的,而不是打马虎眼。

猜你喜欢

转载自blog.csdn.net/alxe_made/article/details/84107017