1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
3 Main authors : XX XX XX
6 - University of LYON http://www.universite-lyon.fr/
7 - Léon Bérard cancer center http://www.centreleonberard.fr
8 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the copyright notices for more information.
14 It is distributed under dual licence
15 - BSD http://www.opensource.org/licenses/bsd-license.php
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
18 =========================================================================*/
21 #include "clitkXml2DicomRTStructFilter.h"
24 #include "../utilities/pugixml/pugixml.hpp"
28 #include "itkImageFileReader.h"
31 #include <vtkSmartPointer.h>
32 #include <vtkMetaImageWriter.h>
33 #include <vtkImageData.h>
34 #include <vtkPolygon.h>
35 #include <vtkAppendPolyData.h>
36 #include <vtkPointData.h>
39 #include "vtkPolyDataMapper.h"
40 #include "vtkPolyDataMapper2D.h"
41 #include "vtkRenderWindowInteractor.h"
42 #include "vtkPolyDataReader.h"
43 #include "vtkRenderWindow.h"
44 #include "vtkRenderer.h"
45 #include "vtkCamera.h"
46 #include "vtkProperty.h"
47 #include "vtkProperty2D.h"
48 #include <vtksys/SystemTools.hxx>
51 #include <vtkRTStructSetProperties.h>
52 #include <vtkGDCMPolyDataReader.h>
53 #include <vtkGDCMPolyDataWriter.h>
55 //--------------------------------------------------------------------
56 template<class PixelType>
57 clitk::Xml2DicomRTStructFilter<PixelType>::Xml2DicomRTStructFilter()
60 m_StructureSetFilename = "";
62 m_OutputFilename = "default-output.dcm";
64 //--------------------------------------------------------------------
67 //--------------------------------------------------------------------
68 template<class PixelType>
69 clitk::Xml2DicomRTStructFilter<PixelType>::~Xml2DicomRTStructFilter()
72 //--------------------------------------------------------------------
75 //--------------------------------------------------------------------
76 template<class PixelType>
77 void clitk::Xml2DicomRTStructFilter<PixelType>::Update()
79 // Check this is a RT-Struct
80 gdcm::Reader gdcm_reader;
81 gdcm_reader.SetFileName(m_StructureSetFilename.c_str());
82 if (!gdcm_reader.Read()) {
83 clitkExceptionMacro("Error could not open the file '" << m_StructureSetFilename << std::endl);
85 gdcm::MediaStorage ms;
86 ms.SetFromFile(gdcm_reader.GetFile());
87 if (ms != gdcm::MediaStorage::RTStructureSetStorage) {
88 clitkExceptionMacro("File '" << m_StructureSetFilename << "' is not a DICOM-RT-Struct file." << std::endl);
92 vtkSmartPointer<vtkGDCMPolyDataReader> reader = vtkGDCMPolyDataReader::New();
93 reader->SetFileName(m_StructureSetFilename.c_str());
96 //Check id use pixel is set and if imageMHD is present in such case
97 typedef itk::Image<double, 3> Input3DType;
98 typedef itk::ImageFileReader<Input3DType> InputReader3DType;
99 InputReader3DType::Pointer mhdReader = InputReader3DType::New();
101 if (m_ImageMHD != "") {
102 mhdReader->SetFileName(m_ImageMHD);
105 std::cout << "Set MHD image (option -j) when pixel is set" << std::endl;
111 vtkRTStructSetProperties * p = reader->GetRTStructSetProperties();
112 if (GetVerboseFlag()) {
113 std::cout << "Number of structures in the dicom-rt-struct : "
114 << p->GetNumberOfStructureSetROIs() << std::endl;
117 std::map<std::string, vtkSmartPointer<vtkAppendPolyData> > mapName2Data;
119 pugi::xml_document doc;
120 pugi::xml_parse_result result = doc.load_file(m_InputFilename.c_str());
122 std::cout << "ERROR: no result" << std::endl;
126 //Take the main dict and look for point_mm in each struct in each slice
127 pugi::xml_node mainDict = doc.child("plist").child("dict").child("array");
128 for (pugi::xml_node_iterator mainDictIt = mainDict.begin(); mainDictIt != mainDict.end(); ++mainDictIt) { //Look for all slice (one slice per dict)
129 if (!std::strcmp(mainDictIt->name(), "dict")) {
130 pugi::xml_node_iterator sliceDescriptionIt = mainDictIt->begin();
131 while (sliceDescriptionIt != mainDictIt->end() && std::abs(std::strcmp(sliceDescriptionIt->child_value(), "ImageIndex"))) //Look for the ImageIndex for the current slice
132 ++sliceDescriptionIt;
134 if (sliceDescriptionIt != mainDictIt->end()) { //take the following node to have the values
135 ++sliceDescriptionIt;
136 sliceNb = std::atoi(sliceDescriptionIt->child_value());
138 for (pugi::xml_node_iterator sliceIt = mainDictIt->child("array").begin(); sliceIt != mainDictIt->child("array").end(); ++sliceIt) { //Look for all struct in the current slice (one struct per dict)
139 if (!std::strcmp(sliceIt->name(), "dict")) {
140 pugi::xml_node_iterator structureIt = sliceIt->begin();
141 while (structureIt != sliceIt->end() && std::abs(std::strcmp(structureIt->child_value(), "Name"))) //Look for the name for the current struct
143 if (structureIt != sliceIt->end()) { //take the following node to have the values
145 std::string name(structureIt->child_value());
147 while (structureIt != sliceIt->end() && std::abs(std::strcmp(structureIt->child_value(), "Point_px"))) //Look for the Point_px for the current struct
150 while (structureIt != sliceIt->end() && std::abs(std::strcmp(structureIt->child_value(), "Point_mm"))) //Look for the Point_mm for the current struct
153 if (structureIt != sliceIt->end()) { //take the following node to have the values
155 // Insert all points for 1 struct into vtkPoints
156 vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
157 for (pugi::xml_node_iterator pointIt = structureIt->begin(); pointIt != structureIt->end(); ++pointIt) { //Look for all points in mm in the current struct (one point per string)
158 if (!std::strcmp(pointIt->name(), "string")) {
159 // Split the string to save the 2 or 3 values (remove the useless char) as double
160 char* copy = (char*)pointIt->child_value();
161 std::vector<char*> v;
162 char* chars_array = strtok(copy, ", ");
164 v.push_back(chars_array);
165 chars_array = strtok(NULL, ", ");
170 v[1][strlen(v[1])-1] = '\0';
174 Input3DType::PointType position;
175 Input3DType::IndexType index;
179 mhdReader->GetOutput()->TransformIndexToPhysicalPoint(index, position);
184 v[2][strlen(v[2])-1] = '\0';
189 points->InsertNextPoint(x, y, z);
193 //Create the polygon attached to the points
194 vtkSmartPointer<vtkPolygon> polygon = vtkSmartPointer<vtkPolygon>::New();
195 polygon->GetPointIds()->SetNumberOfIds(points->GetNumberOfPoints()); //make a quad
196 for (int pointIdx=0; pointIdx<points->GetNumberOfPoints(); ++pointIdx)
197 polygon->GetPointIds()->SetId(pointIdx, pointIdx);
198 // Add the polygon to a list of polygons
199 vtkSmartPointer<vtkCellArray> polygons = vtkSmartPointer<vtkCellArray>::New();
200 polygons->InsertNextCell(polygon);
202 vtkSmartPointer<vtkPolyData> polygonPolyData = vtkSmartPointer<vtkPolyData>::New();
203 polygonPolyData->SetPoints(points);
204 polygonPolyData->SetPolys(polygons);
206 //Append the polyData into the map at the correct stuct name entry
207 std::map<std::string, vtkSmartPointer<vtkAppendPolyData> >::const_iterator it = mapName2Data.find(name);
208 if (it == mapName2Data.end())
209 mapName2Data[name] = vtkSmartPointer<vtkAppendPolyData>::New();
210 #if VTK_MAJOR_VERSION <= 5
211 mapName2Data[name]->AddInput(polygonPolyData);
213 mapName2Data[name]->AddInputData(polygonPolyData);
222 for (std::map<std::string, vtkSmartPointer<vtkAppendPolyData> >::iterator it = mapName2Data.begin(); it != mapName2Data.end(); ++it)
223 it->second->Update();
225 // number of contours
226 int numMasks = mapName2Data.size();
229 vtkGDCMPolyDataWriter * writer = vtkGDCMPolyDataWriter::New();
230 writer->SetNumberOfInputPorts(numMasks);
231 writer->SetFileName(m_OutputFilename.c_str());
232 writer->SetMedicalImageProperties(reader->GetMedicalImageProperties());
234 // List of already present rois
235 vtkStringArray* roiNames = vtkStringArray::New();
236 vtkStringArray* roiAlgorithms = vtkStringArray::New();
237 vtkStringArray* roiTypes = vtkStringArray::New();
238 roiNames->SetNumberOfValues(numMasks);
239 roiAlgorithms->SetNumberOfValues(numMasks);
240 roiTypes->SetNumberOfValues(numMasks);
242 // Add new structures
243 std::map<std::string, vtkSmartPointer<vtkAppendPolyData> >::iterator it = mapName2Data.begin();
244 for (unsigned int i = 0; i < numMasks; ++i) {
245 #if VTK_MAJOR_VERSION <= 5
246 writer->SetInput(i, it->second->GetOutput());
248 writer->SetInputData(i, it->second->GetOutput());
250 roiNames->InsertValue(i, it->first);
251 roiAlgorithms->InsertValue(i, "CLITK_CREATED");
252 roiTypes->InsertValue(i, "coucou"); //Roi type instead of coucou
258 vtkPolyDataMapper *cubeMapper = vtkPolyDataMapper::New();
259 cubeMapper->SetInputData( mapName2Data.begin()->second->GetOutput() );
261 mapName2Data.begin()->second->GetOutput()->GetPointData()->GetScalars()->GetRange(range);
262 std::cout << numMasks << std::endl;
263 cubeMapper->SetScalarRange(range);
264 std::cout << range[0] << " " << range[1] << std::endl;
265 vtkActor *cubeActor = vtkActor::New();
266 cubeActor->SetMapper(cubeMapper);
267 vtkProperty * property = cubeActor->GetProperty();
268 property->SetRepresentationToWireframe();
270 vtkRenderer *renderer = vtkRenderer::New();
271 vtkRenderWindow *renWin = vtkRenderWindow::New();
272 renWin->AddRenderer(renderer);
274 vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
275 iren->SetRenderWindow(renWin);
277 renderer->AddActor(cubeActor);
278 renderer->ResetCamera();
279 renderer->SetBackground(1,1,1);
281 renWin->SetSize(300,300);
288 // Write (need to read dicom for slice id)
289 vtkRTStructSetProperties* theProperties = vtkRTStructSetProperties::New();
290 writer->SetRTStructSetProperties(theProperties);
291 if (GetVerboseFlag()) {
292 std::cout << "Looking for dicom info, study instance "
293 << p->GetStudyInstanceUID() << std::endl;
295 writer->InitializeRTStructSet(m_DicomFolder,
296 reader->GetRTStructSetProperties()->GetStructureSetLabel(),
297 reader->GetRTStructSetProperties()->GetStructureSetName(),
298 roiNames, roiAlgorithms, roiTypes);
303 roiAlgorithms->Delete();
306 //--------------------------------------------------------------------