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