Vous avez reçu un message "Your GitLab account has been locked ..." ? Pas d'inquiétude : lisez cet article https://docs.gricad-pages.univ-grenoble-alpes.fr/help/unlock/

Slice.h 13.9 KB
Newer Older
1
/*****************************************************************************
2
3
4
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
5
 * (c) 2001-2018 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/
25
26
27
28
29
30
31
32
33

#ifndef CANONICAL_SLICE_H
#define CANONICAL_SLICE_H

// -- Core stuff
#include "CamiTKAPI.h"
#include "InterfaceBitMap.h"

// -- vtk stuff
34
#include <vtkImageData.h>
35
#include <vtkWindowLevelLookupTable.h>
36
#include <vtkTransform.h>
37
38
39
40
#include <vtkActor.h>
#include <vtkImageActor.h>
#include <vtkUnstructuredGrid.h>

41
42
namespace camitk {
/**
43
 * @ingroup group_sdk_libraries_core_component
44
 *
45
 * @brief
46
47
48
49
50
51
52
53
54
55
56
 * Display a slice (i.e. an image or BitMap) of an @ref camitk::ImageComponent "ImageComponent". Helper class.
 * 
 * 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 slice is represented in 2D and 3D thanks to:
 * - image2DActor that provides a 2D representation (the slice in the world reference frame)
 * - image3DActor that provides a 3D representation (the slice at this actual 3D position)
 * Both are updated thanks to vtkImageActor::SetDisplayExtent.
 * 
 * \note the setImageWorldTransform(...) methods is used to set the user transform of the image 3D actor.
57
 *
58
 * Slice also manages two other actors to visualize user picking inside the image:
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
 * - the picked plane actor (a wireframe box made of 4 quads around the picked plane) that shows the image border
 * - the picked pixel actor (two wireframe quads centered on the currently picked pixel) that shows the position
 *   of the currently picked pixel.
 * These two actors are build using unstructured grids.
 * 
 * The picked plane actor is defined by 8 points surrounding the current image plane.
 * The points are set at the coordinates of the (red / blue / green) border of the current image plane.
 * To make sure that the borders are visible in any specific orientation, four quads are build from this points.
 * Each quad goes out of the image plane on both side (back and front).
 * 
 * The picked pixel actor is also made of 8 points that describes the cross centered on the currently picked pixel.
 * The points are set at the coordinates of the (red / blue / green) cross around the picked pixel.
 * To make sure that the cross is visible in any specific orientation, two quads are build from this 8 points 
 * Each quad goes out of the image plane on both side
 *
 * \note (easter egg) hit "t" on any slice viewer and move the camera around to see the quad geometries and
 * how these extra actors are build.
76
 *
77
 * 
78
79
80
81
82
83
84
85
86
87
88
89
90
91
 *  \verbatim
 *       3D Volume                         2D Slice
 *       ________  /|\
 *      /|      /|  |                      _______
 *     /______ / | _|_slice     ===>      /       /        Displayed in
 *    |  |____|_/|  |  number            /______ /         the window
 *    | /     |//
 *    |/______|/
 *
 *                                          ________________
 *                                         | vtkLookUpTable |
 *                                      ---|                |
 *                                     |   |    lut         |
 *                                     |   |________________|
92
 *  setOriginalVolume(..)              |
93
94
95
96
97
98
99
100
101
102
103
104
105
106
 *   |                                 | setLookUpTable
 *   |                   setInput      |                                   __________________
 *   |   ________________       _______v____________                      |  vtkImageActor   |
 *   |  |  vtkImageData  |     | vtkImageMapToColor |                     |(setDisplayExtent)|
 *   |_\|                |----\|                    |-------------------\ |                  |
 *     /| originalVolume |----/|   imgToMapFilter   |-------------------/ |   image2DActor   |
 *      |________________|     |____________________|     | |             |__________________|
 *                                                        | |
 *                                                        | |              _________________________            __________________
 *                                                        | |             |  vtkTransformFilter     |          |  vtkImageActor   |
 *                                                        |  -----------\ |(setWorldTransformation) | --------\|(setDisplayExtent)|
 *                                                         -------------/ |                         | --------/|                  |
 *                                                                        |                         |          |   image3DActor   |
 *                                                                        |_________________________|          |__________________|
107
108
109
110
111
112
113
 *
 *
 *
 * \endverbatim
 *
 */

114
class CAMITK_API Slice : public InterfaceBitMap {
115
public:
116
117
    /** Common slices orientation: axial, sagittal, coronal axial_neuro.
     * Axial, Sagittal and Coronal orientation are given in Radiologist point of view.
118
     * The neurologist point of view is displayed in axial_neuro.
119
     *
120
121
122
123
124
125
126
127
128
129
130
131
132
     * The ImageComponent is supposed to be given in RAI orientation !
     * (see Image Reorientation Action Documentation).
     * @image imageRAI.png
     *
     * AXIAL:     from feet  to head of the patient
     * @image axialView.png
     *
     * CORONAL:   from the front to back  of the patient
     * @image coronalView.png
     *
     * SAGITTAL:  from the right to left of the patient
     * @image sagittalView.png
     *
133
134
135
     * AXIAL_NEURO: from head to feet (other side of AXIAL)
     *
     * ARBITRARY: any arbitrary orientation.
136
137
     *
     */
138
    enum SliceOrientation {
139
140
141
        AXIAL,
        CORONAL,
        SAGITTAL,
142
143
        AXIAL_NEURO,
        ARBITRARY
144
    };
145

146
147
    /// @name Constructors / Destructors 
    /// @{                                                                   
148
    /// Constructor
149
    Slice(vtkSmartPointer<vtkImageData> volume, SliceOrientation AXIAL_ORIENTATION, vtkSmartPointer<vtkWindowLevelLookupTable> lookupTable = nullptr);
150

151
    /// virtual destructor
Emmanuel Promayon's avatar
Emmanuel Promayon committed
152
    ~Slice() override;
153
154
155
156
    /// @}
    
    /// @name  InterfaceBitMap implementation  
    /// @{
157
158

    /// set the original volume image data (the source vtkImageData before any reslice) and refresh the vtk pipeline
Emmanuel Promayon's avatar
Emmanuel Promayon committed
159
    void setOriginalVolume(vtkSmartPointer<vtkImageData> img) override;
160

161
    /// set the transformation for 3D image representation
Emmanuel Promayon's avatar
Emmanuel Promayon committed
162
    void setImageWorldTransform(vtkSmartPointer<vtkTransform>) override;
163

164
    /** Return the vtkImageActor (vtkProp) representing a slice to be displayed in the 2D viewers. */
Emmanuel Promayon's avatar
Emmanuel Promayon committed
165
    vtkSmartPointer<vtkImageActor> get2DImageActor() const override;
166

167
    /** Return the vtkImageActor (vtkProp) representing a slice to be displayed in the 3D viewers. */
Emmanuel Promayon's avatar
Emmanuel Promayon committed
168
    vtkSmartPointer<vtkImageActor> get3DImageActor() const override;
169

170
    /** Return the vtkActor visualizing the plane of the slices. */
Emmanuel Promayon's avatar
Emmanuel Promayon committed
171
    vtkSmartPointer<vtkActor> getPickPlaneActor() const override;
172

173
    /** Return the vtkActor visualizing the picked pixels in the slices. */
Emmanuel Promayon's avatar
Emmanuel Promayon committed
174
    vtkSmartPointer<vtkActor> getPixelActor() override;
175
176
177
178

    /** This method is called when the associated plane has been picked in the InteractiveViewer,
     *  the given coordinates is position where the plane was picked.
     */
Emmanuel Promayon's avatar
Emmanuel Promayon committed
179
    void pixelPicked(double, double, double) override;
180

181
    /// update the position of the plane surrounding the currently selected slice
Emmanuel Promayon's avatar
Emmanuel Promayon committed
182
    void updatePickPlane() override;
183
184

    /** Return the number of slices in the image data set. */
Emmanuel Promayon's avatar
Emmanuel Promayon committed
185
    int getNumberOfSlices() const override;
186
187

    /** Return the index of the current displayed slice. */
Emmanuel Promayon's avatar
Emmanuel Promayon committed
188
    int getSlice() const override;
189
190
191
192
193

    /** Set the current slice index.
     * If the slice index is less than the first slice index, the first slice is displayed.
     * If the slice index is more than the last slice index, the last slice is displayed.
     * @param s the index of the slice to display (base 0). */
Emmanuel Promayon's avatar
Emmanuel Promayon committed
194
    void setSlice(int s) override;
195

196
    /// Set the slice corresponding to the given real image (RAI) coordinates
Emmanuel Promayon's avatar
Emmanuel Promayon committed
197
    void setSlice(double x, double y, double z) override;
198

199
200
201
    /** Return the number of colors in the images.
    * If color is coded on 1 byte, the images are on 256 grey level.
    * If color is coded on 2 bytes, the images are on 4096 grey level (not 65536). */
Emmanuel Promayon's avatar
Emmanuel Promayon committed
202
    int getNumberOfColors() const override;
203
204

    /// move the pixel selection green indicator (pixelActor) to the given real position
Emmanuel Promayon's avatar
Emmanuel Promayon committed
205
    void setPixelRealPosition(double, double, double) override;
206

207
    /// get the current image data
Emmanuel Promayon's avatar
Emmanuel Promayon committed
208
    vtkSmartPointer<vtkImageData> getImageData() const override;
209

210
211
212
213
214
215
216
217
218
219
220
    // @}
    
    /// @name manage extra prop associated with a Slice
    /// @{
    /// TODO 
    /// - put all this management into a dedicated interface 
    /// - remove it from InterfaceBitMap and InterfaceGeometry
    /// - remove it from Slice and Geometry helper classes
    /// - create a new associated helper class
    /// - update Component class and all other code using it (if needed)
    /// Note : beware that Geometry requires this to manage to at least "label" and "glyph" extra actors
221
222

    /// Return the vtkProp (actors, volumes and annotations) corresponding to the given name
Emmanuel Promayon's avatar
Emmanuel Promayon committed
223
    vtkSmartPointer<vtkProp> getProp(const QString&) override;
224
225

    /// return the number of additional prop
Emmanuel Promayon's avatar
Emmanuel Promayon committed
226
    unsigned int getNumberOfProp() const override;
227
228

    /// return an additional prop by its index
Emmanuel Promayon's avatar
Emmanuel Promayon committed
229
    vtkSmartPointer<vtkProp> getProp(unsigned int) override;
230
231
232
233

    /** insert an additional prop, defining it by its name (default visibility = false)
     *  @return true if the additional prop was added (i.e. another additional prop of the same name does not exist)
     */
Emmanuel Promayon's avatar
Emmanuel Promayon committed
234
    bool addProp(const QString&,  vtkSmartPointer<vtkProp>) override;
235

236
237
238
    /** remove a given additional prop.
     * @return true if effictively done
     */
Emmanuel Promayon's avatar
Emmanuel Promayon committed
239
    bool removeProp(const QString&) override;
240
241
    
    /// @}
242

243
244

protected:
245
246
247
   
    /// @name Protected utility methods
    /// @{
248

249
250
251
252
253
254
    /** Initialize Attributes */
    virtual void init();

    /** Initialize actors and everything they need.*/
    virtual void initActors();

255
256
257
258
259
260
261
262
263
264
265
266
267
268
    /** Compute the volume coordinates (xyz) from the resliced coordinates (ijk)
     *  @param ijk: given resliced coordinates (generally from a pixel picked in the pickPlane)
     *  @param xyz: output (should be allocated before calling this function) volume coordinates (with image at the origin in RAI convention) computed from the input
    */
    void reslicedToVolumeCoords(const double* ijk, double* xyz);

    /// Compute the resliced coordinates (ijk) from the volume coordinates (xyz)
    /// @param xyz: given volume coordinates (with image at the origin in RAI convention)
    /// @param ijk: output (should be allocated before calling this function) resliced coordinates computed from the input
    void volumeToReslicedCoords(const double* xyz, double* ijk);
    /// @}

    /// @name Attributes / Members of the class                     
    /// @{
269
270

    /** Direction of the reslice */
271
    SliceOrientation sliceOrientation;
272
273
274

    /** Smart pointer to the original volume to reslice (input of the vtk pipeline) */
    vtkSmartPointer<vtkImageData> originalVolume;
275

276
    /** Keep track of the slice number */
277
278
279
    int currentSliceIndex;

    /// Common lookup table
280
    vtkSmartPointer<vtkWindowLevelLookupTable> lut;
281

282
283
    /** Voxel size of the original image volume. Used to compute point coordinates between real world and index world.*/
    double originalSpacing[3];
284

285
286
    /** Real size (originalDimension * originalSpacing in x, y and z) of the original image */
    double originalSize[3];
287
288

    /// 3D actor
289
    vtkSmartPointer<vtkImageActor> image3DActor;
290

291
    /// 2D actor
292
293
294
    vtkSmartPointer<vtkImageActor> image2DActor;
    
    /// @}
295

296
297
    /// @name  Used to visualize the current picking 
    /// @{
298

299
300
301
    /// init the pick plane actor
    void initPickPlaneActor();
    
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
    /**
     * Init the pixel actor for pixel picking
     */
    void initPixelActor();

    /** Update the pixel actor position according to the specified pixel picked by the user
     * i.e. Compute and draw the bounding box around the selected pixel.
     * @param x:
     * The absciss value of the selected pixel
     * @param y:
     * The ordinate value of the selected pixel
     * @param z:
     * The depth value of the selected pixel. In the plane, it's always +/- 0.01 in order to the pixel actor to be
     * visible over the slice.
     **/
317
    void updatePixelActor(double x, double y, double z);
318

319
    /// update the pixel actor to the middle of the current slice
320
321
322
323
324
    void updatePixelActor();

    /** Actor representing the pickPlane. */
    vtkSmartPointer<vtkActor> pickPlaneActor;

325
326
327
    /// the pick plane actor unstructured grid
    vtkSmartPointer<vtkUnstructuredGrid> pickPlaneActorPointSet;  
    
328
329
    /** Actor representing a pixel, displayed over the image. */
    vtkSmartPointer<vtkActor> pixelActor;
330

331
332
    /// the pixel actor unstructured grid
    vtkSmartPointer<vtkUnstructuredGrid> pixelActorPointSet;    
333
334
335
336
337
338
339
340
341
342
    /// @}
    
    /// @name manage extra prop associated with a Slice
    /// @{
    /// TODO see extra prop management method section

    /// The additional map for prop
    QMap<QString, vtkSmartPointer<vtkProp> > extraProp;
    
    /// @}
343
344
345
346
347
};

}

#endif // CANONICAL_SLICE_H