利用VTK進行CT切片提取

#include <vtkSmartPointer.h>
#include <vtkObjectFactory.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkActor.h>
// headers needed for this example
#include <vtkImageViewer2.h>
#include <vtkDICOMImageReader.h>
#include <vtkInteractorStyleImage.h>
#include <vtkActor2D.h>
#include <vtkTextProperty.h>
#include <vtkTextMapper.h>
#include <vtkContourFilter.h>
#include <vtkPolyDataNormals.h>
#include <vtkPolyDataMapper.h>
#include <vtkOutlineFilter.h>
#include <vtkCamera.h>
#include <vtkProperty.h>
#include <vtkPlaneWidget.h>
#include <vtkImageData.h>
#include <vtkAutoInit.h>
#include <vtkImageReslice.h>
#include <vtkImageMapToColors.h>
#include <vtkMatrix4x4.h>
#include <vtkAxesActor.h>
#include <vtkPlaneSource.h>
#include <vtkCaptionActor2D.h>
#include <vtkNamedColors.h>
#include <vtkLookupTable.h>
#include <vtkImageActor.h>

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

int extent[6];
double spacing[3];
double origin[3];

vtkNew<vtkActor> m_planeActor1;

class vtkImageInteractionCallback : public vtkCommand
{
public:
	static vtkImageInteractionCallback *New()
	{
		return new vtkImageInteractionCallback;
	}

	vtkImageInteractionCallback()
	{
		this->Slicing = 0;
		this->ImageReslice = 0;
		this->Interactor = 0;
	}

	void SetImageReslice(vtkImageReslice *reslice)
	{
		this->ImageReslice = reslice;
	}

	void SetImageMapToColors(vtkImageMapToColors *mapToColors)
	{
		this->mapToColors = mapToColors;
	}

	vtkImageReslice *GetImageReslice()
	{
		return this->ImageReslice;
	}

	void SetInteractor(vtkRenderWindowInteractor *interactor)
	{
		this->Interactor = interactor;
	}

	vtkRenderWindowInteractor *GetInteractor()
	{
		return this->Interactor;
	}

	virtual void Execute(vtkObject *, unsigned long event, void *)
	{
		vtkRenderWindowInteractor *interactor = this->GetInteractor();

		int lastPos[2];
		interactor->GetLastEventPosition(lastPos);
		int currPos[2];
		interactor->GetEventPosition(currPos);

		if (event == vtkCommand::LeftButtonPressEvent)
		{
			this->Slicing = 1;

			cout << currPos[0] << "  " << currPos[1] << endl;;
		}
		else if (event == vtkCommand::LeftButtonReleaseEvent)
		{
			this->Slicing = 0;
		}
		else if (event == vtkCommand::MouseMoveEvent)
		{
			if (this->Slicing)
			{
				vtkImageReslice *reslice = this->ImageReslice;

				// Increment slice position by deltaY of mouse
				int deltaY = lastPos[1] - currPos[1];

				reslice->Update();
				double sliceSpacing = reslice->GetOutput()->GetSpacing()[2];
				vtkMatrix4x4 *matrix = reslice->GetResliceAxes();
				// move the center point that we are slicing through
				double point[4];
				double center[4];
				point[0] = 0.0;
				point[1] = 0.0;
				point[2] = sliceSpacing * deltaY;
				point[3] = 1.0;
				matrix->MultiplyPoint(point, center);

				cout << point[2] << "  " << center[0] << "  " << center[1] << "  " << center[2] << endl;
				matrix->SetElement(0, 3, center[0]);
				matrix->SetElement(1, 3, center[1]);
				matrix->SetElement(2, 3, center[2]);
				mapToColors->Update();
				interactor->Render();
			}
			else
			{
				vtkInteractorStyle *style = vtkInteractorStyle::SafeDownCast(
					interactor->GetInteractorStyle());
				if (style)
				{
					style->OnMouseMove();
				}
			}
		}
		else if (event == vtkCommand::MouseWheelForwardEvent)
		{

		}
		else if (event == vtkCommand::MouseWheelBackwardEvent)
		{

		}
	}
private:
	int Slicing;
	vtkImageReslice *ImageReslice;
	vtkRenderWindowInteractor *Interactor;
	vtkImageMapToColors *mapToColors;
};

//畫座標軸
void createAxes(vtkSmartPointer<vtkRenderer> renderer)
{
	//軸
	vtkSmartPointer<vtkAxesActor> axes = vtkSmartPointer<vtkAxesActor>::New();
	axes->SetTotalLength(400.0, 400.0, 400.0);
	axes->SetShaftType(vtkAxesActor::CYLINDER_SHAFT);//設置軸類型圓柱形狀
	axes->SetCylinderRadius(0.01);
	axes->GetXAxisCaptionActor2D()->SetWidth(0.01);
	axes->GetYAxisCaptionActor2D()->SetWidth(0.01);
	axes->GetZAxisCaptionActor2D()->SetWidth(0.01);

	renderer->AddActor(axes);
}


int main(int argc, char* argv[])
{
	//// Verify input arguments
	//if (argc != 2)
	//{
	//	std::cout << "Usage: " << argv[0]
	//		<< " FolderName" << std::endl;
	//	return EXIT_FAILURE;
	//}

	vtkRenderer *aRenderer = vtkRenderer::New();
	vtkRenderer *rRenderer = vtkRenderer::New();

	vtkRenderWindow *renWin1 = vtkRenderWindow::New();
	vtkRenderWindow *renWin2 = vtkRenderWindow::New();
	renWin1->AddRenderer(aRenderer);
	renWin2->AddRenderer(rRenderer);

	vtkRenderWindowInteractor *iren1 = vtkRenderWindowInteractor::New();
	vtkRenderWindowInteractor *iren2 = vtkRenderWindowInteractor::New();
	iren1->SetRenderWindow(renWin1);
	iren2->SetRenderWindow(renWin2);

	createAxes(aRenderer);
	//createAxes(rRenderer);

	vtkDICOMImageReader *reader = vtkDICOMImageReader::New();
	reader->SetDataByteOrderToLittleEndian();
	reader->SetDirectoryName("d:/se1");
	reader->Update();
	//v16->SetDataSpacing(3.2, 3.2, 1.5);

	reader->GetOutput()->GetExtent(extent);
	reader->GetOutput()->GetSpacing(spacing);
	reader->GetOutput()->GetOrigin(origin);


	cout << extent[0] << "  " << extent[1] << "  " << extent[2] << "  "
		<< extent[3] << "  " << extent[4] << "  " << extent[5] << "  " << endl;

	cout << spacing[0] << "  " << spacing[1] << "  " << spacing[2] << "  " << endl;

	cout << origin[0] << "  " << origin[1] << "  " << origin[2] << "  " << endl;


	//***********************畫垂直於X軸的平面***********************
	vtkSmartPointer<vtkPlaneSource> planeSource = vtkSmartPointer<vtkPlaneSource>::New();
	planeSource->SetCenter(0, 0, 0);
	planeSource->SetPoint1(0, 0, 200);
	planeSource->SetPoint2(0, 200, 0);
	planeSource->Update();
	vtkPolyData *plane = planeSource->GetOutput();
	vtkSmartPointer<vtkPolyDataMapper> planeMap = vtkSmartPointer<vtkPolyDataMapper>::New();
	planeMap->SetInputData(plane);
	//vtkSmartPointer<vtkActor> planeActor = vtkSmartPointer<vtkActor>::New();
	m_planeActor1->SetMapper(planeMap);
	vtkSmartPointer<vtkNamedColors> planeColor = vtkSmartPointer<vtkNamedColors>::New();
	m_planeActor1->GetProperty()->SetColor(planeColor->GetColor3d("Red").GetData());
	aRenderer->AddActor(m_planeActor1);


	vtkContourFilter *skinExtractor = vtkContourFilter::New();
	skinExtractor->SetInputConnection(reader->GetOutputPort());
	//skinExtractor->SetValue(0, 500);
	vtkPolyDataNormals *skinNormals = vtkPolyDataNormals::New();
	skinNormals->SetInputConnection(skinExtractor->GetOutputPort());
	//skinNormals->SetFeatureAngle(60.0);
	vtkPolyDataMapper *skinMapper = vtkPolyDataMapper::New();
	skinMapper->SetInputConnection(skinNormals->GetOutputPort());
	skinMapper->ScalarVisibilityOff();
	vtkActor *skin = vtkActor::New();
	skin->SetMapper(skinMapper);


	vtkOutlineFilter *outlineData = vtkOutlineFilter::New();
	outlineData->SetInputConnection(reader->GetOutputPort());
	vtkPolyDataMapper *mapOutline = vtkPolyDataMapper::New();
	mapOutline->SetInputConnection(outlineData->GetOutputPort());
	vtkActor *outline = vtkActor::New();
	outline->SetMapper(mapOutline);
	outline->GetProperty()->SetColor(0, 0, 0);


	vtkCamera *aCamera = vtkCamera::New();
	aCamera->SetViewUp(0, 0, -1);
	aCamera->SetPosition(0, 1, 0);
	aCamera->SetFocalPoint(0, 0, 0);
	aCamera->ComputeViewPlaneNormal();


	aRenderer->AddActor(outline);
	aRenderer->AddActor(skin);
	aRenderer->SetActiveCamera(aCamera);
	aRenderer->ResetCamera();
	aCamera->Dolly(1.5);


	aRenderer->ResetCameraClippingRange();
	aRenderer->SetBackground(1.0, 1.0, 1.0);
	renWin1->SetSize(640, 480);

	// Initialize the event loop and then start it.
	iren1->Initialize();



	double center[3];
	center[0] = origin[0] + spacing[0] * 0.5 * (extent[0] + extent[1]);
	center[1] = origin[1] + spacing[1] * 0.5 * (extent[2] + extent[3]);
	center[2] = origin[2] + spacing[2] * 0.5 * (extent[4] + extent[5]);

	static double axialElements[16] = {
		1, 0, 0, 0,
		0, 1, 0, 0,
		0, 0, 1, 0,
		0, 0, 0, 1
	};

	vtkSmartPointer<vtkMatrix4x4> resliceAxes =
		vtkSmartPointer<vtkMatrix4x4>::New();
	resliceAxes->DeepCopy(axialElements);

	resliceAxes->SetElement(0, 3, center[0]);
	resliceAxes->SetElement(1, 3, center[1]);
	resliceAxes->SetElement(2, 3, center[2]);

	vtkSmartPointer<vtkImageReslice> reslice =
		vtkSmartPointer<vtkImageReslice>::New();
	reslice->SetInputConnection(reader->GetOutputPort());
	reslice->SetOutputDimensionality(2);
	reslice->SetResliceAxes(resliceAxes);
	reslice->SetInterpolationModeToLinear();

	vtkSmartPointer<vtkLookupTable> colorTable =
		vtkSmartPointer<vtkLookupTable>::New();
	colorTable->SetRange(0, 1000);
	colorTable->SetValueRange(0.0, 1.0);
	colorTable->SetSaturationRange(0.0, 0.0);
	colorTable->SetRampToLinear();
	colorTable->Build();

	vtkSmartPointer<vtkImageMapToColors> colorMap =
		vtkSmartPointer<vtkImageMapToColors>::New();
	colorMap->SetLookupTable(colorTable);
	colorMap->SetInputConnection(reslice->GetOutputPort());
	colorMap->Update();

	vtkSmartPointer<vtkImageActor> imgActor =
		vtkSmartPointer<vtkImageActor>::New();
	imgActor->SetInputData(colorMap->GetOutput());

	vtkSmartPointer<vtkRenderer> renderer =
		vtkSmartPointer<vtkRenderer>::New();
	rRenderer->AddActor(imgActor);
	rRenderer->SetBackground(1.0, 1.0, 1.0);
	renWin2->SetSize(640, 480);
	iren2->Initialize();


	vtkSmartPointer<vtkInteractorStyleImage> imagestyle =
		vtkSmartPointer<vtkInteractorStyleImage>::New();

	iren2->SetInteractorStyle(imagestyle);
	iren2->SetRenderWindow(renWin2);
	iren2->Initialize();

	vtkSmartPointer<vtkImageInteractionCallback> callback =
		vtkSmartPointer<vtkImageInteractionCallback>::New();
	callback->SetImageReslice(reslice);
	callback->SetInteractor(iren2);
	callback->SetImageMapToColors(colorMap);

	imagestyle->AddObserver(vtkCommand::MouseMoveEvent, callback);
	imagestyle->AddObserver(vtkCommand::LeftButtonPressEvent, callback);
	imagestyle->AddObserver(vtkCommand::LeftButtonReleaseEvent, callback);

	iren1->Start();
	iren2->Start();

	reader->Delete();
	skinExtractor->Delete();
	skinNormals->Delete();
	skinMapper->Delete();
	skin->Delete();
	outlineData->Delete();
	mapOutline->Delete();
	outline->Delete();
	aCamera->Delete();
	iren1->Delete();
	renWin1->Delete();
	aRenderer->Delete();

	return 0;
}

//垂直於X軸的截面
static double sagittalElements[16] = {
0, 0,-1, 0,
1, 0, 0, 0,
0,-1, 0, 0,
0, 0, 0, 1 };

//垂直於Y軸的截面
static double coronalElements[16] = {
1, 0, 0, 0,
0, 0, 1, 0,
0,-1, 0, 0,
0, 0, 0, 1 };

//垂直於Z軸的截面
static double sagittalElements[16] = {
1, 0,0, 0,
0, 1, 0, 0,
0,0, 1, 0,
0, 0, 0, 1 };

如果還需要旋轉.
例如:在垂直於X軸的截面的基礎上,繞Z軸旋轉30度(符號滿足右手定則),需要左乘一個繞Z軸的旋轉矩陣

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章