PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
ExtractScanLines.cxx
Go to the documentation of this file.
1 #include "PlusConfigure.h"
2 #include "igsioTrackedFrame.h"
3 #include "vtkImageCast.h"
4 #include "vtkImageData.h"
5 #include "vtkIGSIOMetaImageSequenceIO.h"
6 #include "vtkSmartPointer.h"
7 #include "vtkIGSIOTrackedFrameList.h"
8 #include "vtkPlusUsScanConvert.h"
11 #include "vtkPlusSequenceIO.h"
12 
13 #include "vtksys/CommandLineArguments.hxx"
14 
15 
16 void extractScanLines(vtkPlusUsScanConvert* scanConverter, vtkImageData* inputImageData, vtkImageData* outputImageData)
17 {
18  int* linesImageExtent = scanConverter->GetInputImageExtent();
19  int lineLengthPx = linesImageExtent[1] - linesImageExtent[0] + 1;
20  int numScanLines = linesImageExtent[3] - linesImageExtent[2] + 1;
21 
22  float inputPixelValue = 0.0;
23 
24  int* inputExtent = inputImageData->GetExtent();
25  for (int scanLine = 0; scanLine < numScanLines; scanLine ++ )
26  {
27  double start[4] = {0};
28  double end[4] = {0};
29  scanConverter->GetScanLineEndPoints(scanLine, start, end);
30 
31  double directionVectorX = static_cast<double>(end[0]-start[0])/(lineLengthPx-1);
32  double directionVectorY = static_cast<double>(end[1]-start[1])/(lineLengthPx-1);
33  for (int pointIndex=0; pointIndex<lineLengthPx; ++pointIndex)
34  {
35  int pixelCoordX = start[0] + directionVectorX * pointIndex;
36  int pixelCoordY = start[1] + directionVectorY * pointIndex;
37  if ( pixelCoordX<inputExtent[0] || pixelCoordX>inputExtent[1] || pixelCoordY<inputExtent[2] || pixelCoordY>inputExtent[3] )
38  {
39  outputImageData->SetScalarComponentFromFloat(pointIndex, scanLine, 0, 0, 0);
40  continue; // outside of the specified extent
41  }
42  inputPixelValue = inputImageData->GetScalarComponentAsFloat(pixelCoordX, pixelCoordY, 0, 0);
43  outputImageData->SetScalarComponentFromFloat(pointIndex, scanLine, 0, 0, inputPixelValue);
44  }
45  }
46 }
47 
48 
49 int main(int argc, char** argv)
50 {
51  bool printHelp = false;
52  vtksys::CommandLineArguments args;
53 
54  std::string inputFileName;
55  std::string outputFileName;
56  std::string configFileName;
57  int verboseLevel=vtkPlusLogger::LOG_LEVEL_UNDEFINED;
58 
59  args.Initialize(argc, argv);
60  args.AddArgument("--help", vtksys::CommandLineArguments::NO_ARGUMENT, &printHelp, "Print this help");
61  args.AddArgument("--input-seq-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputFileName, "The filename for the input ultrasound sequence to process.");
62  args.AddArgument("--config-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &configFileName, "The filename for input config file.");
63  args.AddArgument("--output-seq-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &outputFileName, "The filename to write the processed sequence to.");
64  args.AddArgument("--verbose", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &verboseLevel, "Verbose level (1=error only, 2=warning, 3=info, 4=debug, 5=trace)");
65 
66  if (!args.Parse())
67  {
68  std::cerr << "Error parsing arguments" << std::endl;
69  std::cout << "Help: " << args.GetHelp() << std::endl;
70  exit(EXIT_FAILURE);
71  }
72 
73  if (printHelp)
74  {
75  std::cout << args.GetHelp() << std::endl;
76  return EXIT_SUCCESS;
77  }
78 
79  vtkPlusLogger::Instance()->SetLogLevel(verboseLevel);
80 
81  if (inputFileName.empty())
82  {
83  std::cerr << "--input-seq-file not found!" << std::endl;
84  return EXIT_FAILURE;
85  }
86 
87  if (configFileName.empty())
88  {
89  std::cerr << "--config-file not found!" << std::endl;
90  return EXIT_FAILURE;
91  }
92 
93  if (outputFileName.empty())
94  {
95  std::cerr << "--output-seq-file not found!" << std::endl;
96  return EXIT_FAILURE;
97  }
98 
99  // Read config file.
100 
101  vtkSmartPointer<vtkXMLDataElement> configRootElement = vtkSmartPointer<vtkXMLDataElement>::New();
102  if (PlusXmlUtils::ReadDeviceSetConfigurationFromFile(configRootElement, configFileName.c_str())==PLUS_FAIL)
103  {
104  LOG_ERROR("Unable to read configuration from file " << configFileName.c_str());
105  return EXIT_FAILURE;
106  }
107 
108  vtkXMLDataElement* scanConversionElement = configRootElement->FindNestedElementWithName("ScanConversion");
109  if (scanConversionElement == NULL)
110  {
111  LOG_ERROR("Cannot find ScanConversion element in XML tree!");
112  return PLUS_FAIL;
113  }
114 
115  const char* transducerGeometry = scanConversionElement->GetAttribute("TransducerGeometry");
116  if (transducerGeometry == NULL)
117  {
118  LOG_ERROR("Scan converter TransducerGeometry is undefined!");
119  return PLUS_FAIL;
120  }
121 
122  int numberOfScanLines = 100;
123  int numberOfSamplesPerScanLine = 200;
124 
125 
126  XML_READ_SCALAR_ATTRIBUTE_NONMEMBER_OPTIONAL(int, NumberOfScanLines, numberOfScanLines, scanConversionElement)
127  XML_READ_SCALAR_ATTRIBUTE_NONMEMBER_OPTIONAL(int, NumberOfSamplesPerScanLine, numberOfSamplesPerScanLine, scanConversionElement)
128 
129  if ( scanConversionElement->GetAttribute("NumberOfScanLines") == NULL )
130  {
131  LOG_WARNING("NumberOfScanLines attribute not specified. Using default value.")
132  }
133  if ( scanConversionElement->GetAttribute("NumberOfSamplesPerScanLine") == NULL )
134  {
135  LOG_WARNING("NumberOfSamplesPerScanLine attribute not specified. Using default value.")
136  }
137 
138  // Create scan converter.
139 
140  vtkSmartPointer<vtkPlusUsScanConvert> scanConverter;
141  if (STRCASECMP(transducerGeometry, "CURVILINEAR")==0)
142  {
143  scanConverter = vtkSmartPointer<vtkPlusUsScanConvert>::Take(vtkPlusUsScanConvertCurvilinear::New());
144  }
145  else if (STRCASECMP(transducerGeometry, "LINEAR")==0)
146  {
147  scanConverter = vtkSmartPointer<vtkPlusUsScanConvert>::Take(vtkPlusUsScanConvertLinear::New());
148  }
149  else
150  {
151  LOG_ERROR("Invalid scan converter TransducerGeometry: " << transducerGeometry);
152  return PLUS_FAIL;
153  }
154  scanConverter->ReadConfiguration(scanConversionElement);
155 
156  // Read input image.
157 
158  vtkSmartPointer<vtkIGSIOTrackedFrameList> inputFrameList = vtkSmartPointer<vtkIGSIOTrackedFrameList>::New();
159  vtkPlusSequenceIO::Read(inputFileName.c_str(), inputFrameList);
160  int numberOfFrames = inputFrameList->GetNumberOfTrackedFrames();
161 
162  // Create lines image (this is the image which holds scan lines in rows).
163 
164  int linesImageExtent[6]= {0, numberOfSamplesPerScanLine-1, 0, numberOfScanLines-1, 0, 0};
165  scanConverter->SetInputImageExtent(linesImageExtent);
166 
167  vtkSmartPointer<vtkImageData> linesImage = vtkSmartPointer<vtkImageData>::New();
168  linesImage->SetExtent(linesImageExtent);
169  linesImage->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
170 
171  // Create frame lists for lines images and output images.
172  vtkSmartPointer<vtkIGSIOTrackedFrameList> linesFrameList = vtkSmartPointer<vtkIGSIOTrackedFrameList>::New();
173  vtkSmartPointer<vtkIGSIOTrackedFrameList> outputFrameList = vtkSmartPointer<vtkIGSIOTrackedFrameList>::New();
174 
175  // Iterate thought every frame.
176  for (int frameIndex = 0; frameIndex < numberOfFrames; frameIndex ++ )
177  {
178  igsioTrackedFrame* inputFrame = inputFrameList->GetTrackedFrame(frameIndex);
179 
180  linesFrameList->AddTrackedFrame(inputFrame);
181  igsioTrackedFrame* linesFrame = linesFrameList->GetTrackedFrame(linesFrameList->GetNumberOfTrackedFrames()-1);
182  linesFrame->GetImageData()->DeepCopyFrom(linesImage); // Would there be a more efficient way to create this tracked frame?
183 
184  // Extract scan lines from image.
185  extractScanLines(scanConverter, inputFrame->GetImageData()->GetImage(), linesFrame->GetImageData()->GetImage() );
186  }
187 
188  std::cout << "Writing output to file. Setting log level to 1, regardless of user specified verbose level." << std::endl;
189  vtkPlusLogger::Instance()->SetLogLevel(1);
190 
191  vtkPlusSequenceIO::Write(outputFileName.c_str(), linesFrameList);
192 
193  return EXIT_SUCCESS;
194 }
virtual PlusStatus GetScanLineEndPoints(int scanLineIndex, double scanlineStartPoint_OutputImage[4], double scanlineEndPoint_OutputImage[4])=0
int main(int argc, char **argv)
#define PLUS_FAIL
Definition: PlusCommon.h:43
static vtkPlusUsScanConvertLinear * New()
void extractScanLines(vtkPlusUsScanConvert *scanConverter, vtkImageData *inputImageData, vtkImageData *outputImageData)
virtual int * GetInputImageExtent()
static igsioStatus Write(const std::string &filename, igsioTrackedFrame *frame, US_IMAGE_ORIENTATION orientationInFile=US_IMG_ORIENT_MF, bool useCompression=true, bool EnableImageDataWrite=true)
static vtkPlusUsScanConvertCurvilinear * New()
static igsioStatus Read(const std::string &filename, vtkIGSIOTrackedFrameList *frameList)
const char * start
Definition: phidget22.h:5116
static vtkIGSIOLogger * Instance()
This is a base class for defining a common scan conversion algorithm interface for all kinds of probe...
static PlusStatus ReadDeviceSetConfigurationFromFile(vtkXMLDataElement *config, const char *filename)
Definition: PlusXmlUtils.h:23