File: VtkImageComponent.cpp

package info (click to toggle)
camitk 6.0.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 389,508 kB
  • sloc: cpp: 103,476; sh: 2,448; python: 1,618; xml: 984; makefile: 128; perl: 84; sed: 20
file content (180 lines) | stat: -rw-r--r-- 7,321 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2025 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
 *
 * 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$
 ****************************************************************************/

#include "VtkImageComponent.h"
#include <ImageComponent.h>
#include <Log.h>

//-- Qt
#include <QFileInfo>
#include <QRegularExpression>
#include <QTextStream>

//-- Vtk
// disable warning generated by clang about the surrounded headers
#include <CamiTKDisableWarnings>
// vtk image readers
#include <vtkImageReader2.h>
#include <vtkJPEGReader.h>
#include <vtkPNGReader.h>
#include <vtkTIFFReader.h>
#include <vtkBMPReader.h>
#include <vtkPNMReader.h>
#include <vtkMetaImageReader.h>
#include <CamiTKReEnableWarnings>

#include <vtkImageData.h>
#include <vtkImageFlip.h>
#include <vtkInformation.h>

using namespace camitk;

// -------------------- constructor --------------------
VtkImageComponent::VtkImageComponent(const QString& fileName)
    : ImageComponent(fileName, QFileInfo(fileName).baseName()) {
    readImageData(fileName);
}

// -------------------- readImageData --------------------
void VtkImageComponent::readImageData(const QString& filename) {
    if (!filename.isNull()) {
        try {
            // Reader and image variables
            vtkSmartPointer<vtkImageReader2> reader;
            vtkSmartPointer<vtkImageData> image = nullptr;

            // filename extension
            QString fileExt = QFileInfo(filename).suffix();

            // Reader initialization, depending on file extension
            if (QString::compare(fileExt, "jpg", Qt::CaseInsensitive) == 0) {
                reader = vtkSmartPointer<vtkJPEGReader>::New();
            }
            else if (QString::compare(fileExt, "png", Qt::CaseInsensitive) == 0) {
                reader = vtkSmartPointer<vtkPNGReader>::New();
            }
            else if ((QString::compare(fileExt, "tiff", Qt::CaseInsensitive) == 0) ||
                     (QString::compare(fileExt, "tif",  Qt::CaseInsensitive) == 0)) {
                reader = vtkSmartPointer<vtkTIFFReader>::New();
            }
            else if (QString::compare(fileExt, "bmp", Qt::CaseInsensitive) == 0) {
                reader = vtkSmartPointer<vtkBMPReader>::New();
            }
            else if ((QString::compare(fileExt, "pbm", Qt::CaseInsensitive) == 0) ||
                     (QString::compare(fileExt, "pgm", Qt::CaseInsensitive) == 0) ||
                     (QString::compare(fileExt, "ppm", Qt::CaseInsensitive) == 0)) {
                reader = vtkSmartPointer<vtkPNMReader>::New();
            }
            else if ((QString::compare(fileExt, "mhd", Qt::CaseInsensitive) == 0) ||
                     (QString::compare(fileExt, "mha", Qt::CaseInsensitive) == 0)) {
                reader = vtkSmartPointer<vtkMetaImageReader>::New();
            }
            else {
                throw AbortException("File format " + fileExt.toStdString() + " not supported yet.");
            }

            std::string stdFilename = QFileInfo(filename).absoluteFilePath().toStdString();
            if (reader) {
                reader->SetFileName(stdFilename.c_str());
                try {
                    reader->Update();
                }
                catch (...) {
                    throw AbortException("VTK was unable to read file " + stdFilename);
                }
                image = reader->GetOutput();
            }

            // Get the image orientation & rotation when possible
            ImageOrientationHelper::PossibleImageOrientations orientation = ImageOrientationHelper::RAI;
            vtkSmartPointer<vtkMatrix4x4> rotationMatrix;
            if (vtkSmartPointer<vtkMetaImageReader> metaImageReader = vtkMetaImageReader::SafeDownCast(reader)) {
                orientation = ImageOrientationHelper::getOrientationAsEnum(QString(metaImageReader->GetAnatomicalOrientation()));
                rotationMatrix = readMetaImageTransformMatrix(filename);
            }

            // set the image data, orientation and rotation matrix
            // note : the orientation is always displayed using RAI inside CamiTK
            // therefore the transformation from orientation to RAI is applied in setImageData
            // Inside the ImageComponent, initialImageDataTransform stores the transformation : [ translation ] * [ orientation -> RAI ]
            setImageData(image, false, orientation, rotationMatrix);

            image = nullptr;
            reader = nullptr;
        }

        catch (const AbortException& e) {
            throw (e);
        }
    }
}

// -------------------- readMetaImageTransformMatrix --------------------
vtkSmartPointer<vtkMatrix4x4> VtkImageComponent::readMetaImageTransformMatrix(const QString& fileName) {

    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        CAMITK_ERROR(tr("Cannot open file \"%1\" to read TransformMatrix tag from image").arg(fileName))
        return nullptr;
    }

    QRegularExpression regExp = QRegularExpression("TransformMatrix = ([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?[ |\\n])+");
    QTextStream in(&file);
    QString line = in.readLine();
    while (!line.isNull()) {
        // Find lind feature TransformMatrix tag information
        if (line.contains(regExp)) { // found it !
            // retrieve information
            QStringList values = line.split(" ");
            int nDim;

            if (values.size() >= 9 + 2) {
                // if the read matrix is 9 elements ( + "TransformMatrix" + "=") or more
                // manage it as a 3D matrix
                nDim = 3;
            }
            else {
                // else manage it as a 2D matrix
                nDim = 2;
            }

            // According to https://itk.org/Wiki/MetaIO/Documentation#Associated_transformations
            // "matrix that is serialized in a column-major format" -> fill column by column
            vtkSmartPointer<vtkMatrix4x4> rotationMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
            for (int j = 0; j < nDim; j++) { // lines
                for (int i = 0; i < nDim; i++) { // columns
                    rotationMatrix->SetElement(i, j, values.at(j * nDim + i + 2).toDouble());
                }
            }
            file.close();

            return rotationMatrix;
        }
        line = in.readLine();
    }

    file.close(); // close the file handle.
    return nullptr;
}