ITK、VTKはDiCOMファイル情報を読み取り、インタラクティブなプレビューを実現します

DICOMファイルの紹介

DICOMの正式名称は、医用画像および関連情報の標準である、医用画像および通信(Digital Imaging and Communications in Medicine)です。また、臨床データの医用画像形式も定義します。

DICOMデータ形式には、患者名、ID、年齢などの基本情報など、「ヘッダーファイル」に保存される多数の属性が含まれています。この保存方法により、患者と画像の不一致が回避されます。

患者のサンプルには複数のDICOMサブファイルが含まれ、単一のDICOMオブジェクトにはピクセルデータのフレームが1つだけ含まれます。フレームは順番に存在し、前後に切り替えて、スキャンやイメージングと同様に、映画のスクリーニングと同様のシーンを形成できます。 3D画像、垂直方向に沿って等しい厚さに分割

Snipaste_2020-07-11_11-25-24.png

ITKはDICOMデータを読み取ります

ITKには、DICOMファイルの読み取り方法に応じて、シングルDICOM読み取りとシリアルDICOM読み取りの2つのタイプがあります。

ITKは単一のDICOMファイルを読み取ります

  • itkImageSeriesReader;
  • itkGDCMImageIO;

読んだ後、itkGCOMImageIOのGet ***関数を使用して、患者関連の情報を取得し、それを印刷できます。ここで注意すべきことの1つは、DICOMに対応するデータ型が短く署名されていることです。コアコード:

	string DirectoryPath = "D:/Data_Training/Dicom_data/215020265/AT000002.152046493.dcm";
	

	typedef signed short InternalPixelType;
	const unsigned int  Dimension = 2;
	using InternalImageType = itk::Image<InternalPixelType, Dimension>;

	typedef itk::Image<InternalPixelType, Dimension> ImageType;
	typedef itk::ImageSeriesReader<ImageType> ReaderType;
	
	typedef itk::GDCMImageIO ImageIOType;
	
	ImageIOType::Pointer gdcmIO = ImageIOType::New();
	
	ReaderType::Pointer reader = ReaderType::New();
	reader->SetImageIO(gdcmIO);
	reader->SetFileNames(DirectoryPath);

	// Reading Data;
	try
	{
		reader->Update();
		reader->GetMetaDataDictionary();
		gdcmIO->GetMetaDataDictionary();// 读取头文件信息;

		//信息赋值
		char* name = new char[50];
		char* patientID = new char[50];
		char* time = new char[50];
		char* manufacture = new char[50];
		char* modility = new char[50];
		char* hospital = new char[50];
		char* sex = new char[50];
		char* age = new char[50];
		char* description = new char[100];
		

		
		
		int pixelType = gdcmIO->GetPixelType();
		int componentType = gdcmIO->GetComponentType();
		int fileType = gdcmIO->GetFileType();
		ImageIOType::ByteOrder byteOrder;
		byteOrder = gdcmIO->GetByteOrder();
		
		unsigned int dim = 0;
		gdcmIO->GetDimensions(dim);
		ImageIOType::SizeType imgsize;
		imgsize = gdcmIO->GetImageSizeInPixels();
		int componetSize = gdcmIO->GetComponentSize();
		int dimension = gdcmIO->GetNumberOfDimensions();
		int ori = 0;
	
		gdcmIO->GetOrigin(ori);
		int spa = 0;

		gdcmIO->GetPatientSex(sex);
		gdcmIO->GetPatientAge(age);
		gdcmIO->GetStudyDescription(description);
		gdcmIO->GetSpacing(spa);
		gdcmIO->GetPatientName(name);
		gdcmIO->GetModality(modility);
		gdcmIO->GetPatientID(patientID);
		gdcmIO->GetManufacturer(manufacture);
		gdcmIO->GetStudyDate(time);
		ImageIOType::TCompressionType compressType;
		compressType = gdcmIO->GetCompressionType();
		gdcmIO->GetInstitution(hospital);
		ImageType::SpacingType spacetype;
		spacetype = reader->GetOutput()->GetSpacing();
		ImageType::PointType origin;
		origin = reader->GetOutput()->GetOrigin();
		
		
		
		cout << "name:" << name << endl;
		cout << "age:" << age << endl;
		cout << "sex:" << sex << endl;
		cout << "description:" << description << endl;
		cout << "hospital:" << hospital << endl;
		cout << "modility:" << modility << endl;
		cout << "manfacture:" << manufacture << endl;
		cout << "dim:" << dim << endl;
		cout << "origin:" << origin << endl;
		cout << "Time:" << time << endl;
		cout << "patientID:" << patientID << endl;
		
	}
	catch (const itk::ExceptionObject& excp)
	{
		cout << " Reading Exceptaion Caught" << endl;
		cout << excp.what() << endl;
		
		return EXIT_FAILURE;
	}
	

ITKはシリアルDICOMファイルを読み取りました

  • itkImageSeriesReader;
  • itkGDCMImageIO;
  • itkGDCMSeriesFileNames;

1枚の読み取りとは異なり、追加のitkGDCMSeriesFileNamesクラスがあります。これは、DICOMシーケンスファイルをパッケージ化し、読み取りのためにGDCMImageIOを渡すために使用されます。

	string DirectoryPath = "D:/Data_Training/Dicom_data/215020265";

	typedef signed short InternalPixelType;
	const unsigned int  Dimension = 3;
	using InternalImageType = itk::Image<InternalPixelType, Dimension>;

	typedef itk::Image<InternalPixelType, Dimension> ImageType;
	typedef itk::ImageSeriesReader<ImageType> ReaderType;
	
	typedef itk::GDCMImageIO ImageIOType;
	typedef itk::GDCMSeriesFileNames NamesGeneratorType;
	
	ImageIOType::Pointer gdcmIO = ImageIOType::New();
	NamesGeneratorType::Pointer namesGenerator = NamesGeneratorType::New();
	
	namesGenerator->SetInputDirectory(DirectoryPath);
	
	const ReaderType::FileNamesContainer & filenames =
		namesGenerator->GetInputFileNames();

	std::size_t numberOfFileNames = filenames.size();
	std::cout << numberOfFileNames << std::endl;
	
	
	ReaderType::Pointer reader = ReaderType::New();
	reader->SetImageIO(gdcmIO);
	reader->SetFileNames(filenames);
	

	// Reading Data;
	try
	{
		reader->Update();
		reader->GetMetaDataDictionary();
		gdcmIO->GetMetaDataDictionary();// 读取头文件信息;

		//信息赋值
		char* name = new char[50];
		char* patientID = new char[50];
		char* time = new char[50];
		char* manufacture = new char[50];
		char* modility = new char[50];
		char* hospital = new char[50];
		char* sex = new char[50];
		char* age = new char[50];
		char* description = new char[100];
		

		
		
		int pixelType = gdcmIO->GetPixelType();
		int componentType = gdcmIO->GetComponentType();
		int fileType = gdcmIO->GetFileType();
		ImageIOType::ByteOrder byteOrder;
		byteOrder = gdcmIO->GetByteOrder();
		
		unsigned int dim = 0;
		gdcmIO->GetDimensions(dim);
		ImageIOType::SizeType imgsize;
		imgsize = gdcmIO->GetImageSizeInPixels();
		int componetSize = gdcmIO->GetComponentSize();
		int dimension = gdcmIO->GetNumberOfDimensions();
		int ori = 0;
	
		gdcmIO->GetOrigin(ori);
		int spa = 0;

		gdcmIO->GetPatientSex(sex);
		gdcmIO->GetPatientAge(age);
		gdcmIO->GetStudyDescription(description);
		gdcmIO->GetSpacing(spa);
		gdcmIO->GetPatientName(name);
		gdcmIO->GetModality(modility);
		gdcmIO->GetPatientID(patientID);
		gdcmIO->GetManufacturer(manufacture);
		gdcmIO->GetStudyDate(time);
		ImageIOType::TCompressionType compressType;
		compressType = gdcmIO->GetCompressionType();
		gdcmIO->GetInstitution(hospital);
		ImageType::SpacingType spacetype;
		spacetype = reader->GetOutput()->GetSpacing();
		ImageType::PointType origin;
		origin = reader->GetOutput()->GetOrigin();
		
		
		
		cout << "name:" << name << endl;
		cout << "age:" << age << endl;
		cout << "sex:" << sex << endl;
		cout << "description:" << description << endl;
		cout << "hospital:" << hospital << endl;
		cout << "modility:" << modility << endl;
		cout << "manfacture:" << manufacture << endl;
		cout << "dim:" << dim << endl;
		cout << "origin:" << origin << endl;
		cout << "Time:" << time << endl;
		cout << "patientID:" << patientID << endl;
		
	}
	catch (const itk::ExceptionObject& excp)
	{
		cout << " Reading Exceptaion Caught" << endl;
		cout << excp.what() << endl;
		
		return EXIT_FAILURE;
	}
	

結果は次のとおりです。

Snipaste_2020-07-11_10-42-43.png

上記の患者の年齢、性別、IDの基本情報に加えて、itkGDCMImageIOを使用て、より多くの患者関連情報を取得します。ここでは、itkGDCMImageIO.hソースコードから次の関数を取得ます。参照できます。

Snipaste_2020-07-11_11-54-48.png

VTKはDICOMを読みました

vTKは関連するDICOM読み取りクラスをカプセル化するため、DICOMの読み取りは比較的簡単です。vtkDICOMImageReader。直接操作できます。

VTKは単一のDICOMファイルを読み取り、それをプレビューします

  • vtkDICOMImageReader
#include<vtkSmartPointer.h>
#include<vtkImageViewer2.h>
#include<vtkDICOMImageReader.h>
#include<vtkRenderWindow.h>
#include<vtkRenderWindowInteractor.h>
#include<vtkRenderer.h>
#include<iostream>
#include<string.h>
#include<vtkAutoInit.h>


VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);


int main()
{
	using namespace std;
	
	string OpenPath = "D:/Data_Training/Dicom_data/215020265/AT000001.151955287.dcm";
	
	vtkSmartPointer<vtkDICOMImageReader> reader =
		vtkSmartPointer<vtkDICOMImageReader>::New();
	reader->SetFileName(OpenPath.c_str());
	reader->Update();


	vtkSmartPointer<vtkImageViewer2> imageViewer =
		vtkSmartPointer<vtkImageViewer2>::New();
	imageViewer->SetInputConnection(reader->GetOutputPort());

	vtkSmartPointer<vtkRenderWindowInteractor> renWin =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	imageViewer->SetupInteractor(renWin);
	imageViewer->Render();
	imageViewer->GetRenderer()->ResetCamera();
	imageViewer->Render();

	renWin->Start();

	return EXIT_SUCCESS;
}

インタラクティブウィンドウが追加されているため、ズームインとズームアウトを使用できます

VTKiMAge1.gif

VTKはシリアルDICOMファイルを読み取り、プレビューします

  • vtkDICOMImageReader

使用法は単一シートの読み取りに似ていますが、違いはシーケンス図で読み取られるフォルダーであり、単一シートは単一のDICOMを読み取ります。

#include<vtkSmartPointer.h>
#include<vtkImageViewer2.h>
#include<vtkDICOMImageReader.h>
#include<vtkRenderWindow.h>
#include<vtkRenderWindowInteractor.h>
#include<vtkRenderer.h>
#include<vtkTextProperty.h>
#include<vtkTextMapper.h>
#include<vtkActor2D.h>
#include<vtkInteractorStyleImage.h>
#include<vtkObjectFactory.h>
#include<iostream>
#include<string.h>
#include<vtkAutoInit.h>
#include<sstream>


VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType)

using namespace std;
class StatusMessage{
    
    
public:
	static std::string Format(int slice, int maxSlice)
	{
    
    
		std::stringstream tmp;
		tmp << "Slice Number  " << slice + 1 << "/" << maxSlice + 1;
		
		return tmp.str();
	}

};

// Define own interation style;
class myVtkInteractorStyleImage : public vtkInteractorStyleImage
{
    
    
public:
	static myVtkInteractorStyleImage* New();
	vtkTypeMacro(myVtkInteractorStyleImage, vtkInteractorStyleImage);
	
protected:
	vtkImageViewer2* _ImageViewer;
	vtkTextMapper* _StatusMapper;
	int _Slice;
	int _MinSlice;
	int _MaxSlice;
	
public:
	void SetImageViewer(vtkImageViewer2* imageViwer)
	{
    
    
		_ImageViewer = imageViwer;
		_MinSlice = imageViwer->GetSliceMin();
		_MaxSlice = imageViwer->GetSliceMax();
		_Slice = _MinSlice;
		
		cout << "Slice : Min = " << _MinSlice << ", Max = " << _MaxSlice << endl;

	}
	
	void SetStatusMapper(vtkTextMapper* statusMapper)
	{
    
    
		_StatusMapper = statusMapper;
	}
	
protected:
	void MoveSliceForward()
	{
    
    
		if (_Slice<_MaxSlice)
		{
    
    
			_Slice += 1;
			cout << " MoveSliceForward::Slice = " << _Slice << endl;
			_ImageViewer->SetSlice(_Slice);
			std::string msg = StatusMessage::Format(_Slice, _MaxSlice);
			_StatusMapper->SetInput(msg.c_str());
			_ImageViewer->Render();

		}
	}

	void MoveSliceBackward()
	{
    
    
		if(_Slice>_MinSlice)
		{
    
    
			_Slice -= 1;
			cout << "MoveSliceBackward::Slice = " << _Slice << endl;
			_ImageViewer->SetSlice(_Slice);
			std::string msg = StatusMessage::Format(_Slice, _MaxSlice);
			_StatusMapper->SetInput(msg.c_str());
			_ImageViewer->Render();

		}
	}

	virtual void OnKeyDown()
	{
    
    
		string key = this->GetInteractor()->GetKeySym();
		if (key.compare("Up") == 0)
		{
    
    
			MoveSliceForward();
		}
		else if (key.compare("Down") == 0)
		{
    
    
			MoveSliceBackward();
		}
		vtkInteractorStyleImage::OnKeyDown();
		
	}

	virtual void OnMouseWheelForward()
	{
    
    
		MoveSliceForward();
	}
	
	virtual void OnMouseWheelBackward()
	{
    
    
		if (_Slice > _MinSlice)
		{
    
    
			MoveSliceBackward();
		}
	}
};


vtkStandardNewMacro(myVtkInteractorStyleImage);



int main()
{
    
    
	using namespace std;
	
	string OpenPath = "D:/Data_Training/Dicom_data/215020265/";
	
	vtkSmartPointer<vtkDICOMImageReader> reader =
		vtkSmartPointer<vtkDICOMImageReader>::New();
	reader->SetDirectoryName(OpenPath.c_str());
	reader->Update();
	

	vtkSmartPointer<vtkImageViewer2> imageViewer =
		vtkSmartPointer<vtkImageViewer2>::New();
	imageViewer->SetInputConnection(reader->GetOutputPort());



	//Slice Status
	vtkSmartPointer<vtkTextProperty> sliceTextProp =
		vtkSmartPointer<vtkTextProperty>::New();
	sliceTextProp->SetFontFamilyToCourier();
	sliceTextProp->SetFontSize(20);
	sliceTextProp->SetVerticalJustificationToBottom();
	sliceTextProp->SetJustificationToLeft();

	vtkSmartPointer<vtkTextMapper> sliceTextMapper =
		vtkSmartPointer<vtkTextMapper>::New();
	string msg = StatusMessage::Format(imageViewer->GetSliceMin(), imageViewer->GetSliceMax());
	sliceTextMapper->SetInput(msg.c_str());
	cout << "msg" << msg.c_str() << endl;

	sliceTextMapper->SetTextProperty(sliceTextProp);
	
	vtkSmartPointer<vtkActor2D> sliceTextActor =
		vtkSmartPointer<vtkActor2D>::New();
	sliceTextActor->SetMapper(sliceTextMapper);
	sliceTextActor->SetPosition(15, 10);
	

	//usage hint message;
	vtkSmartPointer<vtkTextProperty> usageTextProp =
		vtkSmartPointer<vtkTextProperty>::New();
	usageTextProp->SetFontFamilyToCourier();
	usageTextProp->SetFontSize(14);
	usageTextProp->SetVerticalJustificationToTop();
	usageTextProp->SetJustificationToLeft();
	
	vtkSmartPointer<vtkTextMapper> usageTextMapper =
		vtkSmartPointer<vtkTextMapper>::New();
	usageTextMapper->SetInput("Slice with mouse wheel\n or Up/Down-Key\n =Zoom weh pressed right\n mouse button while dragging");
	usageTextMapper->SetTextProperty(usageTextProp);
	
	vtkSmartPointer<vtkActor2D> usageTextActor =
		vtkSmartPointer <vtkActor2D>::New();
	usageTextActor->SetMapper(usageTextMapper);
	usageTextActor->GetPositionCoordinate()->SetCoordinateSystemToNormalizedDisplay();
	usageTextActor->GetPositionCoordinate()->SetValue(0.05, 0.95);


	vtkSmartPointer<myVtkInteractorStyleImage> myInteractorStyle =
		vtkSmartPointer<myVtkInteractorStyleImage>::New();
	
	myInteractorStyle->SetImageViewer(imageViewer);
	myInteractorStyle->SetStatusMapper(sliceTextMapper);


	vtkSmartPointer<vtkRenderWindowInteractor> renWin =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	imageViewer->SetupInteractor(renWin);
	renWin->SetInteractorStyle(myInteractorStyle);

	imageViewer->GetRenderer()->AddActor2D(sliceTextActor);
	imageViewer->GetRenderer()->AddActor2D(usageTextActor);


	imageViewer->Render();
	imageViewer->GetRenderer()->ResetCamera();
	imageViewer->Render();

	renWin->Start();

	return EXIT_SUCCESS;
}

コードは、カスタムインタラクションクラスが定義されている公式から抜粋したもので、マウスをスライドするかボタンを押すことで置き換えることができます。また、vtkTextMapperクラスを介して2つのテキストコメントがインターフェイスに追加されます。これは、ユーザーのガイドに便利です。

プレビュー効果は次のとおりです。

VTKimage2.gif
(記事は最初に公開アカウントで公開されました:Z氏のメモ

参照:

1、https://itk.org/Doxygen/html/classitk_1_1ImageSeriesReader.html

2、https://lorensen.github.io/VTKExamples/site/Cxx/IO/ReadDICOMSeries/ `

おすすめ

転載: blog.csdn.net/weixin_42512684/article/details/107461223