PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
DrawScanLines.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 "igsioCommon.h"
10 #include "PlusMath.h"
11 #include "igsioTrackedFrame.h"
12 #include "igsioVideoFrame.h"
13 #include "vtkPlusSequenceIO.h"
14 #include "vtkIGSIOTrackedFrameList.h"
17 
18 // VTK includes
19 #include <vtkImageData.h>
20 #include <vtkLineSource.h>
21 #include <vtkSmartPointer.h>
22 #include <vtkXMLUtilities.h>
23 #include <vtksys/CommandLineArguments.hxx>
24 
25 namespace
26 {
27  const float DRAWING_COLOR = 255;
28 }
29 
30 //----------------------------------------------------------------------------
31 int main(int argc, char** argv)
32 {
33  // Setup for command line arguments
34  bool printHelp(false);
35  std::string inputImgSeqFileName;
36  std::string outputImgSeqFileName;
37  std::string inputConfigFileName;
38  int verboseLevel = vtkPlusLogger::LOG_LEVEL_UNDEFINED;
39 
40  vtksys::CommandLineArguments args;
41  args.Initialize(argc, argv);
42 
43  args.AddArgument("--source-seq-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputImgSeqFileName, "The ultrasound sequence to draw the scanlines on.");
44  args.AddArgument("--output-seq-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &outputImgSeqFileName, "The output ultrasound sequence with scanlines overlaid on the images.");
45  args.AddArgument("--config-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputConfigFileName, "The ultrasound sequence config file.");
46  args.AddArgument("--help", vtksys::CommandLineArguments::NO_ARGUMENT, &printHelp, "Print this help.");
47  args.AddArgument("--verbose", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &verboseLevel, "Verbose level (1=error only, 2=warning, 3=info, 4=debug, 5=trace)");
48 
49  // Fail if arguments can't be parsed
50  if (!args.Parse())
51  {
52  std::cerr << "Error parsing arguments." << std::endl;
53  std::cout << "Help: " << args.GetHelp() << std::endl;
54  exit(EXIT_FAILURE);
55  }
56  // Print help if requested
57  if (printHelp)
58  {
59  std::cout << args.GetHelp() << std::endl;
60  exit(EXIT_SUCCESS);
61  }
62 
63  vtkPlusLogger::Instance()->SetLogLevel(verboseLevel);
64 
65  // Fail if no ultrasound image file specified
66  if (inputImgSeqFileName.empty())
67  {
68  LOG_ERROR("--seq-file required");
69  exit(EXIT_FAILURE);
70  }
71  // Fail if no ultrasound config file specified
72  if (inputConfigFileName.empty())
73  {
74  LOG_ERROR("--config-file required");
75  exit(EXIT_FAILURE);
76  }
77 
78  // Read the image sequence
79  vtkSmartPointer<vtkIGSIOTrackedFrameList> trackedFrameList = vtkSmartPointer<vtkIGSIOTrackedFrameList>::New();
80  if (vtkPlusSequenceIO::Read(inputImgSeqFileName, trackedFrameList) != PLUS_SUCCESS)
81  {
82  LOG_ERROR("Unable to load input image sequence.");
83  exit(EXIT_FAILURE);
84  }
85 
86  // For reading the configuration file
87  vtkSmartPointer<vtkXMLDataElement> configRootElement = vtkSmartPointer<vtkXMLDataElement>::New();
88  if (PlusXmlUtils::ReadDeviceSetConfigurationFromFile(configRootElement, inputConfigFileName.c_str()) == PLUS_FAIL)
89  {
90  LOG_ERROR("Unable to read configuration from file " << inputConfigFileName.c_str());
91  return EXIT_FAILURE;
92  }
93 
94  vtkXMLDataElement* scanConversionElement = configRootElement->LookupElementWithName("ScanConversion");
95  if (scanConversionElement == NULL)
96  {
97  LOG_ERROR("ScanConversion element was not found in input configuration file");
98  return EXIT_FAILURE;
99  }
100 
101  // Get number of scanlines from US simulator algo (if present)
102  int numOfScanlines = 50;
103  vtkXMLDataElement* usSimulatorAlgoElement = configRootElement->LookupElementWithName("vtkPlusUsSimulatorAlgo");
104  if (usSimulatorAlgoElement != NULL)
105  {
106  // Get US simulator attributes
107  usSimulatorAlgoElement->GetScalarAttribute("NumberOfScanlines", numOfScanlines);
108  }
109  else
110  {
111  LOG_INFO("vtkPlusUsSimulatorAlgo element not found in input configuration file. Using default NumberOfScanlines (" << numOfScanlines << ")");
112  }
113 
114  // Call scanline generator with appropriate scanconvert
115  const char* transducerGeometry = scanConversionElement->GetAttribute("TransducerGeometry");
116  if (transducerGeometry == NULL)
117  {
118  LOG_ERROR("Scan converter TransducerGeometry is undefined");
119  return EXIT_FAILURE;
120  }
121  vtkSmartPointer<vtkPlusUsScanConvert> scanConverter;
122  if (STRCASECMP(transducerGeometry, "CURVILINEAR") == 0)
123  {
124  scanConverter = vtkSmartPointer<vtkPlusUsScanConvert>::Take(vtkPlusUsScanConvertCurvilinear::New());
125  }
126  else if (STRCASECMP(transducerGeometry, "LINEAR") == 0)
127  {
128  scanConverter = vtkSmartPointer<vtkPlusUsScanConvert>::Take(vtkPlusUsScanConvertLinear::New());
129  }
130  else
131  {
132  LOG_ERROR("Invalid scan converter TransducerGeometry: " << transducerGeometry);
133  return EXIT_FAILURE;
134  }
135 
136  scanConverter->ReadConfiguration(scanConversionElement);
137 
138  const int numOfSamplesPerScanline = 100; // number of dots drawn per scanline
139  int rfImageExtent[6] = {0, numOfSamplesPerScanline - 1, 0, numOfScanlines - 1, 0, 0};
140  scanConverter->SetInputImageExtent(rfImageExtent);
141 
142  igsioCommon::PixelLineList lines;
143  for (int scanLine = 0; scanLine < rfImageExtent[3] - rfImageExtent[2] + 1; scanLine++)
144  {
145  double start[4] = { 0 };
146  double end[4] = { 0 };
147  scanConverter->GetScanLineEndPoints(scanLine, start, end);
148  igsioCommon::PixelPoint startPoint = { static_cast<int>(std::round(start[0])), static_cast<int>(std::round(start[1])), static_cast<int>(std::round(start[2])) };
149  igsioCommon::PixelPoint endPoint = { static_cast<int>(std::round(end[0])), static_cast<int>(std::round(end[1])), static_cast<int>(std::round(end[2])) };
150  lines.push_back(igsioCommon::PixelLine(startPoint, endPoint));
151  }
152 
153  if (!lines.empty())
154  {
155  igsioCommon::DrawScanLines(rfImageExtent, 255, lines, trackedFrameList);
156  }
157 
158  // Write the new TrackedFrameList to metafile
159  LOG_INFO("Writing new sequence to file...");
160  if (outputImgSeqFileName.empty())
161  {
162  int extensionDot = inputImgSeqFileName.find_last_of(".");
163  if (extensionDot != std::string::npos)
164  {
165  inputImgSeqFileName = inputImgSeqFileName.substr(0, extensionDot);
166  }
167  outputImgSeqFileName = inputImgSeqFileName + "-Scanlines.nrrd";
168  }
169  if (vtkPlusSequenceIO::Write(outputImgSeqFileName, trackedFrameList) != PLUS_SUCCESS)
170  {
171  return EXIT_FAILURE;
172  }
173  LOG_INFO("Writing to " << outputImgSeqFileName << " complete.");
174 
175  return EXIT_SUCCESS;
176 }
#define PLUS_FAIL
Definition: PlusCommon.h:43
static vtkPlusUsScanConvertLinear * New()
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()
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
static igsioStatus Read(const std::string &filename, vtkIGSIOTrackedFrameList *frameList)
const char * start
Definition: phidget22.h:5116
int main(int argc, char **argv)
static vtkIGSIOLogger * Instance()
static PlusStatus ReadDeviceSetConfigurationFromFile(vtkXMLDataElement *config, const char *filename)
Definition: PlusXmlUtils.h:23