#include <strstream>
#include <string>
#include <vtkDICOMImageReader.h>
#include <vtkStringArray.h>
#include <vtkDirectory.h>
#include <vtkImageThreshold.h>
#include <vtkImageShiftScale.h>
#include <vtkImageReslice.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkImageViewer2.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkPlane.h>
#include <vtkCutter.h>
#include <vtkActor.h>
#include <vtkCommand.h>
#include <vtkSmartPointer.h>
#include <vtkMatrix4x4.h>
#include <vtkInteractorObserver.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkImageData.h>
#include <vtkImageActor.h>
#include "vtkTransformPolyDataFilter.h"
#include <vtkCamera.h>
#include <vtkMath.h>
#include <vtkTransform.h>
#include <vtkTextActor.h>
#include <vtkActor2D.h>
#include <vtkPolyDataMapper2D.h>
#include <vtkProperty2D.h>
#include <vtkImageChangeInformation.h>
const double sphereCenter[3]={74, 219, 70};
const double AxialMatrix[] = { 1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0 };
const double SagittalMatrix[] = { 0.0, 0.0, 1.0, 0.0,
0.0, 1.0, 0.0, 0.0,
-1.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 1.0 };
const double CoronalMatrix[] = { 1.0, 0.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, -1.0, 0.0, 0.0,
0.0, 0.0, 0.0, 1.0 };
const double ObliqueMatrix[] = { 0.0, -0.515038, 0.857167, 0.0,
0.0, 0.857167, 0.515038, 0.0,
-1.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 1.0 };
class ResliceRender;
class KeyCallback : public vtkCommand
{
public:
static KeyCallback* New()
{
return new KeyCallback();
}
void Execute(vtkObject* caller, unsigned long eventId, void *calldata);
void SetCallbackData(ResliceRender* reslice);
protected:
ResliceRender* _reslice;
};
class ResliceRender
{
public:
typedef enum _ORIENTATION
{
AXIAL = 0,
SAGITTAL = 1,
CORONAL = 2,
OBLIQUE = 3
} ORIENTATION;
ResliceRender()
{
_orientation=AXIAL;
}
~ResliceRender()
{
_transform->Delete();
_reader->Delete();
_reslice->Delete();
_interactor->Delete();
_imageViewer->Delete();
_sphere->Delete();
_sphereMapper->Delete();
_sphereActor->Delete();
_plane->Delete();
_cutter->Delete();
_polyTransform->Delete();
_ROIMapper->Delete();
_ROIActor->Delete();
_annotation->Delete();
}
void CreatePipeline(const char* fileName)
{
vtkProperty2D* props;
bool b = s.
Sort( files );
if( !b )
{
std::cerr << "Failed to sort:" << fileName << std::endl;
}
vtkStringArray *vtkfiles = vtkStringArray::New();
std::vector< std::string >::const_iterator it = sorted.begin();
for( ; it != sorted.end(); ++it)
{
const std::string &f = *it;
vtkfiles->InsertNextValue( f.c_str() );
}
_reader->SetFileNames( vtkfiles );
_reader->Update();
const vtkFloatingPointType *spacing = _reader->GetOutput()->GetSpacing();
vtkImageChangeInformation *v16 = vtkImageChangeInformation::New();
#if (VTK_MAJOR_VERSION >= 6)
v16->SetInputConnection( _reader->GetOutputPort() );
#else
v16->SetInput( _reader->GetOutput() );
#endif
v16->SetOutputSpacing( spacing[0], spacing[1], ippzspacing );
v16->Update();
_threshold=vtkImageThreshold::New();
_threshold->ThresholdByUpper(-3024.0);
_threshold->ReplaceOutOn();
_threshold->SetOutValue(0.0);
_threshold->SetInputConnection(v16->GetOutputPort());
_shift=vtkImageShiftScale::New();
_shift->SetShift(0);
_shift->SetScale(1);
_shift->SetInputConnection(_threshold->GetOutputPort());
vtkSmartPointer<vtkMatrix4x4> matrix =
vtkSmartPointer<vtkMatrix4x4>::New();
matrix->Identity();
_transform = vtkTransform::New();
_transform->SetMatrix(matrix);
_reslice = vtkImageReslice::New();
_reslice->SetOutputDimensionality(3);
_reslice->SetResliceAxes(matrix);
_reslice->SetInputConnection(_shift->GetOutputPort());
_sphere=vtkSphereSource::New();
_sphere->SetRadius(7.0);
_sphere->SetThetaResolution(16);
_sphere->SetPhiResolution(16);
_sphere->SetCenter(sphereCenter[0], sphereCenter[1], sphereCenter[2]);
_sphereMapper=vtkPolyDataMapper::New();
_sphereMapper->SetInputConnection(_sphere->GetOutputPort());
_sphereActor=vtkActor::New();
_sphereActor->SetMapper(_sphereMapper);
_sphereActor->PickableOff();
_sphereActor->GetProperty()->SetColor(1.0, 0.0, 0.0);
_sphereActor->GetProperty()->SetEdgeColor(1.0, 0.0, 0.0);
_sphereActor->GetProperty()->SetDiffuseColor(1.0, 0.0, 0.0);
_sphereActor->SetVisibility(true);
_plane = vtkPlane::New();
_plane->SetNormal(0.0, 0.0, 1.0);
_cutter = vtkCutter::New();
_cutter->SetInputConnection(_sphere->GetOutputPort());
_cutter->SetCutFunction(_plane);
_cutter->GenerateCutScalarsOn();
_cutter->SetValue(0, 0.5);
_polyTransform = vtkTransformPolyDataFilter::New();
_polyTransform->SetTransform(_transform);
_polyTransform->SetInputConnection(_cutter->GetOutputPort());
_ROIMapper = vtkPolyDataMapper2D::New();
_ROIMapper->SetInputConnection(_polyTransform->GetOutputPort());
vtkCoordinate* coordinate = vtkCoordinate::New();
coordinate->SetCoordinateSystemToWorld();
_ROIMapper->SetTransformCoordinate(coordinate);
_ROIActor = vtkActor2D::New();
_ROIActor->SetMapper(_ROIMapper);
props=_ROIActor->GetProperty();
props->SetLineWidth(2);
props->SetOpacity(1.0);
props->SetColor(1.0, 0.0, 0.0);
_interactor = vtkRenderWindowInteractor::New();
_imageViewer = vtkImageViewer2::New();
_imageViewer->SetupInteractor(_interactor);
_imageViewer->SetSize(400, 400);
_imageViewer->SetColorWindow(1024);
_imageViewer->SetColorLevel(800);
_imageViewer->SetInputConnection(_reslice->GetOutputPort());
_imageViewer->GetImageActor()->SetOpacity(0.5);
_annotation = vtkTextActor::New();
_annotation->SetTextScaleModeToViewport();
_imageViewer->GetRenderer()->AddActor(_annotation);
_imageViewer->GetRenderer()->AddActor(_ROIActor);
vtkSmartPointer<KeyCallback> callback = vtkSmartPointer<KeyCallback>::New();
callback->SetCallbackData(this);
_interactor->AddObserver(vtkCommand::KeyPressEvent, callback);
_interactor->Initialize();
}
void Start()
{
_interactor->Start();
}
void ResetOrientation()
{
vtkSmartPointer<vtkMatrix4x4> matrix =
vtkSmartPointer<vtkMatrix4x4>::New();
matrix->Identity();
SetOrientation(matrix);
}
void SetOrientation(vtkMatrix4x4* matrix)
{
_reslice->SetResliceAxes(matrix);
_reslice->Update();
vtkMatrix4x4* inverse = vtkMatrix4x4::New();
vtkMatrix4x4::Invert(matrix, inverse);
_transform->SetMatrix(inverse);
_transform->Update();
}
void SetSlice(int slice)
{
std::strstream posString;
double center[3];
double spacing[3];
double origin[3];
double point[4];
double newPoint[4];
vtkImageData* imageData;
int newSlice;
imageData=vtkImageData::SafeDownCast(_reslice->GetOutput());
#if (VTK_MAJOR_VERSION >= 6)
assert(0);
#else
imageData->UpdateInformation();
#endif
_imageViewer->SetSlice(slice);
newSlice=GetSlice();
imageData->GetCenter(center);
imageData->GetSpacing(spacing);
imageData->GetOrigin(origin);
point[0]=center[0];
point[1]=center[1];
point[2]=(newSlice * spacing[2]) + origin[2];
point[3]=1.0;
vtkMatrix4x4* matrix=_reslice->GetResliceAxes();
vtkSmartPointer<vtkMatrix4x4> inverse =
vtkSmartPointer<vtkMatrix4x4>::New();
vtkMatrix4x4::Invert(matrix, inverse);
matrix->MultiplyPoint(point, newPoint);
_plane->SetOrigin(newPoint[0], newPoint[1], newPoint[2]);
posString << "Position: (" << newPoint[0] << ", " << newPoint[1]
<< ", " << newPoint[2] << ") Slice: " << newSlice;
_annotation->SetInput(posString.str());
_imageViewer->Render();
}
int GetSlice()
{
return _imageViewer->GetSlice();
}
void SetOrientation(ResliceRender::ORIENTATION orientation)
{
vtkCamera* camera=_imageViewer->GetRenderer()->GetActiveCamera();
double spacing[3];
double origin[3];
double point[4];
double newPoint[4];
double initialPosition;
double xDirCosine[3];
double yDirCosine[3];
double zDirCosine[3];
double normal[3];
vtkImageData* imageData;
vtkSmartPointer<vtkMatrix4x4> matrix =
vtkSmartPointer<vtkMatrix4x4>::New();
_orientation=orientation;
camera->SetViewUp(0.0, 1.0, 0.0);
imageData=vtkImageData::SafeDownCast(_reslice->GetInput());
#if (VTK_MAJOR_VERSION >= 6)
assert(0);
#else
imageData->UpdateInformation();
#endif
imageData->GetSpacing(spacing);
imageData->GetOrigin(origin);
point[0]=origin[0];
point[1]=origin[1];
point[2]=origin[2];
point[3]=1.0;
switch (_orientation)
{
case AXIAL:
matrix->DeepCopy(AxialMatrix);
initialPosition=sphereCenter[2];
break;
case CORONAL:
matrix->DeepCopy(CoronalMatrix);
initialPosition=sphereCenter[1];
break;
case SAGITTAL:
matrix->DeepCopy(SagittalMatrix);
initialPosition=sphereCenter[0];
break;
case OBLIQUE:
matrix->DeepCopy(ObliqueMatrix);
initialPosition=sphereCenter[2];
break;
}
matrix->MultiplyPoint(point, newPoint);
matrix->SetElement(0, 3, newPoint[0]);
matrix->SetElement(1, 3, newPoint[1]);
matrix->SetElement(2, 3, newPoint[2]);
ResetOrientation();
SetOrientation(matrix);
_reslice->GetResliceAxesDirectionCosines(xDirCosine, yDirCosine,
zDirCosine);
vtkMath::Cross(xDirCosine, yDirCosine, normal);
_plane->SetNormal(normal);
_reslice->SetOutputExtentToDefault();
_reslice->SetOutputSpacing(spacing[0], spacing[0], spacing[0]);
#if (VTK_MAJOR_VERSION >= 6)
_imageViewer->SetInputData(NULL);
#else
_imageViewer->SetInput(NULL);
#endif
_imageViewer->SetInputConnection(_reslice->GetOutputPort());
_imageViewer->GetRenderer()->ResetCameraClippingRange();
_imageViewer->GetRenderer()->ResetCamera();
SetSlice( (int)(initialPosition / spacing[0]));
}
vtkRenderWindowInteractor* GetInteractor()
{
return _interactor;
}
protected:
ORIENTATION _orientation;
vtkImageThreshold* _threshold;
vtkImageShiftScale* _shift;
vtkImageReslice* _reslice;
vtkRenderWindowInteractor* _interactor;
vtkImageViewer2* _imageViewer;
vtkSphereSource* _sphere;
vtkPolyDataMapper* _sphereMapper;
vtkActor* _sphereActor;
vtkPlane* _plane;
vtkCutter* _cutter;
vtkTransform* _transform;
vtkTransformPolyDataFilter* _polyTransform;
vtkPolyDataMapper2D* _ROIMapper;
vtkActor2D* _ROIActor;
vtkTextActor* _annotation;
};
void KeyCallback::Execute(vtkObject* caller, unsigned long eventId, void *calldata)
{
(void)caller;
(void)eventId;
(void)calldata;
std::string sym=_reslice->GetInteractor()->GetKeySym();
if (!sym.compare("Up"))
{
_reslice->SetSlice(_reslice->GetSlice() + 1);
}
else if (!sym.compare("Down"))
{
_reslice->SetSlice(_reslice->GetSlice() - 1);
}
else if ((!sym.compare("A")) || (!sym.compare("a")))
{
_reslice->SetOrientation(ResliceRender::AXIAL);
}
else if ((!sym.compare("C")) || (!sym.compare("c")))
{
_reslice->SetOrientation(ResliceRender::CORONAL);
}
else if ((!sym.compare("S")) || (!sym.compare("s")))
{
_reslice->SetOrientation(ResliceRender::SAGITTAL);
}
else if ((!sym.compare("O")) || (!sym.compare("o")))
{
_reslice->SetOrientation(ResliceRender::OBLIQUE);
}
}
void KeyCallback::SetCallbackData(ResliceRender* reslice)
{
_reslice=reslice;
}
int main(int argc, char *argv[])
{
ResliceRender render;
if (argc == 1)
{
std::string dir3 = root;
dir3 += "/gdcmSampleData/ForSeriesTesting/Dentist/images/";
render.CreatePipeline(dir3.c_str());
}
else
{
render.CreatePipeline(argv[1]);
}
render.SetOrientation(ResliceRender::AXIAL);
render.Start();
return EXIT_SUCCESS;
}