CustusX  15.8
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxIGTLinkConversion.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 #include "cxIGTLinkConversion.h"
34 
35 #include "cxProbeData.h"
36 #include <vtkImageImport.h>
37 #include <vtkImageData.h>
38 #include "cxTypeConversions.h"
39 #include <vtkImageExtractComponents.h>
40 #include <vtkImageAppendComponents.h>
41 
42 typedef vtkSmartPointer<vtkImageImport> vtkImageImportPtr;
43 
44 namespace cx
45 {
46 
47 namespace
48 {
49 //------------------------------------------------------------
50 // Function to generate random matrix.
51 void GetRandomTestMatrix(igtl::Matrix4x4& matrix)
52 {
53  matrix[0][0] = 1.0; matrix[1][0] = 0.0; matrix[2][0] = 0.0; matrix[3][0] = 0.0;
54  matrix[0][1] = 0.0; matrix[1][1] = -1.0; matrix[2][1] = 0.0; matrix[3][1] = 0.0;
55  matrix[0][2] = 0.0; matrix[1][2] = 0.0; matrix[2][2] = 1.0; matrix[3][2] = 0.0;
56  matrix[0][3] = 0.0; matrix[1][3] = 0.0; matrix[2][3] = 0.0; matrix[3][3] = 1.0;
57 }
58 }
59 
61 {
62 }
63 
65 {
66  // TODO Auto-generated destructor stub
67 }
68 
69 
71 {
72  // IGTLinkImageMessage::Pointer retval;
73  vtkImageDataPtr rawImage = image->getBaseVtkImageData();
74 
75 // static int staticCounter = 0;
76  //------------------------------------------------------------
77  // size parameters
78  int size[] = {256, 256, 1}; // image dimension
79  rawImage->GetDimensions(size);
80 // std::cout << "img dim " << size[0] << size[1] << size[2] << std::endl;
81  //size[2] = 1; // grab only one frame
82 
83  double spacingD[3];
84  float spacingF[3];
85  rawImage->GetSpacing(spacingD);
86  spacingF[0] = spacingD[0];
87  spacingF[1] = spacingD[1];
88  spacingF[2] = spacingD[2];
89  int* svsize = size;
90  int svoffset[] = {0, 0, 0}; // sub-volume offset
91  int scalarType = -1;
92 
93  if (rawImage->GetNumberOfScalarComponents()==4)
94  {
95  if (rawImage->GetScalarType()==VTK_UNSIGNED_CHAR)
96  {
97  scalarType = igtl::ImageMessage::TYPE_UINT32;// scalar type
98  }
99  }
100 
101  if (rawImage->GetNumberOfScalarComponents()==1)
102  {
103  if (rawImage->GetScalarType()==VTK_UNSIGNED_SHORT)
104  {
105  scalarType = igtl::ImageMessage::TYPE_UINT16;// scalar type
106  }
107  else if (rawImage->GetScalarType()==VTK_UNSIGNED_CHAR)
108  {
109  scalarType = igtl::ImageMessage::TYPE_UINT8;// scalar type
110  }
111  }
112 
113  if (scalarType==-1)
114  {
115  std::cerr << "Unsupported file type based on vtk " << rawImage->GetScalarTypeAsString() << std::endl;
117  }
118 
119  //------------------------------------------------------------
120  // Create a new IMAGE type message
121  IGTLinkImageMessage::Pointer imgMsg = IGTLinkImageMessage::New();
122  imgMsg->SetDimensions(size);
123  imgMsg->SetSpacing(spacingF);
124  imgMsg->SetScalarType(scalarType);
125  imgMsg->SetDeviceName(cstring_cast(image->getUid()));
126  imgMsg->SetSubVolume(svsize, svoffset);
127  imgMsg->AllocateScalars();
128 
129  QDateTime lastGrabTime = image->getAcquisitionTime();
130  igtl::TimeStamp::Pointer timestamp;
131  timestamp = igtl::TimeStamp::New();
132  // double now = 1.0/1000*(double)QDateTime::currentDateTime().toMSecsSinceEpoch();
133  double grabTime = 1.0 / 1000 * (double) lastGrabTime.toMSecsSinceEpoch();
134  timestamp->SetTime(grabTime);
135  imgMsg->SetTimeStamp(timestamp);
136 
137  //------------------------------------------------------------
138  // Set image data (See GetTestImage() bellow for the details)
139  // GetTestImage(imgMsg, filedir, index);
140 
141  int fsize = imgMsg->GetImageSize();
142  // int frame = (staticCounter++) % image->GetDimensions()[2];
143  // std::cout << "emitting frame " << frame << ", image size=" << fsize << ", comp="<< image->GetNumberOfScalarComponents() << ", scalarType="<< scalarType << ", dim=("<< image->GetDimensions()[0] << ", "<< image->GetDimensions()[1] << ")" << std::endl;
144  memcpy(imgMsg->GetScalarPointer(), rawImage->GetScalarPointer(0,0,0), fsize); // not sure if we need to copy
145 
146  //------------------------------------------------------------
147  // Get randome orientation matrix and set it.
148  igtl::Matrix4x4 matrix;
149  GetRandomTestMatrix(matrix);
150  imgMsg->SetMatrix(matrix);
151 
152  return imgMsg;
153 
154 
155  // return retval;
156 }
157 
159 {
160  vtkImageImportPtr imageImport = vtkImageImportPtr::New();
161 
162  // Retrive the image data
163  float spacing[3]; // spacing (mm/pixel)
164  int svsize[3]; // sub-volume size
165  int svoffset[3]; // sub-volume offset
166  int scalarType; // scalar type
167  int size[3]; // image dimension
168 
169  // Note: subvolumes is not supported. Implement when needed.
170 
171  scalarType = message->GetScalarType();
172  message->GetDimensions(size);
173  message->GetSpacing(spacing);
174  message->GetSubVolume(svsize, svoffset);
175 // message->GetOrigin(origin);
176  QString deviceName = message->GetDeviceName();
177 // std::cout << "size : " << Vector3D(size[0], size[1], size[2]) << std::endl;
178 
179  imageImport->SetNumberOfScalarComponents(1);
180 
181  switch (scalarType)
182  {
183  case IGTLinkImageMessage::TYPE_INT8:
184  std::cout << "signed char is not supported. Falling back to unsigned char." << std::endl;
185  imageImport->SetDataScalarTypeToUnsignedChar();
186  break;
187  case IGTLinkImageMessage::TYPE_UINT8:
188  imageImport->SetDataScalarTypeToUnsignedChar();
189  break;
190  case IGTLinkImageMessage::TYPE_INT16:
191  imageImport->SetDataScalarTypeToShort();
192  break;
193  case IGTLinkImageMessage::TYPE_UINT16:
194 // std::cout << "SetDataScalarTypeToUnsignedShort." << std::endl;
195 // mImageImport->SetDataScalarTypeToUnsignedShort();
196  imageImport->SetNumberOfScalarComponents(2);
197  imageImport->SetDataScalarTypeToUnsignedChar();
198  break;
199  case IGTLinkImageMessage::TYPE_INT32:
200  case IGTLinkImageMessage::TYPE_UINT32:
201 // std::cout << "SetDataScalarTypeTo4channel." << std::endl;
202  // assume RGBA unsigned colors
203  imageImport->SetNumberOfScalarComponents(4);
204 // mImageImport->SetDataScalarTypeToInt();
205  imageImport->SetDataScalarTypeToUnsignedChar();
206 // std::cout << "32bit received" << std::endl;
207  break;
208  case IGTLinkImageMessage::TYPE_FLOAT32:
209  imageImport->SetDataScalarTypeToFloat();
210  break;
211  case IGTLinkImageMessage::TYPE_FLOAT64:
212  imageImport->SetDataScalarTypeToDouble();
213  break;
214  default:
215  std::cout << "unknown type. Falling back to unsigned char." << std::endl;
216  imageImport->SetDataScalarTypeToUnsignedChar();
217  }
218 
219  // get timestamp from igtl second-format:
220  igtl::TimeStamp::Pointer timestamp = igtl::TimeStamp::New();
221  message->GetTimeStamp(timestamp);
222 
223  double timestampMS = timestamp->GetTimeStamp() * 1000;
224  imageImport->SetDataOrigin(0, 0, 0);
225  imageImport->SetDataSpacing(spacing[0], spacing[1], spacing[2]);
226  imageImport->SetWholeExtent(0, size[0] - 1, 0, size[1] - 1, 0, size[2] - 1);
227  imageImport->SetDataExtentToWholeExtent();
228  imageImport->SetImportVoidPointer(message->GetScalarPointer());
229 
230  imageImport->Modified();
231  imageImport->Update();
232 
233  ImagePtr retval(new Image(deviceName, imageImport->GetOutput()));
234  retval->setAcquisitionTime(QDateTime::fromMSecsSinceEpoch(timestampMS));
235  retval = this->decode(retval);
236 
237 // QString format = this->extractColorFormat(deviceName);
239 
240 // vtkImageDataPtr imageRGB = this->createFilterFormat2RGB(format, imageImport->GetOutput());
241 // imageRGB->Update();
242 
243 // ImagePtr retval(new Image(deviceName, imageRGB));
244 // retval->setAcquisitionTime(QDateTime::fromMSecsSinceEpoch(timestampMS));
245 
246  return retval;
247 }
248 
250 {
251  IGTLinkUSStatusMessage::Pointer retval = IGTLinkUSStatusMessage::New();
252 
253  retval->SetOrigin(input->getOrigin_p().data());
254  // 1 = sector, 2 = linear
255  retval->SetProbeType(input->getType());
256 
257  retval->SetDepthStart(input->getDepthStart());// Start of sector in mm from origin
258  retval->SetDepthEnd(input->getDepthEnd()); // End of sector in mm from origin
259  retval->SetWidth(input->getWidth());// Width of sector in mm for LINEAR, Width of sector in radians for SECTOR.
260  retval->SetDeviceName(cstring_cast(input->getUid()));
261 
262  // std::cout << "origin: " << mFrameGeometry.origin[0] << " " << mFrameGeometry.origin[1] << " " << mFrameGeometry.origin[2] << std::endl;
263  // std::cout << "imageType: " << mFrameGeometry.imageType << std::endl;
264  // std::cout << "depthStart: " << mFrameGeometry.depthStart << " end: " << mFrameGeometry.depthEnd << std::endl;
265  // std::cout << "width: " << mFrameGeometry.width << std::endl;
266  // std::cout << "tilt: " << mFrameGeometry.tilt << std::endl;
267 
268  return retval;
269 }
270 
271 //'copied' from OpenIGTLinkRTSource::updateSonixStatus()
273 {
274  ProbeDefinitionPtr retval;
275  if (base)
276  retval = base;
277  else
278  retval = ProbeDefinitionPtr(new ProbeDefinition());
279 
280  if (probeMessage)
281  {
282  // Update the parts of the probe data that is read from the probe message.
283  retval->setType(ProbeDefinition::TYPE(probeMessage->GetProbeType()));
284  retval->setSector(
285  probeMessage->GetDepthStart(),
286  probeMessage->GetDepthEnd(),
287  probeMessage->GetWidth(),
288  0);
289  retval->setOrigin_p(Vector3D(probeMessage->GetOrigin()));
290  retval->setUid(probeMessage->GetDeviceName());
291  }
292 
293  if (imageMessage)
294  {
295  // Update the parts of the probe data that must be read from the image.
296 
297  // Retrive the image data
298  float spacing[3]; // spacing (mm/pixel)
299  int size[3]; // image dimension
300  imageMessage->GetDimensions(size);
301  imageMessage->GetSpacing(spacing);
302 
303  retval->setSpacing(Vector3D(spacing[0], spacing[1], spacing[2]));
304  retval->setSize(QSize(size[0], size[1]));
305  retval->setClipRect_p(DoubleBoundingBox3D(0, retval->getSize().width(), 0, retval->getSize().height(), 0, 0));
306  }
307 
308  return this->decode(retval);
309 }
310 
312 {
313  QString newUid = msg->getUid();
314  QString format = this->extractColorFormat(msg->getUid(), &newUid);
315  vtkImageDataPtr imageRGB = this->createFilterFormat2RGB(format, msg->getBaseVtkImageData());
316 // imageRGB->Update();
317 
318  // copy because the image will eventually be passed to another thread, and we cannot have the entire pipeline dragged along.
319  vtkImageDataPtr copy = vtkImageDataPtr::New();
320  copy->DeepCopy(imageRGB);
321 
322  ImagePtr retval(new Image(newUid, copy));
323  retval->setAcquisitionTime(msg->getAcquisitionTime());
324  return retval;
325 }
326 
328 {
329  QString newUid = msg->getUid();
330  QString format = this->extractColorFormat(msg->getUid(), &newUid);
331  msg->setUid(newUid);
332 
333  return msg;
334 }
335 
336 QString IGTLinkConversion::extractColorFormat(QString deviceName, QString* cleanedDeviceName)
337 {
338  QString format = "";
339  QRegExp colorFormat("\\[[A-Za-z]{1,4}\\]");
340  if (colorFormat.indexIn(deviceName) > 0)
341  {
342  format = colorFormat.cap(0).remove("[").remove("]");
343  }
344 
345  if (cleanedDeviceName)
346  {
347  *cleanedDeviceName = deviceName.remove(colorFormat).trimmed();
348  }
349 
350  return format;
351 }
352 
353 vtkImageDataPtr IGTLinkConversion::createFilterFormat2RGB(QString format, vtkImageDataPtr input)
354 {
355  int R = format.indexOf('R', 0, Qt::CaseInsensitive);
356  int G = format.indexOf('G', 0, Qt::CaseInsensitive);
357  int B = format.indexOf('B', 0, Qt::CaseInsensitive);
358  if (R<0 || G<0 || B<0 || format.size()>4)
359  {
360  R = 0;
361  G = 1;
362  B = 2;
363  }
364 
365  return this->createFilterAny2RGB(R, G, B, input);
366 }
367 
368 vtkImageDataPtr IGTLinkConversion::createFilterAny2RGB(int R, int G, int B, vtkImageDataPtr input)
369 {
370 // input->Update();
371  if (input->GetNumberOfScalarComponents() == 1)
372  return input;
373  if (( input->GetNumberOfScalarComponents()==3 )&&( R==0 )&&( G==1 )&&( B==2 ))
374  return input;
375 
376  vtkImageAppendComponentsPtr merger = vtkImageAppendComponentsPtr::New();
377  vtkImageExtractComponentsPtr splitterRGB = vtkImageExtractComponentsPtr::New();
378  splitterRGB->SetInputData(input);
379  splitterRGB->SetComponents(R, G, B);
380  merger->AddInputConnection(splitterRGB->GetOutputPort());
381 // merger->AddInputConnection(0, splitterRGB->GetOutputPort());
382  merger->Update();
383  return merger->GetOutput();
384 }
385 
386 } // namespace cx
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:48
cstring_cast_Placeholder cstring_cast(const T &val)
vtkSmartPointer< class vtkImageAppendComponents > vtkImageAppendComponentsPtr
A volumetric data set.
Definition: cxImage.h:66
Representation of a floating-point bounding box in 3D. The data are stored as {xmin,xmax,ymin,ymax,zmin,zmax}, in order to simplify communication with vtk.
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition: cxVector3D.h:63
Definition of characteristics for an Ultrasound Probe Sector.
Definition: cxProbeData.h:120
vtkSmartPointer< class vtkImageExtractComponents > vtkImageExtractComponentsPtr
vtkSmartPointer< class vtkImageImport > vtkImageImportPtr
vtkSmartPointer< class vtkImageData > vtkImageDataPtr
boost::shared_ptr< class ProbeDefinition > ProbeDefinitionPtr