1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
5 - University of LYON http://www.universite-lyon.fr/
6 - Léon Bérard cancer center http://www.centreleonberard.fr
7 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the copyright notices for more information.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
25 #include "clitkCommon.h"
31 #include <itksys/SystemTools.hxx>
34 #include <vtkVersion.h>
35 #include <vtkSmartPointer.h>
36 #include <vtkFloatArray.h>
37 #include <vtkPointData.h>
38 #include <vtkPolyData.h>
39 #include <vtkPolyDataReader.h>
40 #include <vtkOBJReader.h>
41 #include <vtkImageData.h>
42 #include <vtkImageStencil.h>
43 #include <vtkLinearExtrusionFilter.h>
44 #include <vtkPolyDataToImageStencil.h>
45 #include <vtkMarchingCubes.h>
46 #include <vtkMetaImageWriter.h>
53 void vvMesh::AddMesh(vtkPolyData* p)
55 vtkPolyData * mesh=vtkPolyData::New();
57 meshes.push_back(mesh);
60 void vvMesh::ReadFromVTK(const char * filename)
62 std::string extension=itksys::SystemTools::GetFilenameLastExtension(std::string(filename));
63 if (extension == ".vtk" || extension== ".VTK") {
64 assert(GetNumberOfMeshes() == 0); ///We assume the object is empty
65 vtkSmartPointer<vtkPolyDataReader> r=vtkSmartPointer<vtkPolyDataReader>::New();
66 r->SetFileName(filename);
68 assert(r->GetOutput());
69 AddMesh(r->GetOutput());
70 } else if (extension == ".obj" || extension== ".OBJ") {
71 assert(GetNumberOfMeshes() == 0); ///We assume the object is empty
72 vtkSmartPointer<vtkOBJReader> r=vtkSmartPointer<vtkOBJReader>::New();
73 r->SetFileName(filename);
75 assert(r->GetOutput());
76 AddMesh(r->GetOutput());
78 assert (false) ; //shouldn't happen
80 assert(GetNumberOfMeshes() != 0); ///We assume the object is empty
81 structure_name=filename;
84 void vvMesh::RemoveMeshes()
86 for (std::vector<vtkPolyData*>::const_iterator i=meshes.begin(); i!=meshes.end(); i++)
88 meshes.erase(meshes.begin(),meshes.end());
91 void vvMesh::AddMask(vtkImageData* im)
93 assert(im->GetScalarType() == VTK_UNSIGNED_CHAR);
94 vtkImageData* image=vtkImageData::New();
95 image->ShallowCopy(im);
96 masks.push_back(image);
99 void vvMesh::RemoveMasks()
101 for (std::vector<vtkImageData*>::const_iterator i=masks.begin(); i!=masks.end(); i++)
103 masks.erase(masks.begin(),masks.end());
112 void vvMesh::CopyInformation(vvMesh::Pointer input)
117 structure_name=input->structure_name;
118 slice_spacing=input->slice_spacing;
121 void vvMesh::Print() const
123 std::cout << this << " : " << structure_name << std::endl << "RGB: " << r << "," << g << "," << b << std::endl;
124 for (std::vector<vtkPolyData*>::const_iterator i=meshes.begin(); i!=meshes.end(); i++) {
125 std::cout << (*i)->GetNumberOfPoints() << " points, " << (*i)->GetNumberOfCells() << " cells." << std::endl;
126 DDV((*i)->GetBounds(),6);
128 std::cout << "-------------------------" << std::endl << std::endl;
131 void vvMesh::ComputeMasks(vtkImageData* sample,bool extrude)
134 for (std::vector<vtkPolyData*>::iterator i=meshes.begin(); i!=meshes.end(); i++) {
135 vtkPolyData* mesh=*i;
136 double *bounds=mesh->GetBounds();
138 vtkSmartPointer<vtkImageData> binary_image=vtkSmartPointer<vtkImageData>::New();
139 #if VTK_MAJOR_VERSION <= 5
140 binary_image->SetScalarTypeToUnsignedChar();
142 ///Use the smallest mask in which the mesh fits
143 // Add two voxels on each side to make sure the mesh fits
144 double * samp_origin=sample->GetOrigin();
145 double * spacing=sample->GetSpacing();
146 binary_image->SetSpacing(spacing);
148 /// Put the origin on a voxel to avoid small skips
149 binary_image->SetOrigin(floor((bounds[0]-samp_origin[0])/spacing[0]-2)*spacing[0]+samp_origin[0],
150 floor((bounds[2]-samp_origin[1])/spacing[1]-2)*spacing[1]+samp_origin[1],
151 floor((bounds[4]-samp_origin[2])/spacing[2]-2)*spacing[2]+samp_origin[2]);
152 double * origin=binary_image->GetOrigin();
153 binary_image->SetExtent(0,ceil((bounds[1]-origin[0])/spacing[0]+4),
154 0,ceil((bounds[3]-origin[1])/spacing[1]+4),
155 0,ceil((bounds[5]-origin[2])/spacing[2])+4);
156 #if VTK_MAJOR_VERSION <= 5
157 binary_image->AllocateScalars();
159 binary_image->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
161 memset(binary_image->GetScalarPointer(),0,binary_image->GetDimensions()[0]*binary_image->GetDimensions()[1]*binary_image->GetDimensions()[2]*sizeof(unsigned char));
164 vtkSmartPointer<vtkPolyDataToImageStencil> sts=vtkSmartPointer<vtkPolyDataToImageStencil>::New();
165 //The following line is extremely important
166 //http://www.nabble.com/Bug-in-vtkPolyDataToImageStencil--td23368312.html#a23370933
167 sts->SetTolerance(0);
168 sts->SetInformationInput(binary_image);
171 vtkSmartPointer<vtkLinearExtrusionFilter> extrude=vtkSmartPointer<vtkLinearExtrusionFilter>::New();
172 #if VTK_MAJOR_VERSION <= 5
173 extrude->SetInput(mesh);
175 extrude->SetInputData(mesh);
177 ///We extrude in the -slice_spacing direction to respect the FOCAL convention
178 extrude->SetVector(0, 0, -slice_spacing);
179 #if VTK_MAJOR_VERSION <= 5
180 sts->SetInput(extrude->GetOutput());
182 sts->SetInputConnection(extrude->GetOutputPort());
185 #if VTK_MAJOR_VERSION <= 5
188 sts->SetInputData(mesh);
192 vtkSmartPointer<vtkImageStencil> stencil=vtkSmartPointer<vtkImageStencil>::New();
193 #if VTK_MAJOR_VERSION <= 5
194 stencil->SetStencil(sts->GetOutput());
195 stencil->SetInput(binary_image);
197 stencil->SetStencilConnection(sts->GetOutputPort());
198 stencil->SetInputData(binary_image);
201 this->AddMask(stencil->GetOutput());
204 vtkSmartPointer<vtkMetaImageWriter> w = vtkSmartPointer<vtkMetaImageWriter>::New();
205 w->SetInput(stencil->GetOutput());
206 w->SetFileName("binary.mhd");
212 void vvMesh::ComputeMeshes()
214 this->RemoveMeshes();
215 for (std::vector<vtkImageData*>::iterator i=masks.begin(); i!=masks.end(); i++) {
216 vtkSmartPointer<vtkMarchingCubes> marching = vtkSmartPointer<vtkMarchingCubes>::New();
217 #if VTK_MAJOR_VERSION <= 5
218 marching->SetInput(*i);
220 marching->SetInputData(*i);
222 marching->SetValue(0,0.5);
224 this->AddMesh(marching->GetOutput());
228 void vvMesh::propagateContour(vvImage::Pointer vf)
230 assert(this->GetNumberOfMeshes() == 1);
231 std::vector<vtkImageData*> sgrids=vf->GetVTKImages();
232 vtkSmartPointer<vtkPolyData> reference_mesh = vtkSmartPointer<vtkPolyData>::New();
233 reference_mesh->ShallowCopy(this->GetMesh(0));
234 this->RemoveMeshes();
236 for (std::vector<vtkImageData*>::iterator i=sgrids.begin();
237 i!=sgrids.end(); i++) {
238 vtkPolyData* new_mesh=vtkPolyData::New();
239 new_mesh->DeepCopy(reference_mesh);
240 double Ox=vf->GetOrigin()[0];
241 double Oy=vf->GetOrigin()[1];
242 double Oz=vf->GetOrigin()[2];
243 double Sx=vf->GetSpacing()[0];
244 double Sy=vf->GetSpacing()[1];
245 double Sz=vf->GetSpacing()[2];
246 int *dims=vf->GetVTKImages()[0]->GetDimensions();
247 assert((*i)->GetScalarType() == VTK_FLOAT); //vfs are assumed to be of float type
248 assert((*i)->GetNumberOfScalarComponents() == 3);
249 float * vector_data=reinterpret_cast<float*>((*i)->GetScalarPointer());
250 for (int j=0; j<new_mesh->GetNumberOfPoints(); j++) {
251 double* old=new_mesh->GetPoint(j);
252 int ix=(old[0]-Ox)/Sx;
253 int iy=(old[1]-Oy)/Sy;
254 int iz=(old[2]-Oz)/Sz;
255 float* vector=vector_data+(ix+iy*vf->GetSize()[0]+iz*vf->GetSize()[0]*vf->GetSize()[1])*3;
256 if (ix>=0 && ix < dims[0]
257 && iy>=0 && iy < dims[1]
258 && iz>=0 && iz < dims[2])
259 new_mesh->GetPoints()->SetPoint(j,old[0]+vector[0],old[1]+vector[1],old[2]+vector[2]);
261 this->AddMesh(new_mesh);
263 if (GetNumberOfMasks()) { //If the input mesh has a mask, use it to compute the warped meshes' masks
264 vtkSmartPointer<vtkImageData> ref_mask = vtkSmartPointer<vtkImageData>::New();
265 ref_mask->ShallowCopy(GetMask(0));
266 this->ComputeMasks(ref_mask);