Fraxinus  16.5.0-fx-rc1
An IGT application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cxMHDImageStreamer.cpp
Go to the documentation of this file.
1 /*=========================================================================
2 This file is part of CustusX, an Image Guided Therapy Application.
3 
4 Copyright (c) 2008-2014, SINTEF Department of Medical Technology
5 All rights reserved.
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 
10 1. Redistributions of source code must retain the above copyright notice,
11  this list of conditions and the following disclaimer.
12 
13 2. Redistributions in binary form must reproduce the above copyright notice,
14  this list of conditions and the following disclaimer in the documentation
15  and/or other materials provided with the distribution.
16 
17 3. Neither the name of the copyright holder nor the names of its contributors
18  may be used to endorse or promote products derived from this software
19  without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 =========================================================================*/
32 
33 #include "cxMHDImageStreamer.h"
34 
35 #include <QTimer>
36 #include <QDateTime>
37 #include "vtkImageData.h"
38 #include "vtkMetaImageReader.h"
39 #include "vtkLookupTable.h"
40 #include "vtkImageMapToColors.h"
41 #include "cxForwardDeclarations.h"
42 #include "cxImageDataContainer.h"
43 #include "cxTypeConversions.h"
44 
45 #include <vtkImageExtractComponents.h>
46 #include <vtkImageAppendComponents.h>
47 #include <vtkImageLuminance.h>
48 #include <QFileInfo>
49 
50 #include "cxStringProperty.h"
51 #include "cxDoubleProperty.h"
52 #include "cxBoolProperty.h"
53 #include "cxDataReaderWriter.h"
54 #include "cxSender.h"
55 #include "cxFilePathProperty.h"
56 #include "cxProfile.h"
57 #include "cxReporter.h"
58 
59 namespace cx
60 {
61 
62 std::vector<PropertyPtr> ImageStreamerDummyArguments::getSettings(QDomElement root)
63 {
64  std::vector<PropertyPtr> retval;
65  retval.push_back(this->getFilenameOption(root));
66  retval.push_back(this->getSecondaryOption(root));
67  return retval;
68 }
69 
71 {
72  FilePathPropertyPtr retval;
73  retval = FilePathProperty::initialize("filename", "Filename",
74  "Select a 3D image file to stream from",
75  "",
76  QStringList() << profile()->getSessionRootFolder(),
77  root);
78 
79  retval->setGroup("File");
80  return retval;
81 }
82 
84 {
85  BoolPropertyPtr retval;
86  bool defaultValue = false;
87  retval = BoolProperty::initialize("secondary", "Secondary",
88  "Create two streams, the second one a dummy color image",
89  defaultValue, root);
90  retval->setAdvanced(true);
91  retval->setGroup("File");
92  return retval;
93 }
94 
96 {
97  StringMap retval;
98  retval["--type"] = "MHDFile";
99  retval["--filename"] = this->getFilenameOption(root)->getValue();
100  if (this->getSecondaryOption(root)->getValue())
101  retval["--secondary"] = "1";
102  return retval;
103 }
104 
106 {
107  QStringList retval;
108  retval << "--filename: name of image file to stream from ";
109  retval << "--secondary: Create two streams, the second one a dummy color image";
110  return retval;
111 }
112 
113 } // namespace cx
114 
115 
119 
120 namespace cx
121 {
122 
123 vtkLookupTablePtr createLookupTable(int numberOfTableValues)
124 {
125  vtkLookupTablePtr lut = vtkLookupTablePtr::New();
126  lut->SetNumberOfTableValues(numberOfTableValues);
127  lut->SetTableRange(0, numberOfTableValues - 1);
128  lut->SetSaturationRange(0, 0.5);
129  lut->SetHueRange(0, 1);
130  lut->SetValueRange(0, 1);
131  lut->Build();
132  return lut;
133 }
134 
136 {
137  vtkImageMapToColorsPtr mapper = vtkImageMapToColorsPtr::New();
138  mapper->SetInputData(input);
139  mapper->SetLookupTable(lut);
140  mapper->Update();
141  vtkImageDataPtr retval = mapper->GetOutput();
142  return retval;
143 }
144 
146 {
147  int numberOfTableValues = 256;
148  vtkLookupTablePtr lut = createLookupTable(numberOfTableValues);
149  vtkImageDataPtr retval = applyLUTToImage(image, lut);
150  return retval;
151 }
152 
153 
155 {
156  ImageTestData retval;
157  QString colorFormat = "R";
158  if (source->GetNumberOfScalarComponents() == 3)
159  {
160  vtkImageAppendComponentsPtr merger = vtkImageAppendComponentsPtr::New();
161  vtkImageExtractComponentsPtr splitterRGB = vtkImageExtractComponentsPtr::New();
162  splitterRGB->SetInputData(source);
163  splitterRGB->SetComponents(0, 1, 2);
164 // merger->AddInputConnection(0, splitterRGB->GetOutputPort());
165  merger->AddInputConnection(splitterRGB->GetOutputPort());
166  vtkImageExtractComponentsPtr splitterA = vtkImageExtractComponentsPtr::New();
167  splitterA->SetInputData(source);
168  splitterA->SetComponents(0);
169  merger->AddInputConnection(splitterA->GetOutputPort());
170 // merger->AddInputConnection(1, splitterA->GetOutputPort());
171  merger->Update();
172  retval.mImageData = merger->GetOutput();
173  colorFormat = "RGBA";
174  }
175  else if (source->GetNumberOfScalarComponents() == 4)
176  {
177  retval.mImageData = source;
178  colorFormat = "RGBA";
179  }
180  else if (source->GetNumberOfScalarComponents() == 1)
181  {
182  retval.mImageData = source;
183  colorFormat = "R";
184  }
185 
186  retval.mRawUid = QString("%1 [%2]").arg(QFileInfo(filename).completeBaseName()).arg(colorFormat);
187  retval.mDataSource.reset(new SplitFramesContainer(retval.mImageData));
188  retval.mCurrentFrame = 0;
189  return retval;
190 }
191 
193 {
194  ImageTestData retval;
195  QString colorFormat = "R";
196  if (source->GetNumberOfScalarComponents() == 3)
197  {
198  vtkSmartPointer < vtkImageLuminance > luminance = vtkSmartPointer < vtkImageLuminance > ::New();
199  luminance->SetInputData(source);
200  luminance->Update();
201  vtkImageDataPtr outData = luminance->GetOutput();
202  retval.mImageData = outData;
203  colorFormat = "R";
204  }
205  else if (source->GetNumberOfScalarComponents() == 4)
206  {
207  retval.mImageData = source;
208  colorFormat = "RGBA";
209  }
210  else if (source->GetNumberOfScalarComponents() == 1)
211  {
212  retval.mImageData = source;
213  colorFormat = "R";
214  }
215 
216  retval.mRawUid = QString("uchar %1[%2]").arg(QFileInfo(filename).completeBaseName()).arg(colorFormat);
217  retval.mDataSource.reset(new SplitFramesContainer(retval.mImageData));
218  retval.mCurrentFrame = 0;
219  return retval;
220 }
221 
223 {
224  PackagePtr package(new Package());
225 
226  int frame = (data->mCurrentFrame++) % data->mDataSource->size();
227  QString uid = data->mRawUid;
228  vtkImageDataPtr copy = vtkImageDataPtr::New();
229  copy->DeepCopy(data->mDataSource->get(frame));
230  ImagePtr image(new Image(uid, copy));
231  image->setAcquisitionTime(QDateTime::currentDateTime());
232  package->mImage = image;
233  return package;
234 }
235 
237  mSendOnce(false),
238  mUseSecondaryStream(false),
239  mPrimaryDataSource(),
240  mSecondaryDataSource()
241 {
242  this->setSendInterval(40);
243 }
244 
246 {
247  return "MHDFile";
248 }
249 
250 vtkImageDataPtr DummyImageStreamer::internalLoadImage(QString filename)
251 {
252  vtkImageDataPtr source = MetaImageReader().loadVtkImageData(filename);
253 
254  if (source)
255  std::cout << "DummyImageStreamer: Initialized with source file: " << getFileName().toStdString() << std::endl;
256  else
257  std::cout << "DummyImageStreamer: Failed to initialize with source file: " << getFileName().toStdString() << std::endl;
258 
259  return source;
260 }
261 QString DummyImageStreamer::getFileName()
262 {
263  return mFilename;
264 }
265 
267 {
269 }
270 
271 
272 void DummyImageStreamer::createTestDataSource(vtkImageDataPtr source)
273 {
274  mPrimaryDataSource = ImageTestData::initializePrimaryData(source, getFileName());
275 
276  if (!this->shouldSetupSecondaryDataSource())
277  return;
278 
279  mSecondaryDataSource = ImageTestData::initializeSecondaryData(source, getFileName());
280  std::cout << "DummyImageStreamer: Initialized secondary data with uid=" << mSecondaryDataSource.mRawUid << std::endl;
281 }
282 
284 {
286 
287  QString filename = arguments["filename"];
288  bool secondary = arguments.count("secondary") ? true : false;
289  this->initialize(filename, secondary);
290 }
291 
292 void DummyImageStreamer::initialize(QString filename, bool secondaryStream, bool sendonce)
293 {
294  mUseSecondaryStream = secondaryStream;
295  mFilename = filename;
296  vtkImageDataPtr source = this->internalLoadImage(filename);
297  if (!source)
298  {
299  this->setInitialized(false);
300  return;
301  }
302  this->createTestDataSource(source);
303  this->setSendOnce(sendonce);
304  this->createSendTimer(sendonce);
305  this->setInitialized(true);
306 }
307 
309 {
310  if (!this->isInitialized())
311  {
312  reportError("DummyImageStreamer: Failed to start streaming: Not initialized.");
313  return;
314  }
315  mSender = sender;
316  mSendTimer->start(this->getSendInterval());
317 }
318 
320 {
321  mSendTimer->stop();
322 }
323 
325 {
326  return this->isInitialized();
327 }
328 
329 vtkSmartPointer<vtkImageData> DummyImageStreamer::hasSecondaryData()
330 {
331  return mSecondaryDataSource.mImageData;
332 }
333 
334 void DummyImageStreamer::sendTestDataFrames()
335 {
336  PackagePtr primaryPackage = ImageTestData::createPackage(&mPrimaryDataSource);
337  mSender->send(primaryPackage);
338 
339  if(!this->hasSecondaryData())
340  return;
341 
342  PackagePtr secondaryPackage = ImageTestData::createPackage(&mSecondaryDataSource);
343  mSender->send(secondaryPackage);
344 }
345 
346 void DummyImageStreamer::streamSlot()
347 {
348  if (!this->isReadyToSend())
349  return;
350 
351  this->sendTestDataFrames();
352 }
353 
354 void DummyImageStreamer::setSendOnce(bool sendonce)
355 {
356  mSendOnce = sendonce;
357 }
358 
359 bool DummyImageStreamer::shouldSetupSecondaryDataSource()
360 {
361  return mUseSecondaryStream;
362 }
363 
364 } //namespace cx
cxResource_EXPORT ProfilePtr profile()
Definition: cxProfile.cpp:176
static BoolPropertyPtr initialize(const QString &uid, QString name, QString help, bool value, QDomNode root=QDomNode())
void reportError(QString msg)
Definition: cxLogger.cpp:92
void createSendTimer(bool singleshot=false)
Definition: cxStreamer.cpp:63
static PackagePtr createPackage(ImageTestData *data)
static ImageTestData initializePrimaryData(vtkImageDataPtr source, QString filename)
FilePathPropertyPtr getFilenameOption(QDomElement root)
void setSendInterval(int milliseconds)
how often an image should be sent (in milliseconds)
Definition: cxStreamer.cpp:43
vtkLookupTablePtr createLookupTable(int numberOfTableValues)
vtkImageDataPtr mImageData
bool isReadyToSend()
Definition: cxStreamer.cpp:70
boost::shared_ptr< class Image > ImagePtr
Definition: cxDicomWidget.h:48
virtual std::vector< PropertyPtr > getSettings(QDomElement root)
virtual void initialize(QString filename, bool secondaryStream, bool sendonce=false)
virtual vtkImageDataPtr loadVtkImageData(QString filename)
vtkSmartPointer< class vtkImageMapToColors > vtkImageMapToColorsPtr
std::map< QString, QString > StringMap
vtkSmartPointer< class vtkImageAppendComponents > vtkImageAppendComponentsPtr
A volumetric data set.
Definition: cxImage.h:66
boost::shared_ptr< class BoolPropertyBase > BoolPropertyBasePtr
virtual void startStreaming(SenderPtr sender)
void setInitialized(bool initialized)
Definition: cxStreamer.cpp:53
vtkSmartPointer< class vtkLookupTable > vtkLookupTablePtr
vtkImageDataPtr applyLUTToImage(vtkImageDataPtr input, vtkLookupTablePtr lut)
virtual QStringList getArgumentDescription()
static FilePathPropertyPtr initialize(const QString &uid, QString name, QString help, QString value, QStringList paths, QDomNode root=QDomNode())
vtkSmartPointer< class vtkImageExtractComponents > vtkImageExtractComponentsPtr
boost::shared_ptr< struct Package > PackagePtr
bool isInitialized()
Definition: cxStreamer.cpp:58
boost::shared_ptr< class SplitFramesContainer > mDataSource
QTimer * mSendTimer
Definition: cxStreamer.h:87
vtkImageDataPtr convertToTestColorImage(vtkImageDataPtr image)
boost::shared_ptr< class FilePathProperty > FilePathPropertyPtr
StringMap convertToCommandLineArguments(QDomElement root)
boost::shared_ptr< class BoolProperty > BoolPropertyPtr
boost::shared_ptr< Sender > SenderPtr
Definition: cxSender.h:85
vtkSmartPointer< class vtkImageData > vtkImageDataPtr
Reader for metaheader .mhd files.
SenderPtr mSender
Definition: cxStreamer.h:86
static ImageTestData initializeSecondaryData(vtkImageDataPtr source, QString filename)
virtual void initialize(StringMap arguments)
Definition: cxStreamer.cpp:80
BoolPropertyBasePtr getSecondaryOption(QDomElement root)
int getSendInterval() const
how often an image should be sent (in milliseconds)
Definition: cxStreamer.cpp:48