NorMIT-nav  18.04
An IGT application
cxIGTLinkConversionSonixCXLegacy.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) SINTEF Department of Medical Technology.
5 All rights reserved.
6 
7 CustusX is released under a BSD 3-Clause license.
8 
9 See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
10 =========================================================================*/
12 
13 #include <vtkImageImport.h>
14 #include <vtkImageData.h>
15 #include <vtkImageExtractComponents.h>
16 #include <vtkImageAppendComponents.h>
17 
18 #include "igtl_status.h"
19 
20 #include "cxLog.h"
21 #include "cxProbeDefinition.h"
22 #include "cxTypeConversions.h"
25 
26 typedef vtkSmartPointer<vtkImageImport> vtkImageImportPtr;
27 
28 namespace {
29 void GetIdentityMatrix(igtl::Matrix4x4& matrix)
30 {
31  matrix[0][0] = 1.0; matrix[1][0] = 0.0; matrix[2][0] = 0.0; matrix[3][0] = 0.0;
32  matrix[0][1] = 0.0; matrix[1][1] = 1.0; matrix[2][1] = 0.0; matrix[3][1] = 0.0;
33  matrix[0][2] = 0.0; matrix[1][2] = 0.0; matrix[2][2] = 1.0; matrix[3][2] = 0.0;
34  matrix[0][3] = 0.0; matrix[1][3] = 0.0; matrix[2][3] = 0.0; matrix[3][3] = 1.0;
35 }
36 }
37 
38 namespace cx
39 {
40 
42 {
43  QString newUid = msg->getUid();
44  QString format = this->extractColorFormat(msg->getUid(), &newUid);
45  msg->setUid(newUid);
46 
47  return msg;
48 }
49 
50 ImagePtr IGTLinkConversionSonixCXLegacy::decode(igtl::ImageMessage::Pointer message)
51 {
52  vtkImageImportPtr imageImport = vtkImageImportPtr::New();
53 
54  // Retrive the image data
55  float spacing[3]; // spacing (mm/pixel)
56  int svsize[3]; // sub-volume size
57  int svoffset[3]; // sub-volume offset
58  int scalarType; // scalar type
59  int size[3]; // image dimension
60 
61  // Note: subvolumes is not supported. Implement when needed.
62 
63  scalarType = message->GetScalarType();
64  message->GetDimensions(size);
65  message->GetSpacing(spacing);
66  message->GetSubVolume(svsize, svoffset);
67  QString deviceName = message->GetDeviceName();
68 
69  imageImport->SetNumberOfScalarComponents(1);
70 
71  switch (scalarType)
72  {
73  case igtl::ImageMessage::TYPE_INT8:
74  CX_LOG_WARNING() << "signed char is not supported. Falling back to unsigned char.";
75  imageImport->SetDataScalarTypeToUnsignedChar();
76  break;
77  case igtl::ImageMessage::TYPE_UINT8:
78  imageImport->SetDataScalarTypeToUnsignedChar();
79  break;
80  case igtl::ImageMessage::TYPE_INT16:
81  imageImport->SetDataScalarTypeToShort();
82  break;
83  case igtl::ImageMessage::TYPE_UINT16:
84  imageImport->SetNumberOfScalarComponents(2);
85  imageImport->SetDataScalarTypeToUnsignedChar();
86  break;
87  case igtl::ImageMessage::TYPE_INT32:
88  case igtl::ImageMessage::TYPE_UINT32:
89  imageImport->SetNumberOfScalarComponents(4);
90  imageImport->SetDataScalarTypeToUnsignedChar();
91  break;
92  case igtl::ImageMessage::TYPE_FLOAT32:
93  imageImport->SetDataScalarTypeToFloat();
94  break;
95  case igtl::ImageMessage::TYPE_FLOAT64:
96  imageImport->SetDataScalarTypeToDouble();
97  break;
98  default:
99  CX_LOG_WARNING() << "Unknown image type. Falling back to unsigned char.";
100  imageImport->SetDataScalarTypeToUnsignedChar();
101  }
102 
103  imageImport->SetDataOrigin(0, 0, 0);
104  imageImport->SetDataSpacing(spacing[0], spacing[1], spacing[2]);
105  imageImport->SetWholeExtent(0, size[0] - 1, 0, size[1] - 1, 0, size[2] - 1);
106  imageImport->SetDataExtentToWholeExtent();
107  imageImport->SetImportVoidPointer(message->GetScalarPointer());
108 
109  imageImport->Modified();
110  imageImport->Update();
111 
112  ImagePtr retval(new Image(deviceName, imageImport->GetOutput()));
113  IGTLinkConversionBase baseConverter;
114  retval->setAcquisitionTime(baseConverter.decode_timestamp(message));
115  retval = this->decode(retval);
116 
117  return retval;
118 }
119 
120 igtl::ImageMessage::Pointer IGTLinkConversionSonixCXLegacy::encode(ImagePtr image)
121 {
122  vtkImageDataPtr rawImage = image->getBaseVtkImageData();
123 
124  int size[] = {256, 256, 1}; // image dimension
125  rawImage->GetDimensions(size);
126 
127  double spacingD[3];
128  float spacingF[3];
129  rawImage->GetSpacing(spacingD);
130  spacingF[0] = spacingD[0];
131  spacingF[1] = spacingD[1];
132  spacingF[2] = spacingD[2];
133  int* svsize = size;
134  int svoffset[] = {0, 0, 0}; // sub-volume offset
135  int scalarType = -1;
136 
137  if (rawImage->GetNumberOfScalarComponents()==4)
138  {
139  if (rawImage->GetScalarType()==VTK_UNSIGNED_CHAR)
140  {
141  scalarType = igtl::ImageMessage::TYPE_UINT32;// scalar type
142  }
143  }
144 
145  if (rawImage->GetNumberOfScalarComponents()==1)
146  {
147  if (rawImage->GetScalarType()==VTK_UNSIGNED_SHORT)
148  {
149  scalarType = igtl::ImageMessage::TYPE_UINT16;// scalar type
150  }
151  else if (rawImage->GetScalarType()==VTK_UNSIGNED_CHAR)
152  {
153  scalarType = igtl::ImageMessage::TYPE_UINT8;// scalar type
154  }
155  }
156 
157  if (scalarType==-1)
158  {
159  std::cerr << "Unsupported file type based on vtk " << rawImage->GetScalarTypeAsString() << std::endl;
160  return igtl::ImageMessage::Pointer();
161  }
162 
163  //------------------------------------------------------------
164  // Create a new IMAGE type message
165  igtl::ImageMessage::Pointer imgMsg = igtl::ImageMessage::New();
166  imgMsg->SetDimensions(size);
167  imgMsg->SetSpacing(spacingF);
168  imgMsg->SetScalarType(scalarType);
169  imgMsg->SetDeviceName(cstring_cast(image->getUid()));
170  imgMsg->SetSubVolume(svsize, svoffset);
171  imgMsg->AllocateScalars();
172 
173  IGTLinkConversionBase baseConverter;
174  baseConverter.encode_timestamp(image->getAcquisitionTime(), imgMsg);
175 
176  int fsize = imgMsg->GetImageSize();
177  memcpy(imgMsg->GetScalarPointer(), rawImage->GetScalarPointer(0,0,0), fsize); // not sure if we need to copy
178 
179  igtl::Matrix4x4 matrix;
180  GetIdentityMatrix(matrix);
181  imgMsg->SetMatrix(matrix);
182 
183  return imgMsg;
184 }
185 
186 
188 {
189  QString newUid = msg->getUid();
190  QString format = this->extractColorFormat(msg->getUid(), &newUid);
191  vtkImageDataPtr imageRGB = this->createFilterFormat2RGB(format, msg->getBaseVtkImageData());
192 
193  // copy because the image will eventually be passed to another thread, and we cannot have the entire pipeline dragged along.
194  vtkImageDataPtr copy = vtkImageDataPtr::New();
195  copy->DeepCopy(imageRGB);
196 
197  ImagePtr retval(new Image(newUid, copy));
198  retval->setAcquisitionTime(msg->getAcquisitionTime());
199  return retval;
200 }
201 
203 {
204  QString dummy;
205  QString format = this->extractColorFormat(deviceName, &dummy);
206  return !format.isEmpty();
207 }
208 
209 QString IGTLinkConversionSonixCXLegacy::extractColorFormat(QString deviceName, QString* cleanedDeviceName)
210 {
211  QString format = "";
212  QRegExp colorFormat("\\[[A-Za-z]{1,4}\\]");
213  if (colorFormat.indexIn(deviceName) > 0)
214  {
215  format = colorFormat.cap(0).remove("[").remove("]");
216  }
217 
218  if (cleanedDeviceName)
219  {
220  *cleanedDeviceName = deviceName.remove(colorFormat).trimmed();
221  }
222 
223  return format;
224 }
225 
226 vtkImageDataPtr IGTLinkConversionSonixCXLegacy::createFilterFormat2RGB(QString format, vtkImageDataPtr input)
227 {
228  int R = format.indexOf('R', 0, Qt::CaseInsensitive);
229  int G = format.indexOf('G', 0, Qt::CaseInsensitive);
230  int B = format.indexOf('B', 0, Qt::CaseInsensitive);
231  if (R<0 || G<0 || B<0 || format.size()>4)
232  {
233  R = 0;
234  G = 1;
235  B = 2;
236  }
237 
238  return this->createFilterAny2RGB(R, G, B, input);
239 }
240 
241 vtkImageDataPtr IGTLinkConversionSonixCXLegacy::createFilterAny2RGB(int R, int G, int B, vtkImageDataPtr input)
242 {
243  if (input->GetNumberOfScalarComponents() == 1)
244  return input;
245  if (( input->GetNumberOfScalarComponents()==3 )&&( R==0 )&&( G==1 )&&( B==2 ))
246  return input;
247 
248  vtkImageAppendComponentsPtr merger = vtkImageAppendComponentsPtr::New();
249  vtkImageExtractComponentsPtr splitterRGB = vtkImageExtractComponentsPtr::New();
250  splitterRGB->SetInputData(input);
251  splitterRGB->SetComponents(R, G, B);
252  merger->AddInputConnection(splitterRGB->GetOutputPort());
253  merger->Update();
254  return merger->GetOutput();
255 }
256 
257 } //namespace cx
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:27
cstring_cast_Placeholder cstring_cast(const T &val)
vtkSmartPointer< class vtkImageAppendComponents > vtkImageAppendComponentsPtr
A volumetric data set.
Definition: cxImage.h:45
vtkSmartPointer< class vtkImageExtractComponents > vtkImageExtractComponentsPtr
vtkSmartPointer< class vtkImageImport > vtkImageImportPtr
#define CX_LOG_WARNING
Definition: cxLogger.h:98
vtkSmartPointer< class vtkImageData > vtkImageDataPtr
boost::shared_ptr< class ProbeDefinition > ProbeDefinitionPtr
Namespace for all CustusX production code.