PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
ViewSequenceFile.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2 Program: Plus
3 Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
4 See License.txt for details.
5 =========================================================Plus=header=end*/
6 
7 #include "PlusConfigure.h"
8 #include "igsioTrackedFrame.h"
9 #include "vtkActorCollection.h"
10 #include "vtkCallbackCommand.h"
11 #include "vtkCollectionIterator.h"
12 #include "vtkCommand.h"
13 #include "vtkImageActor.h"
14 #include "vtkImageData.h"
15 #include "vtkImageImport.h"
16 #ifdef PLUS_RENDERING_ENABLED
17 #include "vtkImageViewer2.h"
18 #endif
19 #include "vtkMatrix4x4.h"
20 #include "vtkProp.h"
21 #include "vtkRenderWindow.h"
22 #include "vtkRenderWindow.h"
23 #include "vtkRenderWindowInteractor.h"
24 #include "vtkRenderer.h"
25 #include "vtkRenderer.h"
26 #include "vtkIGSIOSequenceIO.h"
27 #include "vtkSmartPointer.h"
28 #include "vtkTextActor.h"
29 #include "vtkTextActor3D.h"
30 #include "vtkTextProperty.h"
31 #include "vtkIGSIOTrackedFrameList.h"
32 #include "vtkTransform.h"
33 #include "vtkIGSIOTransformRepository.h"
34 #include "vtkXMLUtilities.h"
35 #include "vtksys/CommandLineArguments.hxx"
36 #include <iomanip>
37 
39 
40 class vtkMyCallback : public vtkCommand
41 {
42 public:
43  static vtkMyCallback* New() {return new vtkMyCallback;}
44 
45  void Initialize(vtkRenderWindow* renderWindow,
46  vtkRenderWindowInteractor* renderWindowInteractor,
47  vtkTextActor* textActor,
48  vtkCollection* imageActors,
49  std::vector<vtkTransform*>* imageTransforms)
50  {
51  this->RenderWindow = renderWindow;
52  this->RenderWindowInteractor = renderWindowInteractor;
53  this->TextActor = textActor;
54  this->ImageActors = imageActors;
55  this->ImageTransforms = imageTransforms;
56  }
57 
58  virtual void Execute(vtkObject* caller, unsigned long callerEvent, void*)
59  {
60  if (callerEvent == vtkCommand::CharEvent)
61  {
62  char keycode = this->RenderWindowInteractor->GetKeyCode();
63  switch (keycode)
64  {
65  case '+':
66  {
67  if (++this->FrameNum >= this->ImageActors->GetNumberOfItems())
68  {
69  this->FrameNum = 0;
70  }
71 
72  if (this->CurrentActor != NULL)
73  {
74  this->CurrentActor->VisibilityOff();
75  static_cast<vtkImageActor*>(this->ImageActors->GetItemAsObject(0))->VisibilityOn();
76  }
77 
78  this->CurrentActor = static_cast<vtkImageActor*>(this->ImageActors->GetItemAsObject(this->FrameNum));
79  this->CurrentActor->VisibilityOn();
80  }
81  break;
82  case '-':
83  {
84  if (--this->FrameNum < 0)
85  {
86  this->FrameNum = this->ImageActors->GetNumberOfItems() - 1;
87  }
88 
89  if (this->CurrentActor != NULL)
90  {
91  this->CurrentActor->VisibilityOff();
92  static_cast<vtkImageActor*>(this->ImageActors->GetItemAsObject(0))->VisibilityOn();
93  }
94 
95  this->CurrentActor = static_cast<vtkImageActor*>(this->ImageActors->GetItemAsObject(this->FrameNum));
96  this->CurrentActor->VisibilityOn();
97  }
98  break;
99  }
100  }
101 
102  double* position = (*this->ImageTransforms)[this->FrameNum]->GetPosition();
103  std::ostringstream ss;
104  ss.precision(2);
105  ss << "Frame " << this->FrameNum << "\nImage position: " << std::fixed << position[0] << " " << position[1] << " " << position[2] << std::ends;
106  this->TextActor->SetInput(ss.str().c_str());
107 
108  this->RenderWindow->Render();
109  // Update the timer so it will trigger again
110  this->RenderWindowInteractor->CreateTimer(VTKI_TIMER_UPDATE);
111  }
112 
113 protected:
114  vtkMyCallback()
115  {
116  this->FrameNum = 0;
117  this->CurrentActor = NULL;
118  this->RenderWindow = NULL;
119  this->RenderWindowInteractor = NULL;
120  this->TextActor = NULL;
121  this->ImageActors = NULL;
122  this->ImageTransforms = NULL;
123  }
124 
125  virtual ~vtkMyCallback()
126  {
127  }
128 
129  int FrameNum;
130  vtkImageActor* CurrentActor;
131  vtkRenderWindow* RenderWindow;
132  vtkRenderWindowInteractor* RenderWindowInteractor;
133  vtkTextActor* TextActor;
134  vtkCollection* ImageActors;
135  std::vector<vtkTransform*>* ImageTransforms;
136 };
137 
138 int main(int argc, char** argv)
139 {
140  bool printHelp(false);
141  std::string inputSequenceFilename;
142  std::string inputConfigFileName;
143  std::string outputModelFilename;
144  std::string imageToReferenceTransformNameStr;
145  bool renderingOff(false);
146 
147  int verboseLevel = vtkPlusLogger::LOG_LEVEL_UNDEFINED;
148 
149  vtksys::CommandLineArguments args;
150  args.Initialize(argc, argv);
151 
152  args.AddArgument("--image-to-reference-transform", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &imageToReferenceTransformNameStr, "Transform name used for displaying the slices");
153  args.AddArgument("--source-seq-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputSequenceFilename, "Tracked ultrasound recorded by Plus (e.g., by the TrackedUltrasoundCapturing application) in a sequence file (.mha/.nrrd)");
154  args.AddArgument("--config-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputConfigFileName, "Config file containing coordinate system definitions");
155  args.AddArgument("--rendering-off", vtksys::CommandLineArguments::NO_ARGUMENT, &renderingOff, "Run in test mode, without rendering.");
156  args.AddArgument("--verbose", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &verboseLevel, "Verbose level (1=error only, 2=warning, 3=info, 4=debug, 5=trace)");
157  args.AddArgument("--help", vtksys::CommandLineArguments::NO_ARGUMENT, &printHelp, "Print this help.");
158 
159  if (!args.Parse())
160  {
161  std::cerr << "Problem parsing arguments" << std::endl;
162  std::cout << "Help: " << args.GetHelp() << std::endl;
163  exit(EXIT_FAILURE);
164  }
165 
166  if (printHelp)
167  {
168  std::cout << args.GetHelp() << std::endl;
169  exit(EXIT_SUCCESS);
170  }
171 
172  vtkPlusLogger::Instance()->SetLogLevel(verboseLevel);
173 
174  if (inputSequenceFilename.empty())
175  {
176  std::cerr << "--source-seq-file is required" << std::endl;
177  exit(EXIT_FAILURE);
178  }
179 
181 
182  vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New();
183 
184  vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
185  renWin->AddRenderer(renderer);
186 
187  // Create image actor collection
188  vtkSmartPointer<vtkCollection> imageActors = vtkSmartPointer<vtkCollection>::New();
189 
190  //Create the inter actor that handles the event loop
191  vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
192  renderWindowInteractor->SetRenderWindow(renWin);
193 
194  // Read input tracked ultrasound data.
195  LOG_DEBUG("Reading input... ");
196  vtkSmartPointer< vtkIGSIOTrackedFrameList > trackedFrameList = vtkSmartPointer< vtkIGSIOTrackedFrameList >::New();
197  // Orientation is XX so that the orientation of the trackedFrameList will match the orientation defined in the file
198  if (vtkIGSIOSequenceIO::Read(inputSequenceFilename, trackedFrameList) != PLUS_SUCCESS)
199  {
200  LOG_ERROR("Unable to load input sequences file.");
201  return EXIT_FAILURE;
202  }
203  LOG_DEBUG("Reading input done.");
204  LOG_DEBUG("Number of frames: " << trackedFrameList->GetNumberOfTrackedFrames());
205 
206  // Read calibration matrices from the config file
207  vtkSmartPointer<vtkIGSIOTransformRepository> transformRepository = vtkSmartPointer<vtkIGSIOTransformRepository>::New();
208  if (!inputConfigFileName.empty())
209  {
210  LOG_DEBUG("Reading config file...");
211  vtkSmartPointer<vtkXMLDataElement> configRootElement = vtkSmartPointer<vtkXMLDataElement>::New();
212  if (PlusXmlUtils::ReadDeviceSetConfigurationFromFile(configRootElement, inputConfigFileName.c_str()) == PLUS_FAIL)
213  {
214  LOG_ERROR("Unable to read configuration from file " << inputConfigFileName.c_str());
215  return EXIT_FAILURE;
216  }
217  if (transformRepository->ReadConfiguration(configRootElement) != PLUS_SUCCESS)
218  {
219  LOG_ERROR("Failed to read transforms for transform repository!");
220  return EXIT_FAILURE;
221  }
222  }
223  else
224  {
225  LOG_INFO("Configuration file is not specified. Only those transforms are available that are defined in the sequence metafile");
226  }
227 
228  LOG_INFO("Adding frames to actors...");
229 
230  std::vector<vtkTransform*> imageTransforms;
231 
232  igsioTransformName imageToReferenceTransformName;
233  if (!imageToReferenceTransformNameStr.empty())
234  {
235  // transform name is defined, we'll show each image in its correct 3D position
236  if (imageToReferenceTransformName.SetTransformName(imageToReferenceTransformNameStr.c_str()) != PLUS_SUCCESS)
237  {
238  LOG_ERROR("Invalid image to reference transform name: " << imageToReferenceTransformNameStr);
239  return EXIT_FAILURE;
240  }
241  }
242 
243  int numberOfFrames = trackedFrameList->GetNumberOfTrackedFrames();
244  for (int frameIndex = 0; frameIndex < numberOfFrames; frameIndex++)
245  {
246  vtkPlusLogger::PrintProgressbar((100.0 * frameIndex) / numberOfFrames);
247  igsioTrackedFrame* frame = trackedFrameList->GetTrackedFrame(frameIndex);
248 
249  // Update transform repository
250  if (transformRepository->SetTransforms(*frame) != PLUS_SUCCESS)
251  {
252  LOG_ERROR("Failed to set repository transforms from tracked frame!");
253  continue;
254  }
255 
256  vtkSmartPointer<vtkImageData> frameImageData = vtkSmartPointer<vtkImageData>::New();
257  frameImageData->DeepCopy(frame->GetImageData()->GetImage());
258 
259  vtkSmartPointer<vtkImageActor> imageActor = vtkSmartPointer<vtkImageActor>::New();
260  imageActor->SetInputData(frameImageData);
261 
262  vtkSmartPointer< vtkTransform > imageToReferenceTransform = vtkSmartPointer< vtkTransform >::New();
263  if (imageToReferenceTransformName.IsValid())
264  {
265  vtkSmartPointer<vtkMatrix4x4> imageToReferenceTransformMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
266  if (transformRepository->GetTransform(imageToReferenceTransformName, imageToReferenceTransformMatrix) != PLUS_SUCCESS)
267  {
268  std::string strTransformName;
269  imageToReferenceTransformName.GetTransformName(strTransformName);
270  LOG_ERROR("Failed to get transform from repository: " << strTransformName);
271  continue;
272  }
273  imageToReferenceTransform->SetMatrix(imageToReferenceTransformMatrix);
274  }
275 
276  imageActor->SetUserTransform(imageToReferenceTransform);
277  imageActor->VisibilityOff();
278  imageTransforms.push_back(imageToReferenceTransform);
279  imageActors->AddItem(imageActor);
280  }
281 
282  vtkPlusLogger::PrintProgressbar(100);
283  std::cout << std::endl;
284 
285  for (int i = 0; i < imageActors->GetNumberOfItems(); i++)
286  {
287  vtkImageActor* imgActor = static_cast<vtkImageActor*>(imageActors->GetItemAsObject(i));
288  imgActor->SetVisibility(i == 0); // hide all frames but the first one
289  renderer->AddActor(imgActor);
290  }
291 
292  if (renderingOff)
293  {
294  LOG_INFO("No need for rendering...");
295  }
296  else
297  {
298  // Create a text actor for image position information
299  vtkSmartPointer<vtkTextActor> textActor = vtkSmartPointer<vtkTextActor>::New();
300  vtkSmartPointer<vtkTextProperty> textprop = textActor->GetTextProperty();
301  textprop->SetColor(1, 0, 0);
302  textprop->SetFontFamilyToArial();
303  textprop->SetFontSize(15);
304  textprop->SetJustificationToLeft();
305  textprop->SetVerticalJustificationToTop();
306 
307  textActor->VisibilityOn();
308  textActor->SetDisplayPosition(10, 50);
309 
310  renderer->AddActor(textActor);
311 
312  renderer->SetBackground(0.1, 0.2, 0.4);
313  renWin->SetSize(800, 600);
314  renWin->Render();
315 
316  //establish timer event and create timer
317  vtkSmartPointer<vtkMyCallback> call = vtkSmartPointer<vtkMyCallback>::New();
318  call->Initialize(renWin, renderWindowInteractor, textActor, imageActors, &imageTransforms);
319  renderWindowInteractor->AddObserver(vtkCommand::TimerEvent, call);
320  renderWindowInteractor->AddObserver(vtkCommand::CharEvent, call);
321  renderWindowInteractor->CreateTimer(VTKI_TIMER_FIRST); //VTKI_TIMER_FIRST = 0
322 
323  //iren must be initialized so that it can handle events
324  renderWindowInteractor->Initialize();
325  renderWindowInteractor->Start();
326  }
327 
328  std::cout << "MetaImageSequenceViewer completed successfully!" << std::endl;
329  return EXIT_SUCCESS;
330 }
int main(int argc, char **argv)
for i
#define PLUS_FAIL
Definition: PlusCommon.h:43
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
static vtkIGSIOLogger * Instance()
double * position
Definition: phidget22.h:3303
static PlusStatus ReadDeviceSetConfigurationFromFile(vtkXMLDataElement *config, const char *filename)
Definition: PlusXmlUtils.h:23