MITK-IGT
IGT Extension of MITK
Loading...
Searching...
No Matches
mitkImageToIGTLMessageFilter.cpp
Go to the documentation of this file.
1/*============================================================================
2
3The Medical Imaging Interaction Toolkit (MITK)
4
5Copyright (c) German Cancer Research Center (DKFZ)
6All rights reserved.
7
8Use of this source code is governed by a 3-clause BSD license that can be
9found 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::IOComponentEnum::CHAR:
73 imgMsg->SetScalarTypeToInt8();
74 break;
75 case itk::IOComponentEnum::UCHAR:
76 imgMsg->SetScalarTypeToUint8();
77 break;
78 case itk::IOComponentEnum::SHORT:
79 imgMsg->SetScalarTypeToInt16();
80 break;
81 case itk::IOComponentEnum::USHORT:
82 imgMsg->SetScalarTypeToUint16();
83 break;
84 case itk::IOComponentEnum::INT:
85 imgMsg->SetScalarTypeToInt32();
86 break;
87 case itk::IOComponentEnum::UINT:
88 imgMsg->SetScalarTypeToUint32();
89 break;
90 case itk::IOComponentEnum::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::IOComponentEnum::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::IOComponentEnum::FLOAT:
103 // The igtl library has no method for this. Correct type is 10.
104 imgMsg->SetScalarType(10);
105 break;
106 case itk::IOComponentEnum::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::IOComponentEnum::CHAR:
167 case itk::IOComponentEnum::UCHAR:
168 // No endian conversion necessary, because a char is exactly one byte!
169 break;
170 case itk::IOComponentEnum::SHORT:
171 case itk::IOComponentEnum::USHORT:
172 itk::ByteSwapper<short>::SwapRangeFromSystemToLittleEndian((short*)out,
173 num_scalars);
174 break;
175 case itk::IOComponentEnum::INT:
176 case itk::IOComponentEnum::UINT:
177 itk::ByteSwapper<int>::SwapRangeFromSystemToLittleEndian((int*)out,
178 num_scalars);
179 break;
180 case itk::IOComponentEnum::LONG:
181 case itk::IOComponentEnum::ULONG:
182 itk::ByteSwapper<long>::SwapRangeFromSystemToLittleEndian((long*)out,
183 num_scalars);
184 break;
185 case itk::IOComponentEnum::FLOAT:
186 itk::ByteSwapper<float>::SwapRangeFromSystemToLittleEndian((float*)out,
187 num_scalars);
188 break;
189 case itk::IOComponentEnum::DOUBLE:
190 itk::ByteSwapper<double>::SwapRangeFromSystemToLittleEndian(
191 (double*)out, num_scalars);
192 break;
193 default:
194 MITK_ERROR << "Can not handle pixel component type "
195 << type.GetComponentType();
196 return;
197 }
198
199 //copy timestamp of mitk image
200 igtl::TimeStamp::Pointer timestamp = igtl::TimeStamp::New();
201 timestamp->SetTime(img->GetMTime() / 1000, (int)(img->GetMTime()) % 1000);
202 imgMsg->SetTimeStamp(timestamp);
203
204 imgMsg->Pack();
205
206 output->SetMessage(imgMsg.GetPointer());
207 }
208}
209
211{
212 this->ProcessObject::SetNthInput(0, const_cast<mitk::Image*>(img));
213 this->CreateOutputsForAllInputs();
214}
215
217 const Image* img)
218{
219 this->ProcessObject::SetNthInput(idx, const_cast<mitk::Image*>(img));
220 this->CreateOutputsForAllInputs();
221}
222
224{
225 if (this->GetNumberOfInputs() < 1)
226 return nullptr;
227 return static_cast<const mitk::Image*>(this->ProcessObject::GetInput(0));
228}
229
230const mitk::Image* mitk::ImageToIGTLMessageFilter::GetInput(unsigned int idx)
231{
232 if (this->GetNumberOfInputs() < idx + 1)
233 {
234 return nullptr;
235 }
236 return static_cast<const mitk::Image*>(this->ProcessObject::GetInput(idx));
237}
238
239void mitk::ImageToIGTLMessageFilter::ConnectTo(mitk::ImageSource* upstream)
240{
241 MITK_INFO << "Image source for this (" << this << ") mitkImageToIGTLMessageFilter is " << upstream;
242 for (DataObjectPointerArraySizeType i = 0; i < upstream->GetNumberOfOutputs();
243 i++)
244 {
245 this->SetInput(i, upstream->GetOutput(i));
246 }
247}
248
250{
251 // create one message output for all image inputs
252 this->SetNumberOfIndexedOutputs(this->GetNumberOfIndexedInputs());
253
254 for (size_t idx = 0; idx < this->GetNumberOfIndexedOutputs(); ++idx)
255 {
256 if (this->GetOutput(idx) == nullptr)
257 {
258 this->SetNthOutput(idx, this->MakeOutput(idx));
259 }
260 this->Modified();
261 }
262}
A wrapper for the OpenIGTLink message type.
void SetMessage(igtl::MessageBase::Pointer msg)
Sets the OpenIGTLink message.
virtual void CreateOutputsForAllInputs()
create output objects for all inputs
const mitk::Image * GetInput()
Returns the input of this filter.
void GenerateData() override
filter execute method
virtual void SetInput(const mitk::Image *img)
Sets one input Image.
virtual void ConnectTo(mitk::ImageSource *UpstreamFilter)