Line |
Branch |
Exec |
Source |
1 |
|
|
/************************************************************************ |
2 |
|
|
* |
3 |
|
|
* Copyright (C) 2009-2023 IRCAD France |
4 |
|
|
* Copyright (C) 2012-2018 IHU Strasbourg |
5 |
|
|
* |
6 |
|
|
* This file is part of Sight. |
7 |
|
|
* |
8 |
|
|
* Sight is free software: you can redistribute it and/or modify it under |
9 |
|
|
* the terms of the GNU Lesser General Public License as published by |
10 |
|
|
* the Free Software Foundation, either version 3 of the License, or |
11 |
|
|
* (at your option) any later version. |
12 |
|
|
* |
13 |
|
|
* Sight is distributed in the hope that it will be useful, |
14 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 |
|
|
* GNU Lesser General Public License for more details. |
17 |
|
|
* |
18 |
|
|
* You should have received a copy of the GNU Lesser General Public |
19 |
|
|
* License along with Sight. If not, see <https://www.gnu.org/licenses/>. |
20 |
|
|
* |
21 |
|
|
***********************************************************************/ |
22 |
|
|
|
23 |
|
|
#include "io/dicom/writer/tid/measurement.hpp" |
24 |
|
|
|
25 |
|
|
#include "io/dicom/container/dicom_coded_attribute.hpp" |
26 |
|
|
#include "io/dicom/container/sr/dicom_sr_code_node.hpp" |
27 |
|
|
#include "io/dicom/container/sr/dicom_sr_image_node.hpp" |
28 |
|
|
#include "io/dicom/container/sr/dicom_sr_num_node.hpp" |
29 |
|
|
#include "io/dicom/container/sr/dicom_sr_text_node.hpp" |
30 |
|
|
#include "io/dicom/container/sr/dicom_srs_coord3dnode.hpp" |
31 |
|
|
#include "io/dicom/container/sr/dicom_srs_coord_node.hpp" |
32 |
|
|
#include "io/dicom/container/sr/dicom_sruid_ref_node.hpp" |
33 |
|
|
#include "io/dicom/helper/dicom_data_tools.hpp" |
34 |
|
|
|
35 |
|
|
#include <data/helper/medical_image.hpp> |
36 |
|
|
#include <data/point_list.hpp> |
37 |
|
|
#include <data/series.hpp> |
38 |
|
|
#include <data/string.hpp> |
39 |
|
|
#include <data/types.hpp> |
40 |
|
|
#include <data/vector.hpp> |
41 |
|
|
|
42 |
|
|
#include <boost/algorithm/string/split.hpp> |
43 |
|
|
|
44 |
|
|
#include <sstream> |
45 |
|
|
|
46 |
|
|
namespace sight::io::dicom::writer::tid |
47 |
|
|
{ |
48 |
|
|
|
49 |
|
|
//------------------------------------------------------------------------------ |
50 |
|
|
|
51 |
|
✗ |
measurement::measurement( |
52 |
|
|
const SPTR(gdcm::Writer)& _writer, |
53 |
|
|
const SPTR(io::dicom::container::dicom_instance)& _instance, |
54 |
|
|
const data::image::csptr& _image |
55 |
|
✗ |
) : |
56 |
|
✗ |
io::dicom::writer::tid::template_id<data::image>(_writer, _instance, _image) |
57 |
|
|
{ |
58 |
|
|
} |
59 |
|
|
|
60 |
|
|
//------------------------------------------------------------------------------ |
61 |
|
|
|
62 |
|
✗ |
measurement::~measurement() |
63 |
|
|
= default; |
64 |
|
|
|
65 |
|
|
//------------------------------------------------------------------------------ |
66 |
|
|
|
67 |
|
✗ |
void measurement::create_nodes( |
68 |
|
|
const SPTR(io::dicom::container::sr::dicom_sr_node)& _parent, |
69 |
|
|
bool _use_s_coord_3d |
70 |
|
|
) |
71 |
|
|
{ |
72 |
|
✗ |
data::vector::sptr distance_vector = data::helper::medical_image::get_distances(*m_object); |
73 |
|
✗ |
if(distance_vector) |
74 |
|
|
{ |
75 |
|
✗ |
unsigned int id = 1; |
76 |
|
✗ |
for(const data::object::sptr& object : *distance_vector) |
77 |
|
|
{ |
78 |
|
✗ |
data::point_list::sptr point_list = std::dynamic_pointer_cast<data::point_list>(object); |
79 |
|
✗ |
if(point_list) |
80 |
|
|
{ |
81 |
|
✗ |
this->create_measurement(_parent, point_list, id++, _use_s_coord_3d); |
82 |
|
|
} |
83 |
|
|
} |
84 |
|
|
} |
85 |
|
|
} |
86 |
|
|
|
87 |
|
|
//------------------------------------------------------------------------------ |
88 |
|
|
|
89 |
|
✗ |
void measurement::create_measurement( |
90 |
|
|
const SPTR(io::dicom::container::sr::dicom_sr_node)& _parent, |
91 |
|
|
const data::point_list::csptr& _point_list, |
92 |
|
|
unsigned int /*id*/, |
93 |
|
|
bool _use_s_coord_3d |
94 |
|
|
) |
95 |
|
|
{ |
96 |
|
✗ |
const data::point::sptr point1 = _point_list->get_points()[0]; |
97 |
|
✗ |
const data::point::sptr point2 = _point_list->get_points()[1]; |
98 |
|
|
|
99 |
|
✗ |
std::array coordinates { |
100 |
|
✗ |
point1->get_coord()[0], |
101 |
|
✗ |
point1->get_coord()[1], |
102 |
|
✗ |
point1->get_coord()[2], |
103 |
|
✗ |
point2->get_coord()[0], |
104 |
|
✗ |
point2->get_coord()[1], |
105 |
|
✗ |
point2->get_coord()[2] |
106 |
|
✗ |
}; |
107 |
|
|
|
108 |
|
✗ |
const double distance = sqrt( |
109 |
|
✗ |
(coordinates[0] - coordinates[3]) * (coordinates[0] - coordinates[3]) |
110 |
|
✗ |
+ (coordinates[1] - coordinates[4]) * (coordinates[1] - coordinates[4]) |
111 |
|
✗ |
+ (coordinates[2] - coordinates[5]) * (coordinates[2] - coordinates[5]) |
112 |
|
✗ |
); |
113 |
|
|
|
114 |
|
|
// Retrieve Frame Numbers |
115 |
|
✗ |
const std::size_t frame_number1 = io::dicom::helper::dicom_data_tools::convert_point_to_frame_number( |
116 |
|
✗ |
m_object, |
117 |
|
|
point1 |
118 |
|
|
); |
119 |
|
|
|
120 |
|
|
// Create Measurement Node |
121 |
|
|
// cspell: ignore UCUM |
122 |
|
✗ |
SPTR(io::dicom::container::sr::dicom_sr_num_node) num_node = |
123 |
|
|
std::make_shared<io::dicom::container::sr::dicom_sr_num_node>( |
124 |
|
✗ |
io::dicom::container::dicom_coded_attribute("121206", "DCM", "Distance"), |
125 |
|
|
"CONTAINS", |
126 |
|
|
distance, |
127 |
|
✗ |
io::dicom::container::dicom_coded_attribute("mm", "UCUM", "millimeter", "1.4") |
128 |
|
✗ |
); |
129 |
|
✗ |
_parent->add_sub_node(num_node); |
130 |
|
|
|
131 |
|
✗ |
if(_use_s_coord_3d) |
132 |
|
|
{ |
133 |
|
|
// Create SCoord Node |
134 |
|
✗ |
std::vector<float> scoord_vector { |
135 |
|
✗ |
static_cast<float>(point1->get_coord()[0]), |
136 |
|
✗ |
static_cast<float>(point1->get_coord()[1]), |
137 |
|
✗ |
static_cast<float>(point1->get_coord()[2]), |
138 |
|
✗ |
static_cast<float>(point2->get_coord()[0]), |
139 |
|
✗ |
static_cast<float>(point2->get_coord()[1]), |
140 |
|
✗ |
static_cast<float>(point2->get_coord()[2]) |
141 |
|
✗ |
}; |
142 |
|
✗ |
SPTR(io::dicom::container::sr::dicom_srs_coord3_d_node) scoord_node = |
143 |
|
|
std::make_shared<io::dicom::container::sr::dicom_srs_coord3_d_node>( |
144 |
|
✗ |
io::dicom::container::dicom_coded_attribute("121230", "DCM", "Path"), |
145 |
|
|
"INFERRED FROM", |
146 |
|
|
"POLYLINE", |
147 |
|
|
scoord_vector, |
148 |
|
✗ |
m_instance->get_sop_instance_uid_container()[0] |
149 |
|
✗ |
); |
150 |
|
✗ |
num_node->add_sub_node(scoord_node); |
151 |
|
|
} |
152 |
|
|
else |
153 |
|
|
{ |
154 |
|
|
SIGHT_ASSERT( |
155 |
|
|
"Unable to save a 3D distance using a SCOORD object.", |
156 |
|
|
frame_number1 == io::dicom::helper::dicom_data_tools::convert_point_to_frame_number(m_object, point2) |
157 |
|
✗ |
); |
158 |
|
|
|
159 |
|
|
// Create SCoord Node |
160 |
|
✗ |
std::vector<float> scoord_vector { |
161 |
|
✗ |
static_cast<float>(point1->get_coord()[0]), |
162 |
|
✗ |
static_cast<float>(point1->get_coord()[1]), |
163 |
|
✗ |
static_cast<float>(point2->get_coord()[0]), |
164 |
|
✗ |
static_cast<float>(point2->get_coord()[1]) |
165 |
|
✗ |
}; |
166 |
|
✗ |
SPTR(io::dicom::container::sr::dicom_srs_coord_node) scoord_node = |
167 |
|
|
std::make_shared<io::dicom::container::sr::dicom_srs_coord_node>( |
168 |
|
✗ |
io::dicom::container::dicom_coded_attribute("121230", "DCM", "Path"), |
169 |
|
|
"INFERRED FROM", |
170 |
|
|
"POLYLINE", |
171 |
|
|
scoord_vector |
172 |
|
✗ |
); |
173 |
|
✗ |
num_node->add_sub_node(scoord_node); |
174 |
|
|
|
175 |
|
|
// Create Image Node |
176 |
|
✗ |
SPTR(io::dicom::container::sr::dicom_sr_image_node) image_node = |
177 |
|
|
std::make_shared<io::dicom::container::sr::dicom_sr_image_node>( |
178 |
|
✗ |
io::dicom::container::dicom_coded_attribute(), |
179 |
|
|
"SELECTED FROM", |
180 |
|
✗ |
m_instance->get_sop_class_uid(), |
181 |
|
✗ |
m_instance->get_sop_instance_uid_container()[frame_number1 - 1], |
182 |
|
✗ |
int(frame_number1) |
183 |
|
✗ |
); |
184 |
|
✗ |
scoord_node->add_sub_node(image_node); |
185 |
|
|
} |
186 |
|
|
} |
187 |
|
|
|
188 |
|
|
//------------------------------------------------------------------------------ |
189 |
|
|
|
190 |
|
|
} // namespace sight::io::dicom::writer::tid |
191 |
|
|
|