PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusVirtualDeinterlacer.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 // Local includes
8 #include "PlusConfigure.h"
9 #include "vtkPlusChannel.h"
10 #include "vtkPlusDataSource.h"
12 
13 // IGSIO includes
14 #include <igsioVideoFrame.h>
15 #include <vtkIGSIOTrackedFrameList.h>
16 
17 // VTK includes
18 #include <vtkImageData.h>
19 #include <vtkObjectFactory.h>
20 
21 namespace
22 {
23  //----------------------------------------------------------------------------
24  std::string ModeToString(vtkPlusVirtualDeinterlacer::StereoMode mode)
25  {
26  switch (mode)
27  {
29  return "HorizontalInterlace";
31  return "VerticalInterlace";
32  default:
33  return "Unknown";
34  }
35  }
36 
37  //----------------------------------------------------------------------------
38  vtkPlusVirtualDeinterlacer::StereoMode StringToMode(const std::string& mode)
39  {
40  if (igsioCommon::IsEqualInsensitive(mode, "HorizontalInterlace"))
41  {
43  }
44  else if (igsioCommon::IsEqualInsensitive(mode, "VerticalInterlace"))
45  {
47  }
48  else
49  {
51  }
52  }
53 }
54 //----------------------------------------------------------------------------
55 
57 
58 //----------------------------------------------------------------------------
60  : vtkPlusDevice()
61  , Mode(Stereo_Unknown)
62  , Initialized(false)
63  , LastInputTimestamp(UNDEFINED_TIMESTAMP)
64  , FrameList(vtkIGSIOTrackedFrameList::New())
65  , InputSource(nullptr)
66  , LeftImage(nullptr)
67  , RightImage(nullptr)
68  , SwitchInterlaceOrdering(false)
69 {
70  this->AcquisitionRate = 400; // Super fast!
71  this->StartThreadForInternalUpdates = true;
72 }
73 
74 //----------------------------------------------------------------------------
76 {
77  if (this->LeftImage != nullptr)
78  {
79  this->LeftImage->Delete();
80  this->LeftImage = nullptr;
81  }
82  if (this->RightImage != nullptr)
83  {
84  this->RightImage->Delete();
85  this->RightImage = nullptr;
86  }
87  this->FrameList->Delete();
88 }
89 
90 //----------------------------------------------------------------------------
91 void vtkPlusVirtualDeinterlacer::PrintSelf(ostream& os, vtkIndent indent)
92 {
93  this->Superclass::PrintSelf(os, indent);
94 }
95 
96 //----------------------------------------------------------------------------
97 PlusStatus vtkPlusVirtualDeinterlacer::ReadConfiguration(vtkXMLDataElement* rootConfigElement)
98 {
99  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
100 
101  std::string modeStr;
102  XML_READ_STRING_ATTRIBUTE_NONMEMBER_REQUIRED(StereoMode, modeStr, deviceConfig);
103  StereoMode mode = StringToMode(modeStr);
104  if (mode == Stereo_Unknown)
105  {
106  LOG_ERROR("Unknown stereo mode in configuration. Please double check.");
107  return PLUS_FAIL;
108  }
109  this->Mode = mode;
110 
111  XML_READ_BOOL_ATTRIBUTE_OPTIONAL(SwitchInterlaceOrdering, deviceConfig);
112 
113  return PLUS_SUCCESS;
114 }
115 
116 //----------------------------------------------------------------------------
117 PlusStatus vtkPlusVirtualDeinterlacer::WriteConfiguration(vtkXMLDataElement* rootConfigElement)
118 {
119  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement);
120 
121  deviceConfig->SetAttribute("StereoMode", ModeToString(this->Mode).c_str());
122 
123  XML_WRITE_BOOL_ATTRIBUTE(SwitchInterlaceOrdering, deviceConfig);
124 
125  return PLUS_SUCCESS;
126 }
127 
128 //----------------------------------------------------------------------------
130 {
131  if (!this->Initialized && this->InputChannels[0]->GetVideoDataAvailable())
132  {
133  FrameSizeType size = this->InputSource->GetOutputFrameSize();
134  if (this->Mode == Stereo_HorizontalInterlace)
135  {
136  if (size[1] % 2 == 1)
137  {
138  LOG_WARNING("Odd sized Y dimension, extra row will be added.");
139  }
140  // horizontal rows, Y dim is halved
141  size[1] = std::ceil(size[1] / 2.0);
142  }
143  else if (this->Mode == Stereo_VerticalInterlace)
144  {
145  if (size[01] % 2 == 1)
146  {
147  LOG_WARNING("Odd sized X dimension, extra column will be lost.");
148  }
149  // vertical rows, X dim is halved
150  size[0] = std::ceil(size[0] / 2.0);
151  }
152  this->LeftSource->SetInputImageOrientation(US_IMG_ORIENT_MFA);
153  this->RightSource->SetInputImageOrientation(US_IMG_ORIENT_MFA);
154  this->LeftSource->SetInputFrameSize(size);
155  this->RightSource->SetInputFrameSize(size);
162 
163  this->LeftImage = vtkImageData::New();
164  this->RightImage = vtkImageData::New();
165  this->LeftImage->SetDimensions(size[0], size[1], size[2]);
166  this->RightImage->SetDimensions(size[0], size[1], size[2]);
167  this->LeftImage->AllocateScalars(this->InputSource->GetPixelType(), this->InputSource->GetNumberOfScalarComponents());
168  this->RightImage->AllocateScalars(this->InputSource->GetPixelType(), this->InputSource->GetNumberOfScalarComponents());
169 
170  this->Initialized = true;
171  }
172 
173  this->FrameList->Clear();
174  if (this->InputChannels[0]->GetTrackedFrameList(this->LastInputTimestamp, this->FrameList, 100) != PLUS_SUCCESS)
175  {
176  return PLUS_FAIL;
177  }
178 
179  for (auto frame : *this->FrameList)
180  {
181  if (this->Mode == Stereo_HorizontalInterlace)
182  {
183  this->SplitFrameHorizontal(frame);
184  }
185  else if (this->Mode == Stereo_VerticalInterlace)
186  {
187  this->SplitFrameVertical(frame);
188  }
189 
192  this->FrameNumber++;
193  }
194 
195  return PLUS_SUCCESS;
196 }
197 
198 //----------------------------------------------------------------------------
200 {
201  vtkImageData* inputImage = frame->GetImageData()->GetImage();
202  vtkIdType* inputIncrements = inputImage->GetIncrements();
203  unsigned char* inputPtr = (unsigned char*)inputImage->GetScalarPointer();
204  unsigned char* leftPtr = (unsigned char*)this->LeftImage->GetScalarPointer();
205  unsigned char* rightPtr = (unsigned char*)this->RightImage->GetScalarPointer();
206  vtkIdType* outputIncrements = this->LeftImage->GetIncrements();
207 
208  // for each input row
209  for (vtkIdType row = 0; row < inputImage->GetDimensions()[1]; row++)
210  {
211  // %2 = 0 left, %2 = 1 right
212  bool left(false);
213  if (row % 2 == 0)
214  {
215  left = true;
216  }
217  if (this->SwitchInterlaceOrdering)
218  {
219  left = !left;
220  }
221 
222  // finished with this row,
223  // increment output image pointer for this row's image
224  if (left)
225  {
226  // Copy row to left image, increment left image pointer
227  memcpy(leftPtr, inputPtr, inputIncrements[1]);
228  leftPtr += outputIncrements[1];
229  }
230  else
231  {
232  memcpy(rightPtr, inputPtr, inputIncrements[1]);
233  rightPtr += outputIncrements[1];
234  }
235  inputPtr += inputIncrements[1];
236  }
237 }
238 
239 //----------------------------------------------------------------------------
241 {
242 
243 }
244 
245 //----------------------------------------------------------------------------
247 {
248  // Determine frame rate from the video input
249  if (this->InputSource == nullptr)
250  {
251  return -1.;
252  }
253  return this->InputSource->GetDevice()->GetAcquisitionRate();
254 }
255 
256 //----------------------------------------------------------------------------
258 {
259  if (this->InputChannels.size() != 1)
260  {
261  LOG_ERROR("Deinterlacer requires exactly 1 input channel");
262  return PLUS_FAIL;
263  }
264  this->InputChannels[0]->GetVideoSource(this->InputSource);
265  if (this->InputSource == nullptr)
266  {
267  LOG_ERROR("Input channel does not have a video source. It is required.");
268  return PLUS_FAIL;
269  }
270 
271  if (this->OutputChannels.size() < 2)
272  {
273  LOG_ERROR("Deinterlacer requires at least 2 output channels.");
274  return PLUS_FAIL;
275  }
276 
277  if (this->VideoSources.size() != 2)
278  {
279  LOG_ERROR("Deinterlacer requires exactly 2 video sources named \"Left\" and \"Right\"");
280  return PLUS_FAIL;
281  }
282  if (this->VideoSources.find("Left") == this->VideoSources.end())
283  {
284  LOG_ERROR("No video source with ID \"Left\" found.");
285  return PLUS_FAIL;
286  }
287  this->LeftSource = this->VideoSources.find("Left")->second;
288  if (this->VideoSources.find("Right") == this->VideoSources.end())
289  {
290  LOG_ERROR("No video source with ID \"Right\" found.");
291  return PLUS_FAIL;
292  }
293  this->RightSource = this->VideoSources.find("Right")->second;
294 
295  for (ChannelContainerIterator it = this->OutputChannels.begin(); it != this->OutputChannels.end(); ++it)
296  {
297  if (!(*it)->HasVideoSource())
298  {
299  LOG_ERROR("All output channels require a video source.");
300  return PLUS_FAIL;
301  }
302  }
303 
304  return PLUS_SUCCESS;
305 }
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
Abstract interface for tracker and video devices.
Definition: vtkPlusDevice.h:60
US_IMAGE_TYPE GetImageType()
void SplitFrameVertical(igsioTrackedFrame *frame)
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
Phidget_MeshMode mode
Definition: phidget22.h:1332
igsioStatus PlusStatus
Definition: PlusCommon.h:40
ChannelContainer InputChannels
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)
DataSourceContainer VideoSources
virtual unsigned int GetNumberOfScalarComponents()
PlusStatus SetImageType(US_IMAGE_TYPE imageType)
double AcquisitionRate
#define PLUS_FAIL
Definition: PlusCommon.h:43
virtual PlusStatus SetInputImageOrientation(US_IMAGE_ORIENTATION imageOrientation)
PlusStatus SetPixelType(igsioCommon::VTKScalarPixelType pixelType)
virtual double GetAcquisitionRate() const
virtual igsioCommon::VTKScalarPixelType GetPixelType()
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
unsigned long FrameNumber
vtkIGSIOTrackedFrameList * FrameList
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
vtkStandardNewMacro(vtkPlusVirtualDeinterlacer)
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *)
virtual US_IMAGE_ORIENTATION GetInputImageOrientation()
bool StartThreadForInternalUpdates
vtkPlusDevice * GetDevice()
virtual FrameSizeType GetOutputFrameSize() const
ChannelContainer OutputChannels
PlusStatus SetNumberOfScalarComponents(unsigned int numberOfScalarComponents)
ChannelContainer::iterator ChannelContainerIterator
Definition: vtkPlusDevice.h:36
void SplitFrameHorizontal(igsioTrackedFrame *frame)
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *)