PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusUsSimulatorAlgo.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 
9 #include <algorithm>
10 #include <list>
11 #include <map>
12 
13 #include "vtkPlusUsSimulatorAlgo.h"
14 
15 #include "vtkImageAlgorithm.h"
16 #include "vtkInformation.h"
17 #include "vtkTransform.h"
18 #include "vtkPolyData.h"
19 #include "vtkPolyDataToImageStencil.h"
20 #include "vtkSmartPointer.h"
21 #include "vtkImageStencil.h"
22 #include "vtkInformationVector.h"
23 #include "vtkImageData.h"
24 #include "vtkObjectFactory.h"
25 #include "vtkPointData.h"
26 #include "vtkTransformPolyDataFilter.h"
27 #include "vtkImageStencilData.h"
28 #include "vtkPolyData.h"
29 #include "vtksys/SystemTools.hxx"
30 
31 #include "vtkPlusRfProcessor.h"
32 #include "vtkPlusUsScanConvert.h"
33 
34 // For noise generation
35 #include "vtkLineSource.h"
36 #include "vtkPerlinNoise.h"
37 #include "vtkProbeFilter.h"
38 #include "vtkSampleFunction.h"
39 
40 //-----------------------------------------------------------------------------
41 
43 
44 //-----------------------------------------------------------------------------
46  : TransformRepository(NULL)
47 {
48  SetNumberOfInputPorts(0);
49  SetNumberOfOutputPorts(1);
50 
51  this->ImageCoordinateFrame = NULL;
52  this->ReferenceCoordinateFrame = NULL;
53 
54  this->NumberOfScanlines = 256;
55  this->NumberOfSamplesPerScanline = 1000;
56  this->IncomingIntensityMwPerCm2 = 100;
57  this->FrequencyMhz = 2.5;
58  this->BrightnessConversionGamma = 0.333;
59  this->BrightnessConversionOffset = 30;
60  this->BrightnessConversionScale = 30;
61 
62  this->RfProcessor = vtkPlusRfProcessor::New();
63 
64  this->NoiseAmplitude = 0;
65  this->NoiseFrequency[0] = 0;
66  this->NoiseFrequency[1] = 0;
67  this->NoiseFrequency[2] = 0;
68  this->NoisePhase[0] = 0;
69  this->NoisePhase[1] = 0;
70  this->NoisePhase[2] = 0;
71 
72  // this->TransducerSpatialModel doesn't have to be initialized, as the default parameters of SpatialModel
73  // are for soft tissue that should match the transducer material in acoustic impedance
74 }
75 
76 //-----------------------------------------------------------------------------
78 {
81  if (this->RfProcessor != NULL)
82  {
83  this->RfProcessor->Delete();
84  this->RfProcessor = NULL;
85  }
86  this->SetTransformRepository(NULL);
87 }
88 
89 //-----------------------------------------------------------------------------
90 void vtkPlusUsSimulatorAlgo::PrintSelf(ostream& os, vtkIndent indent)
91 {
92  this->Superclass::PrintSelf(os, indent);
93 }
94 
95 //-----------------------------------------------------------------------------
97 {
98  info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkImageData");
99 
100  return 1;
101 }
102 
103 inline double fastPow(double a, double b)
104 {
105  union
106  {
107  double d;
108  int x[2];
109  } u = { a };
110  u.x[1] = (int)(b * (u.x[1] - 1072632447) + 1072632447);
111  u.x[0] = 0;
112  return u.d;
113 }
114 
115 //-----------------------------------------------------------------------------
116 int vtkPlusUsSimulatorAlgo::RequestData(vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector)
117 {
118  if (this->TransformRepository == NULL)
119  {
120  LOG_ERROR("No transform repository is specified ");
121  return 0;
122  }
123 
124  // Get input
125  vtkInformation* outInfo = outputVector->GetInformationObject(0);
126 
127  for (std::vector<PlusSpatialModel>::iterator spatialModelIt = this->SpatialModels.begin(); spatialModelIt != this->SpatialModels.end(); ++spatialModelIt)
128  {
129  spatialModelIt->SetImagingFrequencyMhz(this->FrequencyMhz);
130  }
131  this->TransducerSpatialModel.SetImagingFrequencyMhz(this->FrequencyMhz);
132 
133  vtkSmartPointer<vtkImageData> scanLines = vtkSmartPointer<vtkImageData>::New(); // image data containing the scanlines in rows (FM orientation)
134  scanLines->SetExtent(0, this->NumberOfSamplesPerScanline - 1, 0, this->NumberOfScanlines - 1, 0, 0);
135  scanLines->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
136 
137  // Create BSPTree for fast scanline-model intersection computation
138  vtkSmartPointer<vtkPoints> scanLineIntersectionWithModel = vtkSmartPointer<vtkPoints>::New();
139 
140  vtkPlusUsScanConvert* scanConverter = this->RfProcessor->GetScanConverter();
141  if (scanConverter == NULL)
142  {
143  LOG_ERROR("ScanConverter is not defined");
144  return 0;
145  }
146  // The input image extent has to be set before calling the scanConverter's
147  // GetScanLineEndPoints or GetDistanceBetweenScanlineSamplePointsMm methods
148  scanConverter->SetInputImageExtent(scanLines->GetExtent());
149 
150  double outputImageSpacingMm[3] = {1.0, 1.0, 1.0};
151  scanConverter->GetOutputImageSpacing(outputImageSpacingMm);
152 
153  double distanceBetweenScanlineSamplePointsMm = scanConverter->GetDistanceBetweenScanlineSamplePointsMm();
154 
155  // Initialize noise generator
156  vtkSmartPointer<vtkLineSource> noiseSamplerLine_Reference = vtkSmartPointer<vtkLineSource>::New();
157  vtkSmartPointer<vtkPerlinNoise> noiseFunction = vtkSmartPointer<vtkPerlinNoise>::New();
158  double samplePointPosition_Reference[3] = {0, 0, 0};
159  if (this->NoiseAmplitude > 0)
160  {
161  noiseSamplerLine_Reference->SetResolution(this->NumberOfSamplesPerScanline - 1);
162  noiseFunction->SetAmplitude(this->NoiseAmplitude);
163  noiseFunction->SetFrequency(this->NoiseFrequency);
164  noiseFunction->SetPhase(this->NoisePhase);
165  }
166 
167  igsioTransformName imageToReferenceTransformName(this->GetImageCoordinateFrame(), this->GetReferenceCoordinateFrame());
168  vtkSmartPointer<vtkMatrix4x4> imageToReferenceMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
169  if (this->TransformRepository->GetTransform(imageToReferenceTransformName, imageToReferenceMatrix) != PLUS_SUCCESS)
170  {
171  std::string strTransformName;
172  imageToReferenceTransformName.GetTransformName(strTransformName);
173  LOG_ERROR("Failed to get transform from repository: " << strTransformName);
174 
175  // Prevent crash in the pipeline by initializing output image
176  vtkImageData* simulatedUsImage = vtkImageData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
177  if (simulatedUsImage == NULL)
178  {
179  LOG_ERROR("vtkPlusUsSimulatorAlgo output type is invalid");
180  return 0;
181  }
182  simulatedUsImage->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
183 
184  return 0;
185  }
186  vtkSmartPointer<vtkMatrix4x4> referenceToImageMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
187  vtkMatrix4x4::Invert(imageToReferenceMatrix, referenceToImageMatrix);
188 
189  // Create a few variables outside the loop to avoid reallocations and to make the code easier to read
190  vtkPoints* samplePointPositions_Reference = 0;
191  // Create a buffer outside the for loop to allow reusing it
192  std::vector<double> intensities;
193  // scanline start/end positions in Image and Reference coordinate systems
194  double scanLineStartPoint_Image[4] = {0, 0, 0, 1};
195  double scanLineEndPoint_Image[4] = {0, 0, 0, 1};
196  double scanLineStartPoint_Reference[4] = {0, 0, 0, 1};
197  double scanLineEndPoint_Reference[4] = {0, 0, 0, 1};
198 
199  for (std::vector<PlusSpatialModel>::iterator spatialModelIt = this->SpatialModels.begin(); spatialModelIt != this->SpatialModels.end(); ++spatialModelIt)
200  {
201  vtkSmartPointer<vtkMatrix4x4> referenceToObjectMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
202  if (!spatialModelIt->GetObjectCoordinateFrame().empty())
203  {
204  igsioTransformName referenceToObjectTransformName(this->GetReferenceCoordinateFrame(), spatialModelIt->GetObjectCoordinateFrame());
205  if (this->TransformRepository->GetTransform(referenceToObjectTransformName, referenceToObjectMatrix) != PLUS_SUCCESS)
206  {
207  std::string strTransformName;
208  imageToReferenceTransformName.GetTransformName(strTransformName);
209  LOG_ERROR("Error computing spatial position of " << spatialModelIt->GetName() << " SpatialModel: failed to get transform from repository: " << strTransformName);
210  }
211  }
212  spatialModelIt->SetReferenceToObjectTransform(referenceToObjectMatrix);
213  }
214 
215  for (int scanLineIndex = 0; scanLineIndex < this->NumberOfScanlines; scanLineIndex++)
216  {
217  scanConverter->GetScanLineEndPoints(scanLineIndex, scanLineStartPoint_Image, scanLineEndPoint_Image);
218  imageToReferenceMatrix->MultiplyPoint(scanLineStartPoint_Image, scanLineStartPoint_Reference);
219  imageToReferenceMatrix->MultiplyPoint(scanLineEndPoint_Image, scanLineEndPoint_Reference);
220 
221  if (this->NoiseAmplitude > 0)
222  {
223  noiseSamplerLine_Reference->SetPoint1(scanLineStartPoint_Reference);
224  noiseSamplerLine_Reference->SetPoint2(scanLineEndPoint_Reference);
225  noiseSamplerLine_Reference->Update();
226  samplePointPositions_Reference = noiseSamplerLine_Reference->GetOutput()->GetPoints();
227  }
228 
229  // Get model intersection positions along the scanline for all the models
230  std::deque<PlusSpatialModel::LineIntersectionInfo> lineIntersectionsWithModels;
231  for (std::vector<PlusSpatialModel>::iterator spatialModelIt = this->SpatialModels.begin(); spatialModelIt != this->SpatialModels.end(); ++spatialModelIt)
232  {
233  // Append line intersections found with this model to lineIntersectionsWithModels
234  spatialModelIt->GetLineIntersections(lineIntersectionsWithModels, scanLineStartPoint_Reference, scanLineEndPoint_Reference);
235  }
236 
237  ConvertLineModelIntersectionsToSegmentDescriptor(lineIntersectionsWithModels);
238 
239  int currentPixelIndex = 0;
240  int scanLineExtent[6] = {0, this->NumberOfSamplesPerScanline - 1, scanLineIndex, scanLineIndex, 0, 0};
241  unsigned char* dstPixelAddress = (unsigned char*)scanLines->GetScalarPointerForExtent(scanLineExtent);
242  double incomingBeamIntensity = this->IncomingIntensityMwPerCm2 * 1000;
243  int numIntersectionPoints = lineIntersectionsWithModels.size();
244  if (numIntersectionPoints < 1)
245  {
246  LOG_ERROR("No intersections with any SpatialObjects. Probably no background object is specified.");
247  return 0;
248  }
249  PlusSpatialModel* previousModel = &this->TransducerSpatialModel;
250  for (vtkIdType intersectionIndex = 0; (intersectionIndex <= numIntersectionPoints) && (currentPixelIndex < this->NumberOfSamplesPerScanline); intersectionIndex++)
251  {
252  // determine end of segment position and pixel color
253  int endOfSegmentPixelIndex = currentPixelIndex;
254  double distanceOfIntersectionPointFromScanLineStartPointMm = 0; // defined here to allow for access later on in code
255  if (intersectionIndex + 1 < numIntersectionPoints)
256  {
257  distanceOfIntersectionPointFromScanLineStartPointMm = lineIntersectionsWithModels[intersectionIndex + 1].IntersectionDistanceFromStartPointMm;
258  endOfSegmentPixelIndex = distanceOfIntersectionPointFromScanLineStartPointMm / distanceBetweenScanlineSamplePointsMm;
259  if (endOfSegmentPixelIndex > this->NumberOfSamplesPerScanline)
260  {
261  // the next intersection point is out of the image
262  endOfSegmentPixelIndex = this->NumberOfSamplesPerScanline;
263  }
264  }
265  else
266  {
267  // last segment, after all the intersection points
268  endOfSegmentPixelIndex = this->NumberOfSamplesPerScanline;
269  }
270 
271  int numberOfFilledPixels = endOfSegmentPixelIndex - currentPixelIndex;
272  if (numberOfFilledPixels < 1)
273  {
274  continue;
275  }
276 
277  PlusSpatialModel* currentModel = NULL;
278  if (intersectionIndex < numIntersectionPoints)
279  {
280  currentModel = lineIntersectionsWithModels[intersectionIndex].Model;
281  }
282  else
283  {
284  // the segment after the last intersection point is assumed to belong to the model of the last intersection
285  currentModel = lineIntersectionsWithModels[numIntersectionPoints - 1].Model;
286  }
287 
288  double outgoingBeamIntensity = 0;
289  currentModel->CalculateIntensity(intensities, numberOfFilledPixels, distanceBetweenScanlineSamplePointsMm, previousModel->GetAcousticImpedanceMegarayls(), incomingBeamIntensity, outgoingBeamIntensity, lineIntersectionsWithModels[intersectionIndex].IntersectionIncidenceAngleRad);
290  previousModel = currentModel;
291 
292  if (this->NoiseAmplitude > 0)
293  {
294  for (int pixelIndex = 0; pixelIndex < numberOfFilledPixels; pixelIndex++)
295  {
296  samplePointPositions_Reference->GetPoint(currentPixelIndex + pixelIndex, samplePointPosition_Reference);
297  double noise = noiseFunction->EvaluateFunction(samplePointPosition_Reference);
298  // Noise is multiplicative: NoisySignal = signal + noise * (signal-SignalMean) = signal*(1+noise) - noise*SignalMean;
299  (*dstPixelAddress++) = std::max(std::min(this->BrightnessConversionOffset + this->BrightnessConversionScale * fastPow(intensities[pixelIndex], this->BrightnessConversionGamma) + noise, 255.0), 0.0);
300  }
301  }
302  else
303  {
304  for (int pixelIndex = 0; pixelIndex < numberOfFilledPixels; pixelIndex++)
305  {
306  (*dstPixelAddress++) = std::max(std::min(this->BrightnessConversionOffset + this->BrightnessConversionScale * fastPow(intensities[pixelIndex], this->BrightnessConversionGamma), 255.0), 0.0);
307  }
308  }
309 
310  incomingBeamIntensity = outgoingBeamIntensity;
311 
312  currentPixelIndex += numberOfFilledPixels;
313  }
314  }
315 
316  vtkImageData* simulatedUsImage = vtkImageData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
317  if (simulatedUsImage == NULL)
318  {
319  LOG_ERROR("vtkPlusUsSimulatorAlgo output type is invalid");
320  return 0;
321  }
322  this->RfProcessor->SetRfFrame(scanLines, US_IMG_BRIGHTNESS);
323  simulatedUsImage->DeepCopy(this->RfProcessor->GetBrightnessScanConvertedImage());
324  return 1;
325 }
326 
328 {
329  return a.IntersectionDistanceFromStartPointMm < b.IntersectionDistanceFromStartPointMm;
330 }
331 
332 // In the input the "Model" in the line model intersections refers to the model that either starts or ends
333 // at the given intersection position (e.g., background/spine/spine).
334 // We overwrite the "Model" by the model that starts from that intersection position (e.g., background/spine/background).
335 //-----------------------------------------------------------------------------
336 void vtkPlusUsSimulatorAlgo::ConvertLineModelIntersectionsToSegmentDescriptor(std::deque<PlusSpatialModel::LineIntersectionInfo>& lineIntersectionsWithModels)
337 {
338  // sort intersections based on the intersection distance
339  std::sort(lineIntersectionsWithModels.begin(), lineIntersectionsWithModels.end(), lineIntersectionLessThan);
340 
341  // Cohesiveness defines how likely that the model contains another model.
342  // If cohesiveness is low then the model likely to contain other models (e.g., the background material has the lowest cohesiveness value).
343  // When we are in a segment that is inside multiple models, the model with the highest cohesiveness "overwrites" all the others.
344  // e.g.,
345  // Cohesiveness values:
346  // background: cohesiveness = 0
347  // spine: cohesiveness = 1
348  // needle: cohesiveness = 2
349  // Decision:
350  // if we are in background+spine segment => it's spine
351  // if we are in background+spine+needle segment => it's needle
352  // It is assumed that the SpatialModels are listed in the config file in increasing cohesiveness order (background is the first).
353  std::map< PlusSpatialModel*, int > cohesiveness;
354  for (unsigned int i = 0; i < this->SpatialModels.size(); i++)
355  {
356  cohesiveness[&this->SpatialModels[i]] = i;
357  }
358  // insideModel contains all the SpatialModels that the current segment is in; listed in descending order based on cohesiveness
359  std::list<PlusSpatialModel*> insideModel;
360  for (std::deque<PlusSpatialModel::LineIntersectionInfo>::iterator intersectionIt = lineIntersectionsWithModels.begin();
361  intersectionIt != lineIntersectionsWithModels.end(); ++intersectionIt)
362  {
363  std::list<PlusSpatialModel*>::iterator foundThisModelAt = find(insideModel.begin(), insideModel.end(), intersectionIt->Model);
364  if (foundThisModelAt != insideModel.end())
365  {
366  // we were already inside this model, so now we are out
367  insideModel.erase(foundThisModelAt);
368  }
369  else
370  {
371  // we were not inside this model, so now we are in - need to put this model into the list
372  int thisModelsCohesiveness = cohesiveness[intersectionIt->Model];
373  std::list<PlusSpatialModel*>::iterator insertThisModelAt = insideModel.begin();
374  while (insertThisModelAt != insideModel.end() && cohesiveness[*insertThisModelAt] > thisModelsCohesiveness)
375  {
376  ++insertThisModelAt;
377  }
378  insideModel.insert(insertThisModelAt, intersectionIt->Model);
379  }
380  if (insideModel.empty())
381  {
382  LOG_ERROR("No model is defined in one segment of the scanline");
383  }
384  else
385  {
386  intersectionIt->Model = insideModel.front();
387  }
388  }
389 }
390 
391 //-----------------------------------------------------------------------------
393 {
394  LOG_TRACE("vtkPlusUsSimulatorVideoSource::ReadConfiguration");
395 
396  XML_FIND_NESTED_ELEMENT_REQUIRED(usSimulatorAlgoElement, config, "vtkPlusUsSimulatorAlgo");
397 
398  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(int, NumberOfScanlines, usSimulatorAlgoElement);
399  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(int, NumberOfSamplesPerScanline, usSimulatorAlgoElement);
400  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, FrequencyMhz, usSimulatorAlgoElement);
401  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, BrightnessConversionGamma, usSimulatorAlgoElement);
402  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, BrightnessConversionOffset, usSimulatorAlgoElement);
403  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, BrightnessConversionScale, usSimulatorAlgoElement);
404  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, IncomingIntensityMwPerCm2, usSimulatorAlgoElement);
405  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, NoiseAmplitude, usSimulatorAlgoElement);
406  XML_READ_VECTOR_ATTRIBUTE_OPTIONAL(double, 3, NoiseFrequency, usSimulatorAlgoElement);
407  XML_READ_VECTOR_ATTRIBUTE_OPTIONAL(double, 3, NoisePhase, usSimulatorAlgoElement);
408  XML_READ_CSTRING_ATTRIBUTE_REQUIRED(ImageCoordinateFrame, usSimulatorAlgoElement);
409  XML_READ_CSTRING_ATTRIBUTE_REQUIRED(ReferenceCoordinateFrame, usSimulatorAlgoElement);
410 
411  XML_FIND_NESTED_ELEMENT_REQUIRED(rfProcesingElement, usSimulatorAlgoElement, "RfProcessing");
412  this->RfProcessor->ReadConfiguration(rfProcesingElement);
413 
414  this->SpatialModels.clear();
415  for (int i = 0; i < usSimulatorAlgoElement->GetNumberOfNestedElements(); ++i)
416  {
417  vtkXMLDataElement* spatialModelElement = usSimulatorAlgoElement->GetNestedElement(i);
418  if (STRCASECMP(spatialModelElement->GetName(), "SpatialModel") != 0)
419  {
420  continue;
421  }
422  PlusSpatialModel model;
423  if (model.ReadConfiguration(spatialModelElement) != PLUS_SUCCESS)
424  {
425  return PLUS_FAIL;
426  }
427  this->SpatialModels.push_back(model);
428  }
429 
430  return PLUS_SUCCESS;
431 }
432 
433 //-----------------------------------------------------------------------------
435 {
436  vtkPlusUsScanConvert* scanConverter = this->RfProcessor->GetScanConverter();
437  if (scanConverter == NULL)
438  {
439  LOG_ERROR("Unable to determine frame size, ScanConverter is not defined");
440  return PLUS_FAIL;
441  }
442  frameSize = scanConverter->GetOutputImageSizePixel();
443  frameSize[2] = 1; // currently the simulator always provides 2D images
444  return PLUS_SUCCESS;
445 }
virtual double * GetOutputImageSpacing()
virtual int FillOutputPortInformation(int port, vtkInformation *info)
virtual PlusStatus GetScanLineEndPoints(int scanLineIndex, double scanlineStartPoint_OutputImage[4], double scanlineEndPoint_OutputImage[4])=0
static vtkPlusRfProcessor * New()
virtual void SetInputImageExtent(int, int, int, int, int, int)
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *spatialModelElement)
int
Definition: phidget22.h:3069
bool lineIntersectionLessThan(PlusSpatialModel::LineIntersectionInfo a, PlusSpatialModel::LineIntersectionInfo b)
igsioStatus PlusStatus
Definition: PlusCommon.h:40
void PrintSelf(ostream &os, vtkIndent indent)
virtual vtkPlusUsScanConvert * GetScanConverter()
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *rfElement)
for i
virtual void SetTransformRepository(vtkIGSIOTransformRepository *)
virtual int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector)
virtual vtkImageData * GetBrightnessScanConvertedImage()
#define PLUS_FAIL
Definition: PlusCommon.h:43
virtual PlusStatus SetRfFrame(vtkImageData *rfFrame, US_IMAGE_TYPE imageType)
Initial rotation matrix b
Definition: algo3.m:25
double fastPow(double a, double b)
void CalculateIntensity(std::vector< double > &reflectedIntensity, unsigned int numberOfFilledPixels, double distanceBetweenScanlineSamplePointsMm, double previousModelAcousticImpedanceMegarayls, double incidentIntensity, double &transmittedIntensity, double incidenceAngleRad)
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
void ConvertLineModelIntersectionsToSegmentDescriptor(std::deque< PlusSpatialModel::LineIntersectionInfo > &lineIntersectionsWithModels)
int x
Definition: phidget22.h:4265
Class that simulates ultrasound images from multiple surface models.
virtual void SetImageCoordinateFrame(const char *)
virtual double GetDistanceBetweenScanlineSamplePointsMm()=0
This is a base class for defining a common scan conversion algorithm interface for all kinds of probe...
virtual char * GetReferenceCoordinateFrame()
virtual FrameSizeType GetOutputImageSizePixel()
virtual char * GetImageCoordinateFrame()
vtkStandardNewMacro(vtkPlusUsSimulatorAlgo)
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
PlusStatus GetFrameSize(FrameSizeType &frameSize)
virtual void SetReferenceCoordinateFrame(const char *)
double GetAcousticImpedanceMegarayls()