Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
CamiTK Community Edition
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
17
Issues
17
List
Boards
Labels
Service Desk
Milestones
Merge Requests
2
Merge Requests
2
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
CamiTK
CamiTK Community Edition
Commits
94ad509e
Commit
94ad509e
authored
Jan 04, 2020
by
Emmanuel Promayon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
FIXED bug resulting from merge conflicts + code simplification
parent
aa092313
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
107 additions
and
93 deletions
+107
-93
sdk/libraries/core/component/Slice.cpp
sdk/libraries/core/component/Slice.cpp
+96
-78
sdk/libraries/core/component/Slice.h
sdk/libraries/core/component/Slice.h
+11
-15
No files found.
sdk/libraries/core/component/Slice.cpp
View file @
94ad509e
...
...
@@ -36,6 +36,7 @@
#include <vtkQuad.h>
#include <vtkDataSetMapper.h>
#include <vtkImageMapToColors.h>
#include <vtkImageChangeInformation.h>
using
namespace
std
;
...
...
@@ -61,7 +62,7 @@ Slice::~Slice() {
void
Slice
::
init
()
{
currentSliceIndex
=
0
;
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
originalSpacing
[
i
]
=
1.0
;
}
...
...
@@ -72,13 +73,8 @@ void Slice::init() {
pickPlaneActorPointSet
=
nullptr
;
pixelActor
=
nullptr
;
pixelActorPointSet
=
nullptr
;
image2DChangeInfo
=
vtkSmartPointer
<
vtkImageChangeInformation
>::
New
();
image2DReslicer
=
vtkSmartPointer
<
vtkImageReslice
>::
New
();
transformReslicer
=
vtkSmartPointer
<
vtkTransform
>::
New
();
resliceTransform
=
vtkSmartPointer
<
vtkTransform
>::
New
();
transformReslicer
->
Identity
();
resliceTransform
->
Identity
();
image2DReslicer
=
nullptr
;
resliceTransform
=
nullptr
;
}
// -------------------- getImageData --------------------
...
...
@@ -93,22 +89,22 @@ void Slice::setOriginalVolume(vtkSmartPointer<vtkImageData> volume) {
originalVolume
=
volume
;
// Get the original volume information
// Original volume dimensions in number of voxels (x, y and z)
int
originalDimensions
[
3
];
// Original volume dimensions in number of voxels (x, y and z)
int
originalDimensions
[
3
];
originalVolume
->
GetDimensions
(
originalDimensions
);
originalVolume
->
GetSpacing
(
originalSpacing
);
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
// compute original size (nb of slice * spacing)
originalSize
[
i
]
=
originalDimensions
[
i
]
*
originalSpacing
[
i
];
// As originalSpacing[i] will be used to get the slice number
// for 2D images, lets replace 0.0 by 1.0 to avoid division by 0
if
(
originalSpacing
[
i
]
==
0.0
)
{
originalSpacing
[
i
]
=
1.0
;
}
}
// Prepare all the visualization pipeline
initActors
();
}
...
...
@@ -143,12 +139,12 @@ int Slice::getNumberOfSlices() const {
// 0 & 1 -> x; 2 and 3 -> y; 4 & 5 -> z
int
extent
[
6
];
originalVolume
->
GetExtent
(
extent
);
int
nbSlices
;
switch
(
sliceOrientation
)
{
case
ARBITRARY
:
nbSlices
=
max
(
max
(
extent
[
1
]
-
extent
[
0
],
extent
[
3
]
-
extent
[
2
]),
extent
[
5
]
-
extent
[
4
])
+
1
;
break
;
case
ARBITRARY
:
nbSlices
=
max
(
max
(
extent
[
1
]
-
extent
[
0
],
extent
[
3
]
-
extent
[
2
]),
extent
[
5
]
-
extent
[
4
])
+
1
;
break
;
case
AXIAL
:
case
AXIAL_NEURO
:
nbSlices
=
extent
[
5
]
-
extent
[
4
]
+
1
;
...
...
@@ -193,9 +189,9 @@ void Slice::setSlice(int s) {
originalVolume
->
GetExtent
(
extent
);
switch
(
sliceOrientation
)
{
case
ARBITRARY
:
updateReslice
();
break
;
case
ARBITRARY
:
updateReslice
();
break
;
case
AXIAL
:
case
AXIAL_NEURO
:
image3DActor
->
SetDisplayExtent
(
extent
[
0
],
extent
[
1
],
extent
[
2
],
extent
[
3
],
s
,
s
);
...
...
@@ -245,9 +241,9 @@ void Slice::setSlice(double x, double y, double z) {
// Set pixel position in current slice.
setPixelRealPosition
(
x
,
y
,
z
);
// show the pixel actor
pixelActor
->
VisibilityOn
();
pixelActor
->
VisibilityOn
();
}
// -------------------- getNumberOfColors --------------------
...
...
@@ -263,45 +259,11 @@ void Slice::setPixelRealPosition(double x, double y, double z) {
// -------------------- setReslicerTransform --------------------
void
Slice
::
setReslicerTransform
(
vtkSmartPointer
<
vtkTransform
>
t
)
{
// store the transformation pointer
// (when the transformation is changed, you need to call updateReslice() in order
// (when the transformation is changed, you need to call updateReslice() in order
// to take the new transformation into account and update the arbitrary slice image
resliceTransform
=
t
;
resliceTransform
=
t
;
}
// -------------------- updateReslice --------------------
void
Slice
::
updateReslice
()
{
if
(
sliceOrientation
==
ARBITRARY
)
{
double
wxyz
[
4
];
transformReslicer
->
Identity
();
transformReslicer
->
Translate
(
originalDimensions
[
0
]
/
2
,
originalDimensions
[
1
]
/
2
,
originalDimensions
[
2
]
/
2
);
resliceTransform
->
GetOrientationWXYZ
(
wxyz
);
transformReslicer
->
RotateWXYZ
(
wxyz
[
0
],
wxyz
[
1
],
wxyz
[
2
],
wxyz
[
3
]);
transformReslicer
->
Translate
(
-
originalDimensions
[
0
]
/
2
,
-
originalDimensions
[
1
]
/
2
,
-
originalDimensions
[
2
]
/
2
);
transformReslicer
->
Translate
(
0.0
,
0.0
,
currentSliceIndex
);
image2DReslicer
->
SetResliceAxes
(
transformReslicer
->
GetMatrix
());
image2DReslicer
->
Update
();
image3DActor
->
SetUserMatrix
(
resliceTransform
->
GetMatrix
());
image3DActor
->
SetInputData
(
image2DReslicer
->
GetOutput
());
image3DActor
->
Update
();
}
updateLocalTransformation
();
updatePickPlane
();
}
// -------------------- updateLocalTransformation --------------------
void
Slice
::
updateLocalTransformation
()
{
image2DReslicer
->
SetOutputDimensionality
(
3
);
image2DReslicer
->
UpdateInformation
();
image2DReslicer
->
SetOutputDimensionality
(
2
);
image2DReslicer
->
UpdateInformation
();
}
// -------------------- get2DImageActor --------------------
vtkSmartPointer
<
vtkImageActor
>
Slice
::
get2DImageActor
()
const
{
return
image2DActor
;
...
...
@@ -331,15 +293,6 @@ void Slice::initActors() {
// set the lookupTable
imgToMapFilter
->
SetLookupTable
(
lut
);
image2DChangeInfo
->
SetInputData
(
imgToMapFilter
->
GetOutput
());
image2DChangeInfo
->
SetOutputOrigin
(
0.0
,
0.0
,
0.0
);
image2DReslicer
->
SetInputConnection
(
image2DChangeInfo
->
GetOutputPort
());
image2DReslicer
->
SetInformationInput
(
imgToMapFilter
->
GetOutput
());
image2DReslicer
->
AutoCropOutputOn
();
image2DReslicer
->
SetOutputOriginToDefault
();
image2DReslicer
->
SetOutputExtentToDefault
();
image2DReslicer
->
SetOutputSpacingToDefault
();
// the 2D and 3D image actors are directly plugged to the output of imgToMapFilter
image3DActor
=
vtkSmartPointer
<
vtkImageActor
>::
New
();
image3DActor
->
GetMapper
()
->
SetInputConnection
(
imgToMapFilter
->
GetOutputPort
());
...
...
@@ -349,11 +302,30 @@ void Slice::initActors() {
image2DActor
->
GetMapper
()
->
SetInputConnection
(
imgToMapFilter
->
GetOutputPort
());
image2DActor
->
InterpolateOn
();
// Pick plane
// reslicer for the arbitrary slice
// image2DChangeInfo builds a simple image from the original image
// that has default origin, extent and spacing
vtkSmartPointer
<
vtkImageChangeInformation
>
image2DChangeInfo
=
vtkSmartPointer
<
vtkImageChangeInformation
>::
New
();
image2DChangeInfo
->
SetInputData
(
imgToMapFilter
->
GetOutput
());
image2DChangeInfo
->
SetOutputOrigin
(
0.0
,
0.0
,
0.0
);
image2DReslicer
=
vtkSmartPointer
<
vtkImageReslice
>::
New
();
image2DReslicer
->
SetInputConnection
(
image2DChangeInfo
->
GetOutputPort
());
image2DReslicer
->
SetInformationInput
(
imgToMapFilter
->
GetOutput
());
image2DReslicer
->
AutoCropOutputOn
();
image2DReslicer
->
SetOutputOriginToDefault
();
image2DReslicer
->
SetOutputExtentToDefault
();
image2DReslicer
->
SetOutputSpacingToDefault
();
// use identity by default for the arbitrary slice
resliceTransform
=
vtkSmartPointer
<
vtkTransform
>::
New
();
resliceTransform
->
Identity
();
// Picked plane
initPickPlaneActor
();
updatePickPlane
();
// pixel
//
Picked
pixel
initPixelActor
();
updatePixelActor
();
}
...
...
@@ -381,7 +353,7 @@ void Slice::initPickPlaneActor() {
topQuad
->
GetPointIds
()
->
SetId
(
1
,
5
);
topQuad
->
GetPointIds
()
->
SetId
(
2
,
1
);
topQuad
->
GetPointIds
()
->
SetId
(
3
,
0
);
vtkSmartPointer
<
vtkQuad
>
rightQuad
=
vtkSmartPointer
<
vtkQuad
>::
New
();
rightQuad
->
GetPointIds
()
->
SetId
(
0
,
5
);
rightQuad
->
GetPointIds
()
->
SetId
(
1
,
4
);
...
...
@@ -393,7 +365,7 @@ void Slice::initPickPlaneActor() {
bottomQuad
->
GetPointIds
()
->
SetId
(
1
,
2
);
bottomQuad
->
GetPointIds
()
->
SetId
(
2
,
6
);
bottomQuad
->
GetPointIds
()
->
SetId
(
3
,
7
);
// Create the unstructured grid that includes the two quads
pickPlaneActorPointSet
=
vtkSmartPointer
<
vtkUnstructuredGrid
>::
New
();
pickPlaneActorPointSet
->
Allocate
(
4
);
...
...
@@ -439,7 +411,7 @@ void Slice::initPickPlaneActor() {
//-- pickPlaneActor can not be picked
pickPlaneActor
->
PickableOff
();
// by default, the plane actor is always visible
pickPlaneActor
->
VisibilityOn
();
}
...
...
@@ -527,8 +499,8 @@ void Slice::updatePickPlane() {
switch
(
sliceOrientation
)
{
case
AXIAL_NEURO
:
case
AXIAL
:
sliceBackPlane
=
currentSliceIndex
*
originalSpacing
[
2
]
-
originalSpacing
[
2
]
/
2.0
;
sliceFrontPlane
=
currentSliceIndex
*
originalSpacing
[
2
]
+
originalSpacing
[
2
]
/
2.0
;
sliceBackPlane
=
currentSliceIndex
*
originalSpacing
[
2
]
-
originalSpacing
[
2
]
/
2.0
;
sliceFrontPlane
=
currentSliceIndex
*
originalSpacing
[
2
]
+
originalSpacing
[
2
]
/
2.0
;
pickPlaneActorPointSet
->
GetPoints
()
->
SetPoint
(
0
,
0.0
,
0.0
,
sliceBackPlane
);
pickPlaneActorPointSet
->
GetPoints
()
->
SetPoint
(
1
,
0.0
,
0.0
,
sliceFrontPlane
);
pickPlaneActorPointSet
->
GetPoints
()
->
SetPoint
(
2
,
0.0
,
originalSize
[
1
],
sliceFrontPlane
);
...
...
@@ -540,8 +512,8 @@ void Slice::updatePickPlane() {
break
;
case
CORONAL
:
sliceBackPlane
=
currentSliceIndex
*
originalSpacing
[
1
]
-
originalSpacing
[
1
]
/
2.0
;
sliceFrontPlane
=
currentSliceIndex
*
originalSpacing
[
1
]
+
originalSpacing
[
1
]
/
2.0
;
sliceBackPlane
=
currentSliceIndex
*
originalSpacing
[
1
]
-
originalSpacing
[
1
]
/
2.0
;
sliceFrontPlane
=
currentSliceIndex
*
originalSpacing
[
1
]
+
originalSpacing
[
1
]
/
2.0
;
pickPlaneActorPointSet
->
GetPoints
()
->
SetPoint
(
0
,
0.0
,
sliceBackPlane
,
0.0
);
pickPlaneActorPointSet
->
GetPoints
()
->
SetPoint
(
1
,
0.0
,
sliceFrontPlane
,
0.0
);
pickPlaneActorPointSet
->
GetPoints
()
->
SetPoint
(
2
,
0.0
,
sliceFrontPlane
,
originalSize
[
2
]);
...
...
@@ -553,8 +525,8 @@ void Slice::updatePickPlane() {
break
;
case
SAGITTAL
:
sliceBackPlane
=
currentSliceIndex
*
originalSpacing
[
0
]
-
originalSpacing
[
0
]
/
2.0
;
sliceFrontPlane
=
currentSliceIndex
*
originalSpacing
[
0
]
+
originalSpacing
[
0
]
/
2.0
;
sliceBackPlane
=
currentSliceIndex
*
originalSpacing
[
0
]
-
originalSpacing
[
0
]
/
2.0
;
sliceFrontPlane
=
currentSliceIndex
*
originalSpacing
[
0
]
+
originalSpacing
[
0
]
/
2.0
;
pickPlaneActorPointSet
->
GetPoints
()
->
SetPoint
(
0
,
sliceBackPlane
,
0.0
,
0.0
);
pickPlaneActorPointSet
->
GetPoints
()
->
SetPoint
(
1
,
sliceFrontPlane
,
0.0
,
0.0
);
pickPlaneActorPointSet
->
GetPoints
()
->
SetPoint
(
2
,
sliceFrontPlane
,
0.0
,
originalSize
[
2
]);
...
...
@@ -636,6 +608,52 @@ void Slice::updatePixelActor(double x, double y, double z) {
pixelActorPointSet
->
Modified
();
}
// -------------------- updateReslice --------------------
void
Slice
::
updateReslice
()
{
if
(
sliceOrientation
==
ARBITRARY
)
{
double
wxyz
[
4
];
// Original volume dimensions in number of voxels (x, y and z)
int
originalDimensions
[
3
];
originalVolume
->
GetDimensions
(
originalDimensions
);
// Transformations required to compute the arbitrary slice inside the volume
vtkSmartPointer
<
vtkTransform
>
transformationInsideVolume
=
vtkTransform
::
New
();
transformationInsideVolume
->
Identity
();
// go to the image center
transformationInsideVolume
->
Translate
(
originalDimensions
[
0
]
/
2
,
originalDimensions
[
1
]
/
2
,
originalDimensions
[
2
]
/
2
);
// apply the current rotation from the frame
resliceTransform
->
GetOrientationWXYZ
(
wxyz
);
transformationInsideVolume
->
RotateWXYZ
(
wxyz
[
0
],
wxyz
[
1
],
wxyz
[
2
],
wxyz
[
3
]);
// go back to the image origin
transformationInsideVolume
->
Translate
(
-
originalDimensions
[
0
]
/
2
,
-
originalDimensions
[
1
]
/
2
,
-
originalDimensions
[
2
]
/
2
);
// translate to the current slice
transformationInsideVolume
->
Translate
(
0.0
,
0.0
,
currentSliceIndex
);
image2DReslicer
->
SetResliceAxes
(
transformationInsideVolume
->
GetMatrix
());
image2DReslicer
->
Update
();
image3DActor
->
SetUserMatrix
(
resliceTransform
->
GetMatrix
());
image3DActor
->
SetInputData
(
image2DReslicer
->
GetOutput
());
image3DActor
->
Update
();
}
updateLocalTransformation
();
updatePickPlane
();
}
// -------------------- updateLocalTransformation --------------------
void
Slice
::
updateLocalTransformation
()
{
image2DReslicer
->
SetOutputDimensionality
(
3
);
image2DReslicer
->
UpdateInformation
();
image2DReslicer
->
SetOutputDimensionality
(
2
);
image2DReslicer
->
UpdateInformation
();
}
...
...
sdk/libraries/core/component/Slice.h
View file @
94ad509e
...
...
@@ -37,6 +37,7 @@
#include <vtkActor.h>
#include <vtkImageActor.h>
#include <vtkUnstructuredGrid.h>
#include <vtkImageReslice.h>
namespace
camitk
{
/**
...
...
@@ -47,6 +48,8 @@ namespace camitk {
*
* This class manages the visual representation of one slice of a volume image.
* The slice depends on the orientation and the currently selected slice index.
* A special case is the arbitrary orientation, where the orientation is not perpendicular to one
* of the axes, but can have any free orientation and translation.
*
* A slice is represented in 2D and 3D thanks to:
* - image2DActor that provides a 2D representation (the slice in the world reference frame)
...
...
@@ -302,26 +305,18 @@ protected:
/// @name Management of the arbitrary slice
/// @{
/// Transformation relative to the 3D image actor (it is not parallel to one
/// of the main axe, but has a specific rotation). This should be initialized
/// using the single image component transformation to the world or parent.
vtkSmartPointer
<
vtkTransform
>
resliceTransform
;
/// Transformations required to compute the arbitrary slice inside the volume
/// this can be any transform, unlike the image orientation
vtkSmartPointer
<
vtkTransform
>
transformReslicer
;
/// Transformation relative to the 3D image actor (it is not parallel to one
/// of the main axe, but has a specific rotation)
vtkSmartPointer
<
vtkTransform
>
resliceTransform
;
/// The image reslicer computes the arbitrary slice pixels
vtkSmartPointer
<
vtkImageReslice
>
image2DReslicer
;
/// update the 2D reslicer
void
updateLocalTransformation
();
/// This is required for the arbitrary slice.
/// It builds a simple image from the original image
/// that has default origin, extent and spacing
vtkSmartPointer
<
vtkImageChangeInformation
>
image2DChangeInfo
;
/// The image reslicer computes the arbitrary slice pixels
vtkSmartPointer
<
vtkImageReslice
>
image2DReslicer
;
/// @}
/// @name Used to visualize the current picking
...
...
@@ -376,3 +371,4 @@ protected:
}
#endif // CANONICAL_SLICE_H
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment