PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusUsSimulatorVideoSource.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2  Program: Plus
3  Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
4  See License.txt for details.
5 =========================================================Plus=header=end*/
6 
7 #include "PlusConfigure.h"
8 #include "vtkImageData.h"
9 #include "vtkObjectFactory.h"
10 #include "vtkIGSIOTrackedFrameList.h"
11 #include "vtkPlusChannel.h"
12 #include "vtkPlusDataSource.h"
14 #include "vtkIGSIOTransformRepository.h"
18 
20 
21 //----------------------------------------------------------------------------
23  : UsSimulator(NULL)
24  , LastProcessedTrackingDataTimestamp(0)
25  , GracePeriodLogLevel(vtkPlusLogger::LOG_LEVEL_DEBUG)
26 {
27  // Create and set up US simulator
28  vtkSmartPointer<vtkPlusUsSimulatorAlgo> usSimulator = vtkSmartPointer<vtkPlusUsSimulatorAlgo>::New();
29  this->SetUsSimulator(usSimulator);
30 
31  // Create transform repository
32  vtkSmartPointer<vtkIGSIOTransformRepository> transformRepository = vtkSmartPointer<vtkIGSIOTransformRepository>::New();
33  this->GetUsSimulator()->SetTransformRepository(transformRepository);
34 
36 
37  // No callback function provided by the device, so the data capture thread will be used to poll the hardware and add new items to the buffer
38  this->StartThreadForInternalUpdates = true;
39 }
40 
41 //----------------------------------------------------------------------------
43 {
44  if (!this->Connected)
45  {
46  this->Disconnect();
47  }
48 
49  this->SetUsSimulator(NULL);
50 }
51 
52 //----------------------------------------------------------------------------
53 void vtkPlusUsSimulatorVideoSource::PrintSelf(ostream& os, vtkIndent indent)
54 {
55  this->Superclass::PrintSelf(os, indent);
56 }
57 
58 //----------------------------------------------------------------------------
60 {
61  //LOG_TRACE("vtkPlusUsSimulatorVideoSource::InternalUpdate");
62 
63  if (this->InputChannels.size() != 1)
64  {
65  LOG_ERROR("vtkPlusUsSimulatorVideoSource device requires exactly 1 input stream (that contains the tracking data). Check configuration.");
66  return PLUS_FAIL;
67  }
68 
69  if (this->HasGracePeriodExpired())
70  {
71  this->GracePeriodLogLevel = vtkPlusLogger::LOG_LEVEL_WARNING;
72  }
73 
74  // Get image to tracker transform from the tracker (only request 1 frame, the latest)
75  vtkSmartPointer<vtkIGSIOTrackedFrameList> trackingFrames = vtkSmartPointer<vtkIGSIOTrackedFrameList>::New();
76  if (!this->InputChannels[0]->GetTrackingDataAvailable())
77  {
78  LOG_DEBUG("Simulated US image is not generated, as no tracking data is available yet. Device ID: " << this->GetDeviceId());
79  return PLUS_SUCCESS;
80  }
81  double oldestTrackingTimestamp(0);
82  if (this->InputChannels[0]->GetOldestTimestamp(oldestTrackingTimestamp) == PLUS_SUCCESS)
83  {
84  if (this->LastProcessedTrackingDataTimestamp < oldestTrackingTimestamp)
85  {
86  LOG_INFO("Simulated US image generation started. No tracking data was available between " << this->LastProcessedTrackingDataTimestamp << "-" << oldestTrackingTimestamp <<
87  "sec, therefore no simulated images were generated during this time period.");
88  this->LastProcessedTrackingDataTimestamp = oldestTrackingTimestamp;
89  }
90  }
91  if (this->InputChannels[0]->GetTrackedFrameList(this->LastProcessedTrackingDataTimestamp, trackingFrames, 1) != PLUS_SUCCESS)
92  {
93  LOG_ERROR("Error while getting tracked frame list from data collector during capturing. Last recorded timestamp: " << std::fixed << this->LastProcessedTrackingDataTimestamp << ". Device ID: " << this->GetDeviceId());
94  this->LastProcessedTrackingDataTimestamp = vtkIGSIOAccurateTimer::GetSystemTime(); // forget about the past, try to add frames that are acquired from now on
95  return PLUS_FAIL;
96  }
97  if (trackingFrames->GetNumberOfTrackedFrames() < 1)
98  {
99  LOG_DYNAMIC("Simulated US image generation is skipped, as as no updated tracking data has become available since the last generated image (at " << this->LastProcessedTrackingDataTimestamp << "). Probably the tracker device acquisition rate is lower than the simulator acquisition rate. Device ID: " << this->GetDeviceId(), this->GracePeriodLogLevel);
100  return PLUS_FAIL;
101  }
102  igsioTrackedFrame* trackedFrame = trackingFrames->GetTrackedFrame(0);
103  if (trackedFrame == NULL)
104  {
105  LOG_ERROR("Error while getting tracked frame from data collector during capturing. Last recorded timestamp: " << std::fixed << this->LastProcessedTrackingDataTimestamp << ". Device ID: " << this->GetDeviceId());
106  return PLUS_FAIL;
107  }
108 
109  // Get latest tracker timestamp
110  double latestTrackerTimestamp = trackedFrame->GetTimestamp();
111 
112  if (this->OutputChannels.empty())
113  {
114  LOG_ERROR("No output channels defined");
115  return PLUS_FAIL;
116  }
117  vtkPlusChannel* outputChannel = this->OutputChannels[0];
118  double latestFrameAlreadyAddedTimestamp = 0;
119  outputChannel->GetMostRecentTimestamp(latestFrameAlreadyAddedTimestamp);
120  if (latestFrameAlreadyAddedTimestamp >= latestTrackerTimestamp)
121  {
122  LOG_DEBUG("Simulated frame has been already generated for timestamp: " << latestFrameAlreadyAddedTimestamp);
123  return PLUS_SUCCESS;
124  }
125 
126  // The sampling rate is constant, so to have a constant frame rate we have to increase the FrameNumber by a constant.
127  // For simplicity, we increase it always by 1.
128  this->FrameNumber++;
129 
130  if (this->UsSimulator->GetTransformRepository()->SetTransforms(*trackedFrame) != PLUS_SUCCESS)
131  {
132  LOG_ERROR("Failed to set repository transforms from tracked frame!");
133  return PLUS_FAIL;
134  }
135 
136  // Get the simulated US image
137  this->UsSimulator->Modified(); // Signal that the transforms have changed so we need to recompute
138  this->UsSimulator->Update();
139 
140  vtkPlusDataSource* aSource(NULL);
141  if (outputChannel->GetVideoSource(aSource) != PLUS_SUCCESS)
142  {
143  LOG_ERROR("Unable to retrieve the video source in the USSimulator device.");
144  return PLUS_FAIL;
145  }
146 
147  LOG_DEBUG("Simulated frame " << this->FrameNumber << " generated.");
148  PlusStatus status = aSource->AddItem(
149  this->UsSimulator->GetOutput(), aSource->GetInputImageOrientation(), US_IMG_BRIGHTNESS, this->FrameNumber, latestTrackerTimestamp, latestTrackerTimestamp);
150 
151  this->Modified();
152  return status;
153 }
154 
155 //----------------------------------------------------------------------------
157 {
158  LOG_TRACE("vtkPlusUsSimulatorVideoSource::InternalConnect");
159 
160  if (this->OutputChannels.empty())
161  {
162  LOG_ERROR("No output channels defined");
163  return PLUS_FAIL;
164  }
165  vtkPlusChannel* outputChannel = this->OutputChannels[0];
166 
167  vtkPlusDataSource* aSource(NULL);
168  if (outputChannel->GetVideoSource(aSource) != PLUS_SUCCESS)
169  {
170  LOG_ERROR("Unable to retrieve the video source in the USSimulator device.");
171  return PLUS_FAIL;
172  }
173 
174  // Set to default MF output image orientation
175  aSource->SetOutputImageOrientation(US_IMG_ORIENT_MF);
176  aSource->Clear();
177  FrameSizeType frameSize = {0, 0, 1};
178  if (this->UsSimulator->GetFrameSize(frameSize) != PLUS_SUCCESS)
179  {
180  LOG_ERROR("Failed to initialize buffer, frame size is unknown");
181  return PLUS_FAIL;
182  }
183  aSource->SetInputFrameSize(frameSize);
184 
186  {
188  }
190  {
192  vtkPlusUsScanConvertLinear* linearScanConverter = vtkPlusUsScanConvertLinear::SafeDownCast(scanConverter);
193  vtkPlusUsScanConvertCurvilinear* curvilinearScanConverter = vtkPlusUsScanConvertCurvilinear::SafeDownCast(scanConverter);
194  if (linearScanConverter)
195  {
196  this->ImagingParameters->SetDepthMm(linearScanConverter->GetImagingDepthMm());
197  }
198  else if (curvilinearScanConverter)
199  {
201  curvilinearScanConverter->GetRadiusStopMm() - curvilinearScanConverter->GetRadiusStartMm());
202  }
203  }
205  {
207  }
209  {
211  }
212 
214 
215  return PLUS_SUCCESS;
216 }
217 
218 //----------------------------------------------------------------------------
220 {
221  return PLUS_SUCCESS;
222 }
223 
224 //-----------------------------------------------------------------------------
226 {
227  LOG_TRACE("vtkPlusUsSimulatorVideoSource::ReadConfiguration");
228  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
229 
230  // Read US simulator configuration
231  if (!this->UsSimulator
232  || this->UsSimulator->ReadConfiguration(deviceConfig) != PLUS_SUCCESS)
233  {
234  LOG_ERROR("Failed to read US simulator configuration!");
235  return PLUS_FAIL;
236  }
237 
238  // Read transform repository configuration
239  if (!this->UsSimulator->GetTransformRepository()
240  || this->UsSimulator->GetTransformRepository()->ReadConfiguration(rootConfigElement) != PLUS_SUCCESS)
241  {
242  LOG_ERROR("Failed to read transform repository configuration!");
243  return PLUS_FAIL;
244  }
245 
246  return PLUS_SUCCESS;
247 }
248 
249 //----------------------------------------------------------------------------
251 {
252  if (this->OutputChannels.size() > 1)
253  {
254  LOG_WARNING("vtkPlusUsSimulatorVideoSource is expecting one output channel and there are " << this->OutputChannels.size() << " channels. First output channel will be used.");
255  }
256 
257  if (this->OutputChannels.empty())
258  {
259  LOG_ERROR("No output channels defined for vtkPlusUsSimulatorVideoSource. Cannot proceed.");
260  this->SetCorrectlyConfigured(false);
261  return PLUS_FAIL;
262  }
263 
264  return PLUS_SUCCESS;
265 }
266 
267 //----------------------------------------------------------------------------
269 {
272  {
274  vtkPlusUsScanConvertLinear* linearScanConverter = vtkPlusUsScanConvertLinear::SafeDownCast(scanConverter);
275  vtkPlusUsScanConvertCurvilinear* curvilinearScanConverter = vtkPlusUsScanConvertCurvilinear::SafeDownCast(scanConverter);
276  if (linearScanConverter)
277  {
278  linearScanConverter->SetImagingDepthMm(this->ImagingParameters->GetDepthMm());
279  }
280  else if (curvilinearScanConverter)
281  {
282  curvilinearScanConverter->SetRadiusStopMm(
283  curvilinearScanConverter->GetRadiusStartMm() + this->ImagingParameters->GetDepthMm() );
284  }
286  }
289  {
292  }
295  {
298  }
301  {
304  }
305 
306  //TODO: Acknowledge parameter change
307  // (if here then need to trust developer, or do it everywhere this function is called)
308 
309  return PLUS_SUCCESS;
310 }
virtual void SetBrightnessConversionGamma(double)
virtual double GetRadiusStartMm()
bool IsPending(const std::string &paramName) const
virtual PlusStatus SetOutputImageOrientation(US_IMAGE_ORIENTATION imageOrientation)
virtual vtkIGSIOTransformRepository * GetTransformRepository()
static vtkPlusUsScanConvertCurvilinear * SafeDownCast(vtkObject *o)
Class to abstract away specific sequence file read/write details.
Definition: vtkPlusLogger.h:21
virtual void SetImagingDepthMm(double)
igsioStatus PlusStatus
Definition: PlusCommon.h:40
ChannelContainer InputChannels
PlusStatus SetContrast(double aContrast)
PlusStatus GetDepthMm(double &aDepthMm) const
virtual vtkPlusUsScanConvert * GetScanConverter()
virtual std::string GetDeviceId() const
PlusStatus SetInputFrameSize(unsigned int x, unsigned int y, unsigned int z)
virtual PlusStatus AddItem(vtkImageData *frame, US_IMAGE_ORIENTATION usImageOrientation, US_IMAGE_TYPE imageType, long frameNumber, double unfilteredTimestamp=UNDEFINED_TIMESTAMP, double filteredTimestamp=UNDEFINED_TIMESTAMP, const igsioFieldMapType *customFields=NULL)
virtual double GetRadiusStopMm()
vtkPlusUsImagingParameters * ImagingParameters
Store the current imaging parameters.
bool RequireImageOrientationInConfiguration
virtual void SetRadiusStopMm(double)
PlusStatus SetPending(const std::string &paramName, bool pending)
virtual void SetTransformRepository(vtkIGSIOTransformRepository *)
#define PLUS_FAIL
Definition: PlusCommon.h:43
virtual void SetUsSimulator(vtkPlusUsSimulatorAlgo *)
virtual PlusStatus Disconnect()
virtual void SetIncomingIntensityMwPerCm2(double)
virtual void SetCorrectlyConfigured(bool)
unsigned long FrameNumber
vtkStandardNewMacro(vtkPlusUsSimulatorVideoSource)
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
virtual PlusStatus GetMostRecentTimestamp(double &ts)
virtual double GetImagingDepthMm()
PlusStatus GetContrast(double &aContrast) const
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
virtual double GetBrightnessConversionGamma()
virtual double GetIncomingIntensityMwPerCm2()
virtual vtkPlusUsSimulatorAlgo * GetUsSimulator()
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
virtual US_IMAGE_ORIENTATION GetInputImageOrientation()
bool StartThreadForInternalUpdates
Class for providing VTK video input interface from simulated ultrasound.
This class performs scan conversion from scan lines for curvilinear probes.
bool HasGracePeriodExpired()
virtual double GetFrequencyMhz()
PlusStatus SetIntensity(double aIntensity)
Contains an optional timestamped circular buffer containing the video images and a number of timestam...
PlusStatus SetFrequencyMhz(double aFrequencyMhz)
ChannelContainer OutputChannels
PlusStatus GetFrequencyMhz(double &aFrequencyMhz) const
This is a base class for defining a common scan conversion algorithm interface for all kinds of probe...
This class performs scan conversion from scan lines for curvilinear probes.
PlusStatus GetIntensity(double &aIntensity) const
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
virtual void SetFrequencyMhz(double)
bool IsSet(const std::string &paramName) const
static vtkPlusUsScanConvertLinear * SafeDownCast(vtkObject *o)
PlusStatus GetVideoSource(vtkPlusDataSource *&aVideoSource) const
virtual vtkPlusRfProcessor * GetRfProcessor()
PlusStatus SetDepthMm(double aDepthMm)
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
vtkPlusLogger::LogLevelType GracePeriodLogLevel
PlusStatus GetFrameSize(FrameSizeType &frameSize)
Interface to a 3D positioning tool, video source, or generalized data stream.