comparison Framework/Inputs/DicomPyramid.cpp @ 0:4a7a53257c7d

initial commit
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sat, 22 Oct 2016 21:48:33 +0200
parents
children 7a88c614be04
comparison
equal deleted inserted replaced
-1:000000000000 0:4a7a53257c7d
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 *
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU Affero General Public License
8 * as published by the Free Software Foundation, either version 3 of
9 * the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 **/
19
20
21 #include "DicomPyramid.h"
22
23 #include "../DicomToolbox.h"
24 #include "../Orthanc/Core/Logging.h"
25 #include "../Orthanc/Core/OrthancException.h"
26
27 #include <algorithm>
28 #include <cassert>
29
30 namespace OrthancWSI
31 {
32 struct DicomPyramid::Comparator
33 {
34 bool operator() (DicomPyramidInstance* const& a,
35 DicomPyramidInstance* const& b) const
36 {
37 return a->GetTotalWidth() > b->GetTotalWidth();
38 }
39 };
40
41
42 void DicomPyramid::Clear()
43 {
44 for (size_t i = 0; i < levels_.size(); i++)
45 {
46 if (levels_[i] != NULL)
47 {
48 delete levels_[i];
49 }
50 }
51
52 for (size_t i = 0; i < instances_.size(); i++)
53 {
54 if (instances_[i] != NULL)
55 {
56 delete instances_[i];
57 }
58 }
59 }
60
61
62 void DicomPyramid::RegisterInstances(const std::string& seriesId)
63 {
64 Json::Value series;
65 IOrthancConnection::RestApiGet(series, orthanc_, "/series/" + seriesId);
66
67 if (series.type() != Json::objectValue)
68 {
69 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
70 }
71
72 const Json::Value& instances = DicomToolbox::GetSequenceTag(series, "Instances");
73 instances_.reserve(instances.size());
74
75 for (Json::Value::ArrayIndex i = 0; i < instances.size(); i++)
76 {
77 if (instances[i].type() != Json::stringValue)
78 {
79 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
80 }
81
82 std::string instance = instances[i].asString();
83
84 try
85 {
86 instances_.push_back(new DicomPyramidInstance(orthanc_, instance));
87 }
88 catch (Orthanc::OrthancException&)
89 {
90 LOG(ERROR) << "Skipping a DICOM instance that is not part of a whole-slide image: " << instance;
91 }
92 }
93 }
94
95
96 void DicomPyramid::Check(const std::string& seriesId) const
97 {
98 if (instances_.empty())
99 {
100 LOG(ERROR) << "This series does not contain a whole-slide image: " << seriesId;
101 throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource);
102 }
103
104 const DicomPyramidInstance& a = *instances_[0];
105
106 for (size_t i = 1; i < instances_.size(); i++)
107 {
108 const DicomPyramidInstance& b = *instances_[i];
109
110 if (a.GetImageCompression() != b.GetImageCompression() ||
111 a.GetPixelFormat() != b.GetPixelFormat() ||
112 a.GetTileWidth() != b.GetTileWidth() ||
113 a.GetTileHeight() != b.GetTileHeight() ||
114 a.GetTotalWidth() < b.GetTotalWidth() ||
115 a.GetTotalHeight() < b.GetTotalHeight())
116 {
117 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
118 }
119
120 if (a.GetTotalWidth() == b.GetTotalWidth() &&
121 a.GetTotalHeight() != b.GetTotalHeight())
122 {
123 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
124 }
125 }
126 }
127
128
129 void DicomPyramid::CheckLevel(size_t level) const
130 {
131 if (level >= levels_.size())
132 {
133 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
134 }
135 }
136
137
138 DicomPyramid::DicomPyramid(IOrthancConnection& orthanc,
139 const std::string& seriesId) :
140 orthanc_(orthanc),
141 seriesId_(seriesId)
142 {
143 RegisterInstances(seriesId);
144
145 // Sort the instances of the pyramid by decreasing total widths
146 std::sort(instances_.begin(), instances_.end(), Comparator());
147
148 try
149 {
150 Check(seriesId);
151 }
152 catch (Orthanc::OrthancException&)
153 {
154 Clear();
155 throw;
156 }
157
158 for (size_t i = 0; i < instances_.size(); i++)
159 {
160 if (i == 0 ||
161 instances_[i - 1]->GetTotalWidth() != instances_[i]->GetTotalWidth())
162 {
163 levels_.push_back(new DicomPyramidLevel(*instances_[i]));
164 }
165 else
166 {
167 assert(levels_.back() != NULL);
168 levels_.back()->AddInstance(*instances_[i]);
169 }
170 }
171 }
172
173
174 unsigned int DicomPyramid::GetLevelWidth(unsigned int level) const
175 {
176 CheckLevel(level);
177 return levels_[level]->GetTotalWidth();
178 }
179
180
181 unsigned int DicomPyramid::GetLevelHeight(unsigned int level) const
182 {
183 CheckLevel(level);
184 return levels_[level]->GetTotalHeight();
185 }
186
187
188 unsigned int DicomPyramid::GetTileWidth() const
189 {
190 assert(!levels_.empty() && levels_[0] != NULL);
191 return levels_[0]->GetTileWidth();
192 }
193
194
195 unsigned int DicomPyramid::GetTileHeight() const
196 {
197 assert(!levels_.empty() && levels_[0] != NULL);
198 return levels_[0]->GetTileHeight();
199 }
200
201
202 bool DicomPyramid::ReadRawTile(std::string& tile,
203 unsigned int level,
204 unsigned int tileX,
205 unsigned int tileY)
206 {
207 CheckLevel(level);
208
209 ImageCompression compression;
210 Orthanc::PixelFormat format;
211
212 if (levels_[level]->DownloadRawTile(compression, format, tile, orthanc_, tileX, tileY))
213 {
214 assert(compression == GetImageCompression() &&
215 format == GetPixelFormat());
216 return true;
217 }
218 else
219 {
220 return false;
221 }
222 }
223
224
225 ImageCompression DicomPyramid::GetImageCompression() const
226 {
227 assert(!instances_.empty() && instances_[0] != NULL);
228 return instances_[0]->GetImageCompression();
229 }
230
231
232 Orthanc::PixelFormat DicomPyramid::GetPixelFormat() const
233 {
234 assert(!instances_.empty() && instances_[0] != NULL);
235 return instances_[0]->GetPixelFormat();
236 }
237 }