Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkUSDevice.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,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 #include "mitkUSDevice.h"
18 #include "mitkImageReadAccessor.h"
19 
20 // US Control Interfaces
24 
25 // Microservices
26 #include <usGetModuleContext.h>
27 #include <usModule.h>
28 #include <usServiceProperties.h>
29 #include <usModuleContext.h>
30 
31 mitk::USDevice::PropertyKeys mitk::USDevice::GetPropertyKeys()
32 {
33  static mitk::USDevice::PropertyKeys propertyKeys;
34  return propertyKeys;
35 }
36 
38 {
39  MITK_INFO << "Return Crop Area L:" << m_CropArea.cropLeft
40  << " R:" << m_CropArea.cropRight << " T:" << m_CropArea.cropTop
41  << " B:" << m_CropArea.cropBottom;
42  return m_CropArea;
43 }
44 
45 mitk::USDevice::USDevice(std::string manufacturer, std::string model)
46  : mitk::ImageSource(),
47  m_IsFreezed(false),
48  m_DeviceState(State_NoState),
49  m_Manufacturer(manufacturer),
50  m_Name(model),
51  m_SpawnAcquireThread(true),
52  m_MultiThreader(itk::MultiThreader::New()),
53  m_ImageMutex(itk::FastMutexLock::New()),
54  m_ThreadID(-1),
55  m_UnregisteringStarted(false)
56 {
57  USImageCropArea empty;
58  empty.cropBottom = 0;
59  empty.cropTop = 0;
60  empty.cropLeft = 0;
61  empty.cropRight = 0;
62  this->m_CropArea = empty;
63 
64  // set number of outputs
65  this->SetNumberOfIndexedOutputs(1);
66 
67  // create a new output
69  this->SetNthOutput(0, newOutput);
70 }
71 
73  : mitk::ImageSource(),
74  m_IsFreezed(false),
75  m_DeviceState(State_NoState),
76  m_SpawnAcquireThread(true),
77  m_MultiThreader(itk::MultiThreader::New()),
78  m_ImageMutex(itk::FastMutexLock::New()),
79  m_ThreadID(-1),
80  m_UnregisteringStarted(false)
81 {
82  m_Manufacturer = metadata->GetDeviceManufacturer();
83  m_Name = metadata->GetDeviceModel();
84  m_Comment = metadata->GetDeviceComment();
85 
86  USImageCropArea empty;
87  empty.cropBottom = 0;
88  empty.cropTop = 0;
89  empty.cropLeft = 0;
90  empty.cropRight = 0;
91  this->m_CropArea = empty;
92 
93  // set number of outputs
94  this->SetNumberOfIndexedOutputs(1);
95 
96  // create a new output
98  this->SetNthOutput(0, newOutput);
99 }
100 
102 {
103  if (m_ThreadID >= 0)
104  {
105  m_MultiThreader->TerminateThread(m_ThreadID);
106  }
107 
108  // make sure that the us device is not registered at the micro service
109  // anymore after it is destructed
110  this->UnregisterOnService();
111 }
112 
115 {
116  MITK_INFO << "Custom control interface does not exist for this object.";
117  return 0;
118 }
119 
122 {
123  MITK_INFO << "Control interface BMode does not exist for this object.";
124  return 0;
125 }
126 
129 {
130  MITK_INFO << "Control interface Probes does not exist for this object.";
131  return 0;
132 }
133 
136 {
137  MITK_INFO << "Control interface Doppler does not exist for this object.";
138  return 0;
139 }
140 
141 void mitk::USDevice::SetManufacturer(std::string manufacturer)
142 {
143  m_Manufacturer = manufacturer;
144  if (m_DeviceState >= State_Initialized)
145  {
146  this->UpdateServiceProperty(
147  mitk::USDevice::GetPropertyKeys().US_PROPKEY_MANUFACTURER,
148  manufacturer);
149  }
150 }
151 
152 void mitk::USDevice::SetName(std::string name)
153 {
154  m_Name = name;
155  if (m_DeviceState >= State_Initialized)
156  {
157  this->UpdateServiceProperty(
158  mitk::USDevice::GetPropertyKeys().US_PROPKEY_NAME, name);
159  }
160 }
161 
162 void mitk::USDevice::SetComment(std::string comment)
163 {
164  m_Comment = comment;
165  if (m_DeviceState >= State_Initialized)
166  {
167  this->UpdateServiceProperty(
168  mitk::USDevice::GetPropertyKeys().US_PROPKEY_COMMENT, comment);
169  }
170 }
171 
173 {
174  mitk::USDevice::PropertyKeys propertyKeys = mitk::USDevice::GetPropertyKeys();
175 
176  us::ServiceProperties props;
177 
178  props[propertyKeys.US_PROPKEY_ISCONNECTED] =
179  this->GetIsConnected() ? "true" : "false";
180  props[propertyKeys.US_PROPKEY_ISACTIVE] =
181  this->GetIsActive() ? "true" : "false";
182 
183  props[propertyKeys.US_PROPKEY_LABEL] = this->GetServicePropertyLabel();
184 
185  // get identifier of selected probe if there is one selected
187  this->GetControlInterfaceProbes();
188  if (probesControls.IsNotNull() && probesControls->GetIsActive())
189  {
190  mitk::USProbe::Pointer probe = probesControls->GetSelectedProbe();
191  if (probe.IsNotNull())
192  {
193  props[propertyKeys.US_PROPKEY_PROBES_SELECTED] = probe->GetName();
194  }
195  }
196 
197  props[propertyKeys.US_PROPKEY_CLASS] = GetDeviceClass();
198  props[propertyKeys.US_PROPKEY_MANUFACTURER] = m_Manufacturer;
199  props[propertyKeys.US_PROPKEY_NAME] = m_Name;
200  props[propertyKeys.US_PROPKEY_COMMENT] = m_Comment;
201 
202  m_ServiceProperties = props;
203 
204  return props;
205 }
206 
208 {
209  // unregister on micro service
210  if (m_ServiceRegistration && !m_UnregisteringStarted)
211  {
212  // make sure that unregister is not started a second
213  // time due to a callback during unregister for example
214  m_UnregisteringStarted = true;
215  m_ServiceRegistration.Unregister();
216  m_ServiceRegistration = 0;
217  }
218 }
219 
221 {
222  if (!this->OnInitialization())
223  {
224  return false;
225  }
226 
227  m_DeviceState = State_Initialized;
228 
229  // Get Context and Module
230  us::ModuleContext* context = us::GetModuleContext();
231  us::ServiceProperties props = this->ConstructServiceProperties();
232 
233  m_ServiceRegistration = context->RegisterService(this, props);
234 
235  return true;
236 }
237 
239 {
240  MITK_DEBUG << "mitk::USDevice::Connect() called";
241 
242  if (this->GetIsConnected())
243  {
244  MITK_INFO("mitkUSDevice") << "Tried to connect an ultrasound device that "
245  "was already connected. Ignoring call...";
246  return true;
247  }
248 
249  if (!this->GetIsInitialized())
250  {
251  MITK_ERROR("mitkUSDevice")
252  << "Cannot connect device if it is not in initialized state.";
253  return false;
254  }
255 
256  // Prepare connection, fail if this fails.
257  if (!this->OnConnection())
258  {
259  return false;
260  }
261 
262  // Update state
263  m_DeviceState = State_Connected;
264 
265  this->UpdateServiceProperty(
266  mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISCONNECTED, true);
267  return true;
268 }
269 
271 {
272  this->m_MultiThreader->SpawnThread(this->ConnectThread, this);
273 }
274 
276 {
277  if (!GetIsConnected())
278  {
279  MITK_WARN << "Tried to disconnect an ultrasound device that was not "
280  "connected. Ignoring call...";
281  return false;
282  }
283  // Prepare connection, fail if this fails.
284  if (!this->OnDisconnection())
285  return false;
286 
287  // Update state
288  m_DeviceState = State_Initialized;
289 
290  this->UpdateServiceProperty(
291  mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISCONNECTED, false);
292 
293  return true;
294 }
295 
297 {
298  if (!this->GetIsConnected())
299  {
300  MITK_INFO("mitkUSDevice")
301  << "Cannot activate device if it is not in connected state.";
302  return true;
303  }
304 
305  if (OnActivation())
306  {
307  m_DeviceState = State_Activated;
308 
309  m_FreezeBarrier = itk::ConditionVariable::New();
310 
311  // spawn thread for aquire images if us device is active
312  if (m_SpawnAcquireThread)
313  {
314  this->m_ThreadID =
315  this->m_MultiThreader->SpawnThread(this->Acquire, this);
316  }
317 
318  this->UpdateServiceProperty(
319  mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE, true);
320  this->UpdateServiceProperty(
321  mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL,
322  this->GetServicePropertyLabel());
323  // initialize the b mode control properties of the micro service
325  this->GetControlInterfaceBMode();
326  if (bmodeControls.IsNotNull())
327  {
328  bmodeControls->Initialize();
329  }
330  }
331 
332  this->ProvideViaOIGTL();
333 
334  return m_DeviceState == State_Activated;
335 }
336 
338 {
339  // create a new OpenIGTLink Server
340  if (m_IGTLServer.IsNull())
341  m_IGTLServer = mitk::IGTLServer::New(true);
342 
343  m_IGTLServer->SetName(this->GetName());
344 
345  // create a new OpenIGTLink Device source
346  if (m_IGTLMessageProvider.IsNull())
347  m_IGTLMessageProvider = mitk::IGTLMessageProvider::New();
348 
349  // set the OpenIGTLink server as the source for the device source
350  m_IGTLMessageProvider->SetIGTLDevice(m_IGTLServer);
351 
352  // register the provider so that it can be configured with the IGTL manager
353  // plugin. This could be hardcoded but now I already have the fancy plugin.
354  m_IGTLMessageProvider->RegisterAsMicroservice();
355 
356  m_ImageToIGTLMsgFilter = mitk::ImageToIGTLMessageFilter::New();
357  m_ImageToIGTLMsgFilter->ConnectTo(this);
358 
359  // set the name of this filter to identify it easier
360  m_ImageToIGTLMsgFilter->SetName(this->GetName());
361 
362  // register this filter as micro service. The message provider looks for
363  // provided IGTLMessageSources, once it found this microservice and someone
364  // requested this data type then the provider will connect with this filter
365  // automatically.
366  m_ImageToIGTLMsgFilter->RegisterAsMicroservice();
367 }
368 
370 {
371  if (!this->GetIsActive())
372  {
373  MITK_WARN("mitkUSDevice")
374  << "Cannot deactivate a device which is not activae.";
375  return;
376  }
377 
378  if (!OnDeactivation())
379  {
380  return;
381  }
382 
383  DisableOIGTL();
384  m_DeviceState = State_Connected;
385 
386  this->UpdateServiceProperty(
387  mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE, false);
388  this->UpdateServiceProperty(
389  mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL,
390  this->GetServicePropertyLabel());
391 }
392 
394 {
395  // TODO: This seems not to be enough cleanup to catch all cases. For example, if the device is disconnected
396  // from the OIGTL GUI, this won't get cleaned up correctly.
397  m_IGTLServer->CloseConnection();
398  m_IGTLMessageProvider->UnRegisterMicroservice();
399  m_ImageToIGTLMsgFilter->UnRegisterMicroservice();
400 }
401 
403 {
404  if (!this->GetIsActive())
405  {
406  MITK_WARN("mitkUSDevice")
407  << "Cannot freeze or unfreeze if device is not active.";
408  return;
409  }
410 
411  this->OnFreeze(freeze);
412 
413  if (freeze)
414  {
415  m_IsFreezed = true;
416  }
417  else
418  {
419  m_IsFreezed = false;
420 
421  // wake up the image acquisition thread
422  m_FreezeBarrier->Signal();
423  }
424 }
425 
427 {
428  if (!this->GetIsActive())
429  {
430  MITK_WARN("mitkUSDevice")("mitkUSTelemedDevice")
431  << "Cannot get freeze state if the hardware interface is not ready. "
432  "Returning false...";
433  return false;
434  }
435 
436  return m_IsFreezed;
437 }
438 
440 {
441  mitk::USImageSource::Pointer imageSource = this->GetUSImageSource();
442  if (imageSource.IsNull())
443  {
444  MITK_ERROR << "ImageSource must not be null when pushing a filter.";
445  mitkThrow() << "ImageSource must not be null when pushing a filter.";
446  }
447 
448  imageSource->PushFilter(filter);
449 }
450 
453 {
454  mitk::USImageSource::Pointer imageSource = this->GetUSImageSource();
455  if (imageSource.IsNull())
456  {
457  MITK_ERROR << "ImageSource must not be null when pushing a filter.";
458  mitkThrow() << "ImageSource must not be null when pushing a filter.";
459  }
460 
461  if (!imageSource->GetIsFilterInThePipeline(filter))
462  {
463  imageSource->PushFilter(filter);
464  }
465 }
466 
468 {
469  mitk::USImageSource::Pointer imageSource = this->GetUSImageSource();
470  if (imageSource.IsNull())
471  {
472  MITK_ERROR << "ImageSource must not be null when pushing a filter.";
473  mitkThrow() << "ImageSource must not be null when removing a filter.";
474  }
475 
476  return imageSource->RemoveFilter(filter);
477 }
478 
479 void mitk::USDevice::UpdateServiceProperty(std::string key, std::string value)
480 {
481  m_ServiceProperties[key] = value;
482  m_ServiceRegistration.SetProperties(m_ServiceProperties);
483 
484  // send event to notify listeners about the changed property
485  m_PropertyChangedMessage(key, value);
486 }
487 
488 void mitk::USDevice::UpdateServiceProperty(std::string key, double value)
489 {
490  std::stringstream stream;
491  stream << value;
492  this->UpdateServiceProperty(key, stream.str());
493 }
494 
495 void mitk::USDevice::UpdateServiceProperty(std::string key, bool value)
496 {
497  this->UpdateServiceProperty(
498  key, value ? std::string("true") : std::string("false"));
499 }
500 
547 {
548  mitk::Image::Pointer image = this->GetUSImageSource()->GetNextImage();
549  m_ImageMutex->Lock();
550  this->SetImage(image);
551  m_ImageMutex->Unlock();
552  // if (image.IsNotNull() && (image->GetGeometry()!=NULL)){
553  // MITK_INFO << "Spacing: " << image->GetGeometry()->GetSpacing();}
554 }
555 
556 //########### GETTER & SETTER ##################//
557 
559 {
560  return m_DeviceState == State_Initialized;
561 }
562 
563 bool mitk::USDevice::GetIsActive() { return m_DeviceState == State_Activated; }
564 
566 {
567  return m_DeviceState == State_Connected;
568 }
569 
570 std::string mitk::USDevice::GetDeviceManufacturer() { return m_Manufacturer; }
571 
572 std::string mitk::USDevice::GetDeviceModel() { return m_Name; }
573 
574 std::string mitk::USDevice::GetDeviceComment() { return m_Comment; }
575 
577 {
578  m_ImageMutex->Lock();
579 
580  if (m_Image.IsNull() || !m_Image->IsInitialized())
581  {
582  m_ImageMutex->Unlock();
583  return;
584  }
585 
586  mitk::Image::Pointer output = this->GetOutput();
587 
588  if (!output->IsInitialized() ||
589  output->GetDimension(0) != m_Image->GetDimension(0) ||
590  output->GetDimension(1) != m_Image->GetDimension(1))
591  {
592  output->Initialize(m_Image->GetPixelType(), m_Image->GetDimension(),
593  m_Image->GetDimensions());
594  }
595 
596  mitk::ImageReadAccessor inputReadAccessor(m_Image,
597  m_Image->GetSliceData(0, 0, 0));
598  output->SetSlice(inputReadAccessor.GetData());
599  output->SetGeometry(m_Image->GetGeometry());
600  m_ImageMutex->Unlock();
601 };
602 
604 {
605  std::string isActive;
606  if (this->GetIsActive())
607  {
608  isActive = " (Active)";
609  }
610  else
611  {
612  isActive = " (Inactive)";
613  }
614  // e.g.: Zonare MyLab5 (Active)
615  return m_Manufacturer + " " + m_Name + isActive;
616 }
617 
618 ITK_THREAD_RETURN_TYPE mitk::USDevice::Acquire(void* pInfoStruct)
619 {
620  /* extract this pointer from Thread Info structure */
621  struct itk::MultiThreader::ThreadInfoStruct* pInfo =
622  (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct;
623  mitk::USDevice* device = (mitk::USDevice*)pInfo->UserData;
624  while (device->GetIsActive())
625  {
626  // lock this thread when ultrasound device is freezed
627  if (device->m_IsFreezed)
628  {
629  itk::SimpleMutexLock* mutex = &(device->m_FreezeMutex);
630  mutex->Lock();
631 
632  if (device->m_FreezeBarrier.IsNotNull())
633  {
634  device->m_FreezeBarrier->Wait(mutex);
635  }
636  }
637 
638  device->GrabImage();
639  }
640  return ITK_THREAD_RETURN_VALUE;
641 }
642 
643 ITK_THREAD_RETURN_TYPE mitk::USDevice::ConnectThread(void* pInfoStruct)
644 {
645  /* extract this pointer from Thread Info structure */
646  struct itk::MultiThreader::ThreadInfoStruct* pInfo =
647  (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct;
648  mitk::USDevice* device = (mitk::USDevice*)pInfo->UserData;
649 
650  device->Connect();
651 
652  return ITK_THREAD_RETURN_VALUE;
653 }
654 
655 
656 void mitk::USDevice::ProbeChanged(std::string probename)
657 {
658  this->UpdateServiceProperty(mitk::USDevice::GetPropertyKeys().US_PROPKEY_PROBES_SELECTED, probename);
659 }
660 
662 {
663  this->UpdateServiceProperty(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH, depth);
664 }
virtual itk::SmartPointer< USControlInterfaceBMode > GetControlInterfaceBMode()
Default getter for the b mode control interface. Has to be implemented in a subclass if a b mode cont...
Superclass of all classes generating Images (instances of class Image) as output. ...
bool Activate()
Activates this device. After the activation process, the device will start to produce images...
A device holds information about it's model, make and the connected probes. It is the common super cl...
Definition: mitkUSDevice.h:77
void UpdateServiceProperty(std::string key, std::string value)
Given property is updated in the device micro service. This method is mainly for being used by the co...
static ITK_THREAD_RETURN_TYPE Acquire(void *pInfoStruct)
itk::SmartPointer< Self > Pointer
std::string GetDeviceComment()
Deprecated -> use GetCommend() instead.
#define MITK_INFO
Definition: mitkLogMacros.h:22
#define MITK_ERROR
Definition: mitkLogMacros.h:24
void PushFilterIfNotPushedBefore(AbstractOpenCVImageFilter::Pointer filter)
USImageCropArea m_CropArea
Definition: mitkUSDevice.h:346
const std::string US_PROPKEY_LABEL
Definition: mitkUSDevice.h:105
us::ServiceProperties ConstructServiceProperties()
This Method constructs the service properties which can later be used to register the object with the...
#define MITK_DEBUG
Definition: mitkLogMacros.h:26
DataCollection - Class to facilitate loading/accessing structured data.
const std::string US_PROPKEY_ISCONNECTED
Definition: mitkUSDevice.h:106
void DisableOIGTL()
Deregisters the microservices for OpenIGTLink.
bool Connect()
Connects this device. A connected device is ready to deliver images (i.e. be Activated). A Connected Device can be active. A disconnected Device cannot be active. Internally calls onConnect and then registers the device with the service. A device usually should override the OnConnection() method, but never the Connect() method, since this will possibly exclude the device from normal service management. The exact flow of events is: 0. Check if the device is already connected. If yes, return true anyway, but don't do anything.
bool GetIsConnected()
True, if the device is currently ready to start transmitting image data or is already transmitting im...
std::string GetDeviceManufacturer()
Deprecated -> use GetManufacturer() instead.
mitk::USDevice::USImageCropArea GetCropArea()
void ProbeChanged(std::string probename)
To be called when the used probe changed. Will update the service properties.
virtual itk::SmartPointer< USControlInterfaceDoppler > GetControlInterfaceDoppler()
Default getter for the doppler control interface. Has to be implemented in a subclass if a doppler co...
void DepthChanged(double depth)
To be called when the scanning depth of the probe changed. Will update the service properties...
const std::string US_PROPKEY_CLASS
Definition: mitkUSDevice.h:108
void SetComment(std::string comment)
#define MITK_WARN
Definition: mitkLogMacros.h:23
std::string GetDeviceModel()
Deprecated -> use GetName() instead.
These constants are used in conjunction with Microservices. The constants aren't defined as static me...
Definition: mitkUSDevice.h:99
static Pointer New()
void SetManufacturer(std::string manufacturer)
#define mitkThrow()
virtual void SetIsFreezed(bool freeze)
Can toggle if ultrasound image is currently updated or freezed.
const std::string US_PROPKEY_PROBES_SELECTED
Definition: mitkUSDevice.h:110
USDevice(std::string manufacturer, std::string model)
Enforces minimal Metadata to be set.
void ConnectAsynchron()
bool Initialize()
Changes device state to mitk::USDevice::State_Initialized. During initialization the virtual method m...
virtual ~USDevice()
static Pointer New()
void UnregisterOnService()
Remove this device from the micro service.
const std::string US_PROPKEY_MANUFACTURER
Definition: mitkUSDevice.h:102
US_UNORDERED_MAP_TYPE< std::string, Any > ServiceProperties
void SetName(std::string name)
virtual bool GetIsFreezed()
void Deactivate()
Deactivates this device. After the deactivation process, the device will no longer produce images...
static std::string GetName(std::string fileName, std::string suffix)
virtual void GenerateData() override
Grabs the next frame from the Video input. This method is called internally, whenever Update() is inv...
const std::string US_PROPKEY_ISACTIVE
Definition: mitkUSDevice.h:107
bool GetIsInitialized()
True, if the device object is created and initialized, false otherwise.
const std::string US_PROPKEY_NAME
Definition: mitkUSDevice.h:103
static ITK_THREAD_RETURN_TYPE ConnectThread(void *pInfoStruct)
ImageReadAccessor class to get locked read access for a particular image part.
void PushFilter(AbstractOpenCVImageFilter::Pointer filter)
bool GetIsActive()
True, if the device is currently generating image data, false otherwise.
void ProvideViaOIGTL()
Registers an OpenIGTLink device as a microservice so that we can send the images of this device via t...
virtual mitkNewMessage2Macro(PropertyChanged, const std::string &, const std::string &) static mitk itk::SmartPointer< USAbstractControlInterface > GetControlInterfaceCustom()
Event for being notified about changes of the micro service properties. This event can be used if no ...
Definition: mitkUSDevice.h:156
bool Disconnect()
Works analogously to mitk::USDevice::Connect(). Don't override this Method, but onDisconnection inste...
static ModuleContext * GetModuleContext()
Returns the module context of the calling module.
const std::string US_PROPKEY_COMMENT
Definition: mitkUSDevice.h:104
bool RemoveFilter(AbstractOpenCVImageFilter::Pointer filter)
std::string GetServicePropertyLabel()
virtual itk::SmartPointer< USControlInterfaceProbes > GetControlInterfaceProbes()
Default getter for the probes control interface. Has to be implemented in a subclass if a probes cont...
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.