基于ITK和VTK实现三维体数据的区域生长分割和可视化
2016-07-18 22:35
2995 查看
该文由Markdown语法编译器编辑完成。
本文主要介绍ITK中的基于itkConnectedThresholdFilter的区域生长分割算法,并且利用 VTK将区域生长分割后的体数据进行显示。
这篇文章是基于当前我正在公司开发的一个项目中抽取的部分需求来撰写的。其中的需求是输入患者的一组CT数据,首先基于阈值进行分割,然后在阈值分割的基础上,再进行区域生长分割,这样可以快速地获取用户需要后处理的感兴趣区域。
由于要处理的是医学体数据,而且是已经进行完阈值分割后的数据,因此它的数据类型设为vtkImageData。
由于VTK和ITK的数据类型不能直接使用,因此首先需要将VTK类型的体数据vtkImageData转化成itkImage,然后再调用ITK中的区域生长的算法,最后再将分割后的数据再转换回vtkImageData,进行后续的三维后处理等。
好在,ITK中已经提供了转化数据类型的filter,只需根据需要选择使用即可。
以下是主要的实现代码:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201607/a6f8eac6903c1b6e95926225623953cd)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201607/7b46c45822f4f6630d084fe347ca2c6f)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201607/2000c60ffef2cbbedae8f1512da20c79)
完。
1. 前言:
在医学影像的开源库中,ITK主要擅长图像分割和图像配准算法的 研究,VTK则擅长三维可视化的实现。通过结合二者,可以实现基本的图像分割或配准算法的执行和结果显示。本文主要介绍ITK中的基于itkConnectedThresholdFilter的区域生长分割算法,并且利用 VTK将区域生长分割后的体数据进行显示。
2. 基本步骤:
本文所采用的基本开发环境为:序号 | 软件 | 版本号 |
---|---|---|
1 | ITK | 4.10.0 |
2 | VTK | 6.0.0 |
3 | QT | 5.1.0 |
4 | Visual Studio | 2012 |
5 | OS | Windows 7 |
由于要处理的是医学体数据,而且是已经进行完阈值分割后的数据,因此它的数据类型设为vtkImageData。
由于VTK和ITK的数据类型不能直接使用,因此首先需要将VTK类型的体数据vtkImageData转化成itkImage,然后再调用ITK中的区域生长的算法,最后再将分割后的数据再转换回vtkImageData,进行后续的三维后处理等。
好在,ITK中已经提供了转化数据类型的filter,只需根据需要选择使用即可。
以下是主要的实现代码:
//.h文件: static const int kDimension=3; typedef itk::Image< int, kDimension > ImageType; typedef ImageType::IndexType PixelIndexType; ImageType::Pointer m_itkImage; ImageType::IndexType m_pixelIndex; //.cpp文件: void ConstructITKImage(const vtkImageData* originalImageData) { double imageSpacing[3] = {0.0}; double imageOrigin[3] = {0.0}; int imageDimension[3] = {0}; originalImageData->GetSpacing(imageSpacing); originalImageData->GetOrigin(imageOrigin); originalImageData->GetDimensions(imageDimension); const ImageType::SizeType size = {{imageDimension[0], imageDimension[1], imageDimension[2]}}; //Size along {X,Y,Z} const ImageType::IndexType start = {{0,0,0}}; // First index on {X,Y,Z} ImageType::RegionType region; region.SetSize( size ); region.SetIndex( start ); //Types for converting between ITK and VTK typedef itk::VTKImageToImageFilter<ImageType> VTKImageToImageType; //Converting to ITK Image Format VTKImageToImageType::Pointer vtkImageToImageFilter = VTKImageToImageType::New(); vtkImageToImageFilter->SetInput(originalImageData); vtkImageToImageFilter->UpdateLargestPossibleRegion(); //将vtk的图像转化为itk的图像,以便利用itk的分割算法进行分割. m_itkImage->SetRegions( region ); m_itkImage->Allocate(); m_itkImage = const_cast<itk::Image<int, kDimension>*>(vtkImageToImageFilter->GetImporter()->GetOutput()); ImageType::SpacingType spacing; spacing[0] = imageSpacing[0]; // spacing along X spacing[1] = imageSpacing[1]; // spacing along Y spacing[2] = imageSpacing[2]; // spacing along Z m_itkImage->SetSpacing( spacing ); ImageType::PointType newOrigin; newOrigin[0] = imageOrigin[0]; newOrigin[1] = imageOrigin[1]; newOrigin[2] = imageOrigin[2]; m_itkImage->SetOrigin( newOrigin ); ImageType::DirectionType direction; direction.SetIdentity(); m_itkImage->SetDirection( direction ); m_itkImage->UpdateOutputInformation(); }; bool CheckSeedPointInsideImage( double worldSeedPoint[3] ) { typedef itk::Point< double, ImageType::ImageDimension > PointType; PointType point; point[0] = worldSeedPoint[0]; // x coordinate point[1] = worldSeedPoint[1]; // y coordinate point[2] = worldSeedPoint[2]; // z coordinate //根据选取的种子点的世界坐标,获取这个种子点在itk图像中的像素索引值. bool isInside = m_itkImage->TransformPhysicalPointToIndex(point, m_pixelIndex); return isInside; } int RegionGrowingByConnectedThredholdFilter(const vtkImageData* pImage, double worldSeedPoint[3]) { ConstructITKImage(originalImageData); bool isSeedPointInsideImage = CheckSeedPointInsideImage(worldSeedPoint); if (!isSeedPointInsideImage) { return; } typedef itk::Image< int, kDimension > InternalImageType; typedef itk::ConnectedThresholdImageFilter< InternalImageType, InternalImageType > ConnectedFilterType; ConnectedFilterType::Pointer connectedThreshold = ConnectedFilterType::New( ); connectedThreshold->SetInput(m_itkImage); //由于区域生长是在阈值分割后进行的,此时的vtkImageData是二值的,灰度只有0和1。因此基于阈值的区域生长的灰度上下限都是1. //区域生长分割后的图像,要经过vtkLookupTable进行颜色映射.vtkLookupTable也只有0和1两个预设值. connectedThreshold->SetLower(1); connectedThreshold->SetUpper(1); connectedThreshold->SetReplaceValue(1); connectedThreshold->SetSeed(m_pixelIndex); typedef itk::ImageToVTKImageFilter<ImageType> ConnectorType; //Converting Back from ITK to VTK Image for Visualization. ConnectorType::Pointer connector = ConnectorType::New(); connector->SetInput(connectedThreshold->GetOutput()); connector->Update(); } ;
3. 区域生长分割结果及显示:
完。
相关文章推荐
- HDU 1811 Rank of Tetris(并查集+拓扑排序)
- JDBC操作封装
- plsql 安装后database下拉没有东西
- LVS负载均衡DR模式+keepalived
- Linux 用户环境变量
- 什么才是正确的javascript数组检测方式
- 使用express + socket.io实现多房间聊天应用
- 将字符串中的空格替换为%20
- TensorFlow学习笔记 - TensorFlow数据结构分析
- 可执行的Python程序
- USB主机控制器驱动——OHCI分析
- Java 集合 ArrayList和LinkedList的几种循环遍历方式及性能对比分析 [ 转载 ]
- 设计模式的概念
- 堆实现最优队列
- UVA 11538 Chess Queen
- 设计模式——工厂方法 FactoryMethod
- PHPExcel 的使用
- jquery ajax
- HTML与SEO的学习之路
- 第三章:Java基础程序设计(中)