Medical Imaging Interaction Toolkit  2018.4.99-899caed2
Medical Imaging Interaction Toolkit
mitkImageToIGTLMessageFilter.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
14 #include "mitkImageReadAccessor.h"
15 #include "itkByteSwapper.h"
16 #include "igtlImageMessage.h"
17 
19 {
20  mitk::IGTLMessage::Pointer output = mitk::IGTLMessage::New();
21  this->SetNumberOfRequiredOutputs(1);
22  this->SetNthOutput(0, output.GetPointer());
23  this->SetNumberOfRequiredInputs(1);
24 }
25 
27 {
28  // MITK_INFO << "ImageToIGTLMessageFilter.GenerateData()";
29  for (unsigned int i = 0; i < this->GetNumberOfIndexedOutputs(); ++i)
30  {
31  mitk::IGTLMessage* output = this->GetOutput(i);
32  assert(output);
33 
34  const mitk::Image* img = this->GetInput(i);
35 
36  int dims = img->GetDimension();
37  int chn = img->GetNumberOfChannels();
38 
39  if (dims < 1)
40  {
41  MITK_ERROR << "Can not handle dimensionless images";
42  }
43  if (dims > 3)
44  {
45  MITK_ERROR << "Can not handle more than three dimensions";
46  continue;
47  }
48 
49  if (chn != 1)
50  {
51  MITK_ERROR << "Can not handle anything but one channel. Image contained " << chn;
52  continue;
53  }
54 
55  igtl::ImageMessage::Pointer imgMsg = igtl::ImageMessage::New();
56 
57  // TODO: Which kind of coordinate system does MITK really use?
58  imgMsg->SetCoordinateSystem(igtl::ImageMessage::COORDINATE_RAS);
59 
60  // We could do this based on the host endiannes, but that's weird.
61  // We instead use little endian, as most modern systems are little endian,
62  // so there will probably not be an endian swap involved.
63  imgMsg->SetEndian(igtl::ImageMessage::ENDIAN_LITTLE);
64 
65  // Set number of components.
66  mitk::PixelType type = img->GetPixelType();
67  imgMsg->SetNumComponents(type.GetNumberOfComponents());
68 
69  // Set scalar type.
70  switch (type.GetComponentType())
71  {
72  case itk::ImageIOBase::CHAR:
73  imgMsg->SetScalarTypeToInt8();
74  break;
75  case itk::ImageIOBase::UCHAR:
76  imgMsg->SetScalarTypeToUint8();
77  break;
78  case itk::ImageIOBase::SHORT:
79  imgMsg->SetScalarTypeToInt16();
80  break;
81  case itk::ImageIOBase::USHORT:
82  imgMsg->SetScalarTypeToUint16();
83  break;
84  case itk::ImageIOBase::INT:
85  imgMsg->SetScalarTypeToInt32();
86  break;
87  case itk::ImageIOBase::UINT:
88  imgMsg->SetScalarTypeToUint32();
89  break;
90  case itk::ImageIOBase::LONG:
91  // OIGTL doesn't formally support 64bit int scalars, but if they are
92  // ever added,
93  // they will have the identifier 8 assigned.
94  imgMsg->SetScalarType(8);
95  break;
96  case itk::ImageIOBase::ULONG:
97  // OIGTL doesn't formally support 64bit uint scalars, but if they are
98  // ever added,
99  // they will have the identifier 9 assigned.
100  imgMsg->SetScalarType(9);
101  break;
102  case itk::ImageIOBase::FLOAT:
103  // The igtl library has no method for this. Correct type is 10.
104  imgMsg->SetScalarType(10);
105  break;
106  case itk::ImageIOBase::DOUBLE:
107  // The igtl library has no method for this. Correct type is 11.
108  imgMsg->SetScalarType(11);
109  break;
110  default:
111  MITK_ERROR << "Can not handle pixel component type "
112  << type.GetComponentType();
113  return;
114  }
115 
116  // Set transformation matrix.
117  vtkMatrix4x4* matrix = img->GetGeometry()->GetVtkMatrix();
118 
119  float matF[4][4];
120  for (size_t i = 0; i < 4; ++i)
121  {
122  for (size_t j = 0; j < 4; ++j)
123  {
124  matF[i][j] = matrix->GetElement(i, j);
125  }
126  }
127  imgMsg->SetMatrix(matF);
128 
129  float spacing[3];
130  auto spacingImg = img->GetGeometry()->GetSpacing();
131 
132  for (int i = 0; i < 3; ++i)
133  spacing[i] = spacingImg[i];
134 
135  imgMsg->SetSpacing(spacing);
136 
137  // Set dimensions.
138  int sizes[3];
139  for (size_t j = 0; j < 3; ++j)
140  {
141  sizes[j] = img->GetDimension(j);
142  }
143  imgMsg->SetDimensions(sizes);
144 
145  // Allocate and copy data.
146  imgMsg->AllocatePack();
147  imgMsg->AllocateScalars();
148 
149  size_t num_pixel = sizes[0] * sizes[1] * sizes[2];
150  void* out = imgMsg->GetScalarPointer();
151  {
152  // Scoped, so that readAccess will be released ASAP.
153  mitk::ImageReadAccessor readAccess(img, img->GetChannelData(0));
154  const void* in = readAccess.GetData();
155 
156  memcpy(out, in, num_pixel * type.GetSize());
157  }
158 
159  // We want to byte swap to little endian. We would like to just
160  // swap by number of bytes for each component, but itk::ByteSwapper
161  // is templated over element type, not over element size. So we need to
162  // switch on the size and use types of the same size.
163  size_t num_scalars = num_pixel * type.GetNumberOfComponents();
164  switch (type.GetComponentType())
165  {
166  case itk::ImageIOBase::CHAR:
167  case itk::ImageIOBase::UCHAR:
168  // No endian conversion necessary, because a char is exactly one byte!
169  break;
170  case itk::ImageIOBase::SHORT:
171  case itk::ImageIOBase::USHORT:
172  itk::ByteSwapper<short>::SwapRangeFromSystemToLittleEndian((short*)out,
173  num_scalars);
174  break;
175  case itk::ImageIOBase::INT:
176  case itk::ImageIOBase::UINT:
177  itk::ByteSwapper<int>::SwapRangeFromSystemToLittleEndian((int*)out,
178  num_scalars);
179  break;
180  case itk::ImageIOBase::LONG:
181  case itk::ImageIOBase::ULONG:
182  itk::ByteSwapper<long>::SwapRangeFromSystemToLittleEndian((long*)out,
183  num_scalars);
184  break;
185  case itk::ImageIOBase::FLOAT:
186  itk::ByteSwapper<float>::SwapRangeFromSystemToLittleEndian((float*)out,
187  num_scalars);
188  break;
189  case itk::ImageIOBase::DOUBLE:
190  itk::ByteSwapper<double>::SwapRangeFromSystemToLittleEndian(
191  (double*)out, num_scalars);
192  break;
193  }
194 
195  //copy timestamp of mitk image
196  igtl::TimeStamp::Pointer timestamp = igtl::TimeStamp::New();
197  timestamp->SetTime(img->GetMTime() / 1000, (int)(img->GetMTime()) % 1000);
198  imgMsg->SetTimeStamp(timestamp);
199 
200  imgMsg->Pack();
201 
202  output->SetMessage(imgMsg.GetPointer());
203  }
204 }
205 
207 {
208  this->ProcessObject::SetNthInput(0, const_cast<mitk::Image*>(img));
210 }
211 
213  const Image* img)
214 {
215  this->ProcessObject::SetNthInput(idx, const_cast<mitk::Image*>(img));
217 }
218 
220 {
221  if (this->GetNumberOfInputs() < 1)
222  return nullptr;
223  return static_cast<const mitk::Image*>(this->ProcessObject::GetInput(0));
224 }
225 
227 {
228  if (this->GetNumberOfInputs() < idx + 1)
229  {
230  return nullptr;
231  }
232  return static_cast<const mitk::Image*>(this->ProcessObject::GetInput(idx));
233 }
234 
236 {
237  MITK_INFO << "Image source for this (" << this << ") mitkImageToIGTLMessageFilter is " << upstream;
238  for (DataObjectPointerArraySizeType i = 0; i < upstream->GetNumberOfOutputs();
239  i++)
240  {
241  this->SetInput(i, upstream->GetOutput(i));
242  }
243 }
244 
246 {
247  // create one message output for all image inputs
248  this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs());
249 
250  for (size_t idx = 0; idx < this->GetNumberOfIndexedOutputs(); ++idx)
251  {
252  if (this->GetOutput(idx) == nullptr)
253  {
254  this->SetNthOutput(idx, this->MakeOutput(idx));
255  }
256  this->Modified();
257  }
258 }
Superclass of all classes generating Images (instances of class Image) as output. ...
virtual void ConnectTo(mitk::ImageSource *UpstreamFilter)
Connects the input of this filter to the outputs of the given ImageSource.
vtkMatrix4x4 * GetVtkMatrix()
#define MITK_INFO
Definition: mitkLogMacros.h:18
void SetMessage(igtl::MessageBase::Pointer msg)
Sets the OpenIGTLink message.
const mitk::PixelType GetPixelType(int n=0) const
Returns the PixelType of channel n.
Definition: mitkImage.cpp:101
#define MITK_ERROR
Definition: mitkLogMacros.h:20
itk::DataObject::Pointer MakeOutput(DataObjectPointerArraySizeType idx) override
vcl_size_t GetNumberOfComponents() const
Get the number of components of which each element consists.
const mitk::Image * GetInput()
Returns the input of this filter.
virtual ImageDataItemPointer GetChannelData(int n=0, void *data=nullptr, ImportMemoryManagementType importMemoryManagement=CopyMemory) const
Definition: mitkImage.cpp:457
int GetComponentType() const
Get the component type (the scalar (!) type). Each element may contain m_NumberOfComponents (more tha...
IGTLMessage * GetOutput(void)
return the output (output with id 0) of the filter
unsigned int GetNumberOfChannels() const
Get the number of channels.
unsigned int GetDimension() const
Get dimension of the image.
Definition: mitkImage.cpp:106
A wrapper for the OpenIGTLink message type.
Image class for storing images.
Definition: mitkImage.h:72
void GenerateData() override
filter execute method
virtual void CreateOutputsForAllInputs()
create output objects for all inputs
unsigned long GetMTime() const override
Get the modified time of the last change of the contents this data object or its geometry.
vcl_size_t GetSize() const
Get size of the PixelType in bytes.
static bool in(Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4)
Definition: jsoncpp.cpp:244
const mitk::Vector3D GetSpacing() const
Get the spacing (size of a pixel).
static Pointer New()
virtual void SetInput(const mitk::Image *img)
Sets one input Image.
ImageReadAccessor class to get locked read access for a particular image part.
mitk::BaseGeometry * GetGeometry(int t=0) const
Return the geometry, which is a TimeGeometry, of the data as non-const pointer.
Definition: mitkBaseData.h:143
Class for defining the data type of pixels.
Definition: mitkPixelType.h:51