Mercurial > hg > orthanc-wsi
annotate Framework/Algorithms/PyramidReader.cpp @ 98:ff0ef01c332c
shared copyright with osimis
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 04 Jan 2017 16:43:25 +0100 |
parents | 7a3853d51c45 |
children | a51dee6a1515 |
rev | line source |
---|---|
0 | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
98
ff0ef01c332c
shared copyright with osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
59
diff
changeset
|
5 * Copyright (C) 2017 Osimis, Belgium |
0 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU Affero General Public License | |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 **/ | |
20 | |
21 | |
16
7a88c614be04
preparing for precompiled headers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
22 #include "../PrecompiledHeadersWSI.h" |
0 | 23 #include "PyramidReader.h" |
24 | |
25 #include "../ImageToolbox.h" | |
59
7a3853d51c45
Move "Framework/Orthanc/" as "Resources/Orthanc/"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
57
diff
changeset
|
26 #include "../../Resources/Orthanc/Core/Logging.h" |
7a3853d51c45
Move "Framework/Orthanc/" as "Resources/Orthanc/"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
57
diff
changeset
|
27 #include "../../Resources/Orthanc/Core/OrthancException.h" |
0 | 28 |
29 #include <cassert> | |
30 | |
31 namespace OrthancWSI | |
32 { | |
33 class PyramidReader::SourceTile : public boost::noncopyable | |
34 { | |
35 private: | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
36 PyramidReader& that_; |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
37 unsigned int tileX_; |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
38 unsigned int tileY_; |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
39 bool hasRawTile_; |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
40 std::string rawTile_; |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
41 ImageCompression rawTileCompression_; |
0 | 42 |
43 std::auto_ptr<Orthanc::ImageAccessor> decoded_; | |
44 | |
45 bool IsRepaintNeeded() const | |
46 { | |
47 return (that_.parameters_.IsRepaintBackground() && | |
48 ((tileX_ + 1) * that_.sourceTileWidth_ > that_.levelWidth_ || | |
49 (tileY_ + 1) * that_.sourceTileHeight_ > that_.levelHeight_)); | |
50 } | |
51 | |
52 void RepaintBackground() | |
53 { | |
54 assert(decoded_.get() != NULL); | |
55 LOG(INFO) << "Repainting background of tile (" | |
56 << tileX_ << "," << tileY_ << ") at level " << that_.level_; | |
57 | |
58 if ((tileY_ + 1) * that_.sourceTileHeight_ > that_.levelHeight_) | |
59 { | |
60 // Bottom overflow | |
61 assert(tileY_ * that_.sourceTileHeight_ < that_.levelHeight_); | |
62 | |
63 unsigned int bottom = that_.levelHeight_ - tileY_ * that_.sourceTileHeight_; | |
64 Orthanc::ImageAccessor a = decoded_->GetRegion(0, bottom, | |
65 that_.sourceTileWidth_, | |
66 that_.sourceTileHeight_ - bottom); | |
67 ImageToolbox::Set(a, | |
68 that_.parameters_.GetBackgroundColorRed(), | |
69 that_.parameters_.GetBackgroundColorGreen(), | |
70 that_.parameters_.GetBackgroundColorBlue()); | |
71 | |
72 } | |
73 | |
74 if ((tileX_ + 1) * that_.sourceTileWidth_ > that_.levelWidth_) | |
75 { | |
76 // Right overflow | |
77 assert(tileX_ * that_.sourceTileWidth_ < that_.levelWidth_); | |
78 | |
79 unsigned int right = that_.levelWidth_ - tileX_ * that_.sourceTileWidth_; | |
80 Orthanc::ImageAccessor a = decoded_->GetRegion(right, 0, | |
81 that_.sourceTileWidth_ - right, | |
82 that_.sourceTileHeight_); | |
83 ImageToolbox::Set(a, | |
84 that_.parameters_.GetBackgroundColorRed(), | |
85 that_.parameters_.GetBackgroundColorGreen(), | |
86 that_.parameters_.GetBackgroundColorBlue()); | |
87 } | |
88 } | |
89 | |
90 | |
91 public: | |
92 SourceTile(PyramidReader& that, | |
93 unsigned int tileX, | |
94 unsigned int tileY) : | |
95 that_(that), | |
96 tileX_(tileX), | |
97 tileY_(tileY) | |
98 { | |
99 if (!that_.parameters_.IsForceReencode() && | |
100 !IsRepaintNeeded() && | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
101 that_.source_.ReadRawTile(rawTile_, rawTileCompression_, that_.level_, tileX, tileY)) |
0 | 102 { |
103 hasRawTile_ = true; | |
104 } | |
105 else | |
106 { | |
107 hasRawTile_ = false; | |
108 decoded_.reset(that_.source_.DecodeTile(that_.level_, tileX, tileY)); | |
109 if (decoded_.get() == NULL) | |
110 { | |
111 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
112 } | |
113 | |
114 RepaintBackground(); | |
115 } | |
116 } | |
117 | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
118 bool HasRawTile(ImageCompression& compression) const |
0 | 119 { |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
120 if (hasRawTile_) |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
121 { |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
122 compression = rawTileCompression_; |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
123 return true; |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
124 } |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
125 else |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
126 { |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
127 return false; |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
128 } |
0 | 129 } |
130 | |
131 const std::string& GetRawTile() const | |
132 { | |
133 if (hasRawTile_) | |
134 { | |
135 return rawTile_; | |
136 } | |
137 else | |
138 { | |
139 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
140 } | |
141 } | |
142 | |
143 const Orthanc::ImageAccessor& GetDecodedTile() | |
144 { | |
145 if (decoded_.get() == NULL) | |
146 { | |
147 if (!hasRawTile_) | |
148 { | |
149 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
150 } | |
151 | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
152 decoded_.reset(ImageToolbox::DecodeTile(rawTile_, rawTileCompression_)); |
0 | 153 if (decoded_.get() == NULL) |
154 { | |
155 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
156 } | |
157 | |
158 RepaintBackground(); | |
159 } | |
160 | |
161 return *decoded_; | |
162 } | |
163 }; | |
164 | |
165 | |
166 Orthanc::ImageAccessor& PyramidReader::GetOutsideTile() | |
167 { | |
168 if (outside_.get() == NULL) | |
169 { | |
170 outside_.reset(ImageToolbox::Allocate(source_.GetPixelFormat(), targetTileWidth_, targetTileHeight_)); | |
171 ImageToolbox::Set(*outside_, | |
172 parameters_.GetBackgroundColorRed(), | |
173 parameters_.GetBackgroundColorGreen(), | |
174 parameters_.GetBackgroundColorBlue()); | |
175 } | |
176 | |
177 return *outside_; | |
178 } | |
179 | |
180 | |
181 void PyramidReader::CheckTileSize(const Orthanc::ImageAccessor& tile) const | |
182 { | |
183 if (tile.GetWidth() != sourceTileWidth_ || | |
184 tile.GetHeight() != sourceTileHeight_) | |
185 { | |
186 LOG(ERROR) << "One tile in the input image has size " << tile.GetWidth() << "x" << tile.GetHeight() | |
187 << " instead of required " << source_.GetTileWidth() << "x" << source_.GetTileHeight(); | |
188 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize); | |
189 } | |
190 } | |
191 | |
192 | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
193 void PyramidReader::CheckTileSize(const std::string& tile, |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
194 ImageCompression compression) const |
0 | 195 { |
196 if (parameters_.IsSafetyCheck()) | |
197 { | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
198 std::auto_ptr<Orthanc::ImageAccessor> decoded(ImageToolbox::DecodeTile(tile, compression)); |
0 | 199 CheckTileSize(*decoded); |
200 } | |
201 } | |
202 | |
203 | |
204 PyramidReader::SourceTile& PyramidReader::AccessSourceTile(const Location& location) | |
205 { | |
206 Cache::iterator found = cache_.find(location); | |
207 if (found != cache_.end()) | |
208 { | |
209 return *found->second; | |
210 } | |
211 else | |
212 { | |
213 SourceTile *tile = new SourceTile(*this, location.first, location.second); | |
214 cache_[location] = tile; | |
215 return *tile; | |
216 } | |
217 } | |
218 | |
219 | |
220 PyramidReader::Location PyramidReader::MapTargetToSourceLocation(unsigned int tileX, | |
221 unsigned int tileY) | |
222 { | |
223 return std::make_pair(tileX / (sourceTileWidth_ / targetTileWidth_), | |
224 tileY / (sourceTileHeight_ / targetTileHeight_)); | |
225 } | |
226 | |
227 | |
228 PyramidReader::PyramidReader(ITiledPyramid& source, | |
229 unsigned int level, | |
230 unsigned int targetTileWidth, | |
231 unsigned int targetTileHeight, | |
232 const DicomizerParameters& parameters) : | |
233 source_(source), | |
234 level_(level), | |
235 levelWidth_(source.GetLevelWidth(level)), | |
236 levelHeight_(source.GetLevelHeight(level)), | |
237 sourceTileWidth_(source.GetTileWidth()), | |
238 sourceTileHeight_(source.GetTileHeight()), | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
239 targetTileWidth_(targetTileWidth), |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
240 targetTileHeight_(targetTileHeight), |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
241 parameters_(parameters) |
0 | 242 { |
243 if (sourceTileWidth_ % targetTileWidth_ != 0 || | |
244 sourceTileHeight_ % targetTileHeight_ != 0) | |
245 { | |
246 LOG(ERROR) << "When resampling the tile size, it must be a integer divisor of the original tile size"; | |
247 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize); | |
248 } | |
249 } | |
250 | |
251 | |
252 PyramidReader::~PyramidReader() | |
253 { | |
254 for (Cache::iterator it = cache_.begin(); it != cache_.end(); ++it) | |
255 { | |
256 assert(it->second != NULL); | |
257 delete it->second; | |
258 } | |
259 } | |
260 | |
261 | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
262 const std::string* PyramidReader::GetRawTile(ImageCompression& compression, |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
263 unsigned int tileX, |
0 | 264 unsigned int tileY) |
265 { | |
266 if (sourceTileWidth_ != targetTileWidth_ || | |
267 sourceTileHeight_ != targetTileHeight_) | |
268 { | |
269 return NULL; | |
270 } | |
271 | |
272 SourceTile& source = AccessSourceTile(MapTargetToSourceLocation(tileX, tileY)); | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
273 |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
274 if (source.HasRawTile(compression)) |
0 | 275 { |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
16
diff
changeset
|
276 CheckTileSize(source.GetRawTile(), compression); |
0 | 277 return &source.GetRawTile(); |
278 } | |
279 else | |
280 { | |
281 return NULL; | |
282 } | |
283 } | |
284 | |
285 | |
286 Orthanc::ImageAccessor PyramidReader::GetDecodedTile(unsigned int tileX, | |
287 unsigned int tileY) | |
288 { | |
289 if (tileX * targetTileWidth_ >= levelWidth_ || | |
290 tileY * targetTileHeight_ >= levelHeight_) | |
291 { | |
292 // Accessing a tile out of the source image | |
293 return GetOutsideTile(); | |
294 } | |
295 | |
296 SourceTile& source = AccessSourceTile(MapTargetToSourceLocation(tileX, tileY)); | |
297 const Orthanc::ImageAccessor& tile = source.GetDecodedTile(); | |
298 | |
299 CheckTileSize(tile); | |
300 | |
301 assert(sourceTileWidth_ % targetTileWidth_ == 0 && | |
302 sourceTileHeight_ % targetTileHeight_ == 0); | |
303 | |
304 unsigned int xx = tileX % (sourceTileWidth_ / targetTileWidth_); | |
305 unsigned int yy = tileY % (sourceTileHeight_ / targetTileHeight_); | |
306 | |
307 const uint8_t* bytes = | |
308 reinterpret_cast<const uint8_t*>(tile.GetConstRow(yy * targetTileHeight_)) + | |
309 GetBytesPerPixel(tile.GetFormat()) * xx * targetTileWidth_; | |
310 | |
311 Orthanc::ImageAccessor region; | |
312 region.AssignReadOnly(tile.GetFormat(), | |
313 targetTileWidth_, | |
314 targetTileHeight_, | |
315 tile.GetPitch(), bytes); | |
316 | |
317 return region; | |
318 } | |
319 } |