Fraxinus  17.12-rc4
An IGT application
cxVideoGraphics.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 
34 #include "cxVideoGraphics.h"
35 
36 #include <vtkActor.h>
37 #include <vtkImageData.h>
38 #include <vtkPlaneSource.h>
39 #include <vtkTransformTextureCoords.h>
40 #include <vtkTextureMapToPlane.h>
41 #include <vtkDataSetMapper.h>
42 #include <vtkTexture.h>
43 #include <vtkProperty.h>
44 #include <vtkImageMask.h>
45 #include <vtkPointData.h>
46 #include <vtkMatrix4x4.h>
47 #include <vtkLookupTable.h>
48 #include <vtkImageThreshold.h>
49 #include <vtkImageChangeInformation.h>
50 #include <vtkExtractVOI.h>
51 
53 #include "cxBoundingBox3D.h"
54 #include "cxLogger.h"
55 
56 namespace cx
57 {
58 
60 {
61  mPlaneActor = vtkActorPtr::New();
62  mPlaneSource = vtkPlaneSourcePtr::New();
63 
64  mDataRedirecter = vtkImageChangeInformationPtr::New();
65  mUSSource = UltrasoundSectorSourcePtr::New();
66 
67  // set a filter that map all zeros in the input to ones. This enables us to
68  // use zero as a special transparency value, to be used in masking.
69  mMapZeroToOne = vtkImageThresholdPtr::New();
70  mMapZeroToOne->ThresholdByLower(1.0);
71  mMapZeroToOne->SetInValue(1);
72  mMapZeroToOne->SetReplaceIn(true);
73 
74  // set the filter that applies a mask to the stream data
75  mMaskFilter = vtkImageMaskPtr::New();
76  mMaskFilter->SetMaskInputData(vtkImageDataPtr());
77  mMaskFilter->SetMaskedOutputValue(0.0);
78 
79  // generate texture coords for mPlaneSource
80  mTextureMapToPlane = vtkTextureMapToPlanePtr::New();
81 
82  mTransformTextureCoords = vtkTransformTextureCoordsPtr::New();
83  mTransformTextureCoords->SetOrigin( 0, 0.5, 0);
84  mTransformTextureCoords->SetScale( 1, 1, 0);
85  mTransformTextureCoords->FlipROn(); // flip around axis
86 
87  mTexture = vtkTexturePtr::New();
88  mTexture->RepeatOff();
89 
90  mDataSetMapper = vtkDataSetMapperPtr::New();
91 
92  mPlaneActor->SetTexture(mTexture);
93  mPlaneActor->SetMapper(mDataSetMapper);
94  mPlaneActor->SetVisibility(false);
95  mPlaneActor->GetProperty()->LightingOff(); // Turning off lighting to remove shadow effects (Fix for #644: 2D ultrasound in 3D scene was too dark)
96 // mPlaneActor->GetProperty()->ShadingOff();
97 }
98 
100 {
101 }
102 
104 {
105  mTransformTextureCoords->SetFlipR(on); // flip around axis
106 }
107 
109 {
110  return mTransformTextureCoords->GetFlipR();
111 }
112 
114 {
115  return mPlaneActor;
116 }
117 
121 void VideoGraphics::setupPipeline()
122 {
123  if (!mInputVideo)
124  {
125  mTexture->SetInputData(NULL);
126  return;
127  }
128 
129  if (mInputMask)
130  {
131  mTextureMapToPlane->SetInputConnection(mPlaneSource->GetOutputPort());
132  mTransformTextureCoords->SetInputConnection(mTextureMapToPlane->GetOutputPort() );
133  mDataSetMapper->SetInputConnection(mTransformTextureCoords->GetOutputPort() );
134 
135  mMaskFilter->SetMaskInputData(mInputMask);
136  mMapZeroToOne->SetInputConnection(mDataRedirecter->GetOutputPort());
137  mMaskFilter->SetInputConnection(0, mMapZeroToOne->GetOutputPort());
138  mTexture->SetInputConnection(mMaskFilter->GetOutputPort());
139  }
140  else if (mInputSector)
141  {
142  mUSSource->setProbeSector(mInputSector);
143  mTransformTextureCoords->SetInputConnection(mUSSource->GetOutputPort() );
144  mDataSetMapper->SetInputConnection(mTransformTextureCoords->GetOutputPort() );
145 
146  mTexture->SetInputConnection(mDataRedirecter->GetOutputPort());
147  }
148  else
149  {
150  mTextureMapToPlane->SetInputConnection(mPlaneSource->GetOutputPort());
151  mTransformTextureCoords->SetInputConnection(mTextureMapToPlane->GetOutputPort() );
152  mDataSetMapper->SetInputConnection(mTransformTextureCoords->GetOutputPort() );
153 
154  mTexture->SetInputConnection(mDataRedirecter->GetOutputPort());
155  }
156 
157  this->setLookupTable();
158  mPlaneActor->SetTexture(mTexture);
159  mPlaneActor->SetMapper(mDataSetMapper);
160 }
161 
163 {
164  if (mInputMask==mask)
165  return;
166  mInputSector = NULL;
167  mInputMask = mask;
168  this->setupPipeline();
169 }
170 
172 {
173  if (mInputSector==sector)
174  return;
175  mInputMask = NULL;
176  mInputSector = sector;
177  this->setupPipeline();
178 }
179 
181 {
182  if (mInputVideo==video)
183  return;
184  mInputVideo = video;
185  this->setupPipeline();
186 }
187 
189 {
190  mPlaneActor->SetUserMatrix(rMu);
191 }
192 
194 {
195  mPlaneActor->SetVisibility(visible);
196  mPlaneActor->Modified();
197 }
198 
200 {
201  if (this->inputImageIsEmpty())
202  {
203  this->setVisibility(false);
204  return;
205  }
206 
207  this->connectVideoImageToPipeline();
208  this->updateLUT();
209  this->updatePlaneSourceBounds();
210 
211  mPlaneActor->Modified();
212 }
213 
214 void VideoGraphics::connectVideoImageToPipeline()
215 {
216  if (mInputVideo == NULL)
217  {
218  mTexture->SetInputData(NULL); // TODO trouble - will destroy the pipeline
219  return;
220  }
221 
222  //Check if 3D volume. If so, only use middle frame
223  int* extent = mInputVideo->GetExtent();
224  if(extent[5] - extent[4] > 0)
225  {
226  int slice = floor(extent[4]+0.5f*(extent[5]-extent[4]));
227  if (slice < 0) slice = 0;
228 // std::cout << "Got 3D volume, showing middle slice: " << slice << std::endl;
229  vtkSmartPointer<vtkExtractVOI> extractVOI = vtkSmartPointer<vtkExtractVOI>::New();
230  extractVOI->SetInputData(mInputVideo);
231  extractVOI->SetVOI(extent[0], extent[1], extent[2], extent[3], slice, slice);
232  extractVOI->Update();
233  mDataRedirecter->SetInputConnection(extractVOI->GetOutputPort());
234  }
235  else //2D
236  {
237  mDataRedirecter->SetInputData(mInputVideo);
238  }
239 
240  mDataRedirecter->UpdateWholeExtent(); // important! syncs update extent to whole extent
241  mDataRedirecter->Update();
242 // mDataRedirecter->GetOutput()->Update(); //???
243 }
244 
245 void VideoGraphics::updatePlaneSourceBounds()
246 {
247  // set the planesource where we have no ProbeDefinition.
248  // TODO dont do this when planesource is not part of pipeline.
249  DoubleBoundingBox3D bounds(mDataRedirecter->GetOutput()->GetBounds());
250  if (!similar(bounds.range()[0], 0.0) || !similar(bounds.range()[1], 0.0))
251  {
252  mPlaneSource->SetOrigin(bounds.corner(0,0,0).begin());
253  mPlaneSource->SetPoint1(bounds.corner(1,0,0).begin());
254  mPlaneSource->SetPoint2(bounds.corner(0,1,0).begin());
255  mPlaneSource->GetOutput()->GetPointData()->Modified();
256  mPlaneSource->GetOutput()->Modified();
257  }
258 }
259 
260 void VideoGraphics::updateLUT()
261 {
262  this->setLookupTable();
263  mTexture->SetLookupTable(mLUT);
264 
265  // apply a lut only if the input data is monochrome
266  int numComp = mDataRedirecter->GetOutput()->GetNumberOfScalarComponents();
267  bool is8bit = mDataRedirecter->GetOutput()->GetScalarType()==VTK_UNSIGNED_CHAR;
268  if (numComp==1)
269  {
270  double srange[2];
271  if (is8bit)
272  {
273  srange[0] = 0;
274  srange[1] = 255;
275  }
276  else
277  {
278  mDataRedirecter->GetOutput()->GetScalarRange(srange);
279  }
280 
281  mTexture->GetLookupTable()->SetRange(srange[0], srange[1]);
282  mTexture->MapColorScalarsThroughLookupTableOn();
283  }
284  else
285  {
286  mTexture->MapColorScalarsThroughLookupTableOff();
287  }
288 }
289 
292 void VideoGraphics::setLookupTable()
293 {
294  // applies only to mask:
295  // Create a lut of size at least equal to the data range. Set the tableRange[0] to zero.
296  // This will force input zero to be mapped onto the first table value (the transparent one),
297  // and inputs [1, -> > is mapped to larger values, not transparent.
298  // In order to create a window-level function, manually build a table.
299 
300  //make a default system set lookuptable, grayscale...
301  vtkLookupTablePtr lut = vtkLookupTablePtr::New();
302  lut->SetNumberOfTableValues(1000); // large enough to give resolution even for ct images.
303  //lut->SetTableRange (0, 1024); // the window of the input
304  lut->SetTableRange (0, 255); // the window of the input - must be reset according to data
305  lut->SetSaturationRange (0, 0);
306  lut->SetHueRange (0, 0);
307  lut->SetValueRange (0, 1);
308  lut->SetRampToLinear();
309  lut->Build();
310 
311  if (mInputMask)
312  {
313  lut->SetTableValue(0, 0, 0, 0, 0); // set the lowest value to transparent. This will make the masked values transparent, but nothing else
314  }
315 
316  lut->Modified();
317  mLUT = lut;
318 }
319 
320 bool VideoGraphics::inputImageIsEmpty()
321 {
322  if (mInputVideo == NULL)
323  return true;
324 // mInputVideo->Update();
325  //Don't do anything if we get an empty image
326  int* dim = mInputVideo->GetDimensions();
327  if(dim[0] == 0 || dim[1] == 0)
328  return true;
329 
330  return false;
331 }
332 
333 } // namespace cx
vtkSmartPointer< class vtkMatrix4x4 > vtkMatrix4x4Ptr
Definition: cxMathBase.h:58
vtkSmartPointer< class vtkActor > vtkActorPtr
void setActorUserMatrix(vtkMatrix4x4Ptr rMu)
void setClip(vtkPolyDataPtr sector)
void setFlipVertical(bool on)
void setVisibility(bool visible)
vtkSmartPointer< class vtkLookupTable > vtkLookupTablePtr
Representation of a floating-point bounding box in 3D. The data are stored as {xmin,xmax,ymin,ymax,zmin,zmax}, in order to simplify communication with vtk.
vtkSmartPointer< vtkPolyData > vtkPolyDataPtr
bool similar(const CameraInfo &lhs, const CameraInfo &rhs, double tol)
vtkActorPtr getActor()
void setInputVideo(vtkImageDataPtr video)
void setMask(vtkImageDataPtr mask)
vtkSmartPointer< class vtkImageData > vtkImageDataPtr
Namespace for all CustusX production code.