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
|
|
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 "ReconstructPyramidCommand.h"
|
|
22
|
|
23 #include "../ImageToolbox.h"
|
|
24 #include "../Orthanc/Core/Logging.h"
|
|
25 #include "../Orthanc/Core/OrthancException.h"
|
|
26 #include "../Orthanc/Core/Images/Image.h"
|
|
27
|
|
28 #include <cassert>
|
|
29
|
|
30 namespace OrthancWSI
|
|
31 {
|
|
32 Orthanc::ImageAccessor* ReconstructPyramidCommand::Explore(unsigned int level,
|
|
33 unsigned int offsetX,
|
|
34 unsigned int offsetY)
|
|
35 {
|
|
36 unsigned int zoom = 1 << level;
|
|
37 assert(x_ % zoom == 0 && y_ % zoom == 0);
|
|
38 unsigned int x = x_ / zoom + offsetX;
|
|
39 unsigned int y = y_ / zoom + offsetY;
|
|
40
|
|
41 if (x >= target_.GetCountTilesX(level + shiftTargetLevel_) ||
|
|
42 y >= target_.GetCountTilesY(level + shiftTargetLevel_))
|
|
43 {
|
|
44 return NULL;
|
|
45 }
|
|
46
|
|
47 std::auto_ptr<Orthanc::ImageAccessor> result;
|
|
48
|
|
49 if (level == 0)
|
|
50 {
|
|
51 result.reset(new Orthanc::ImageAccessor(source_.GetDecodedTile(x, y)));
|
|
52
|
|
53 const std::string* rawTile = source_.GetRawTile(x, y);
|
|
54
|
|
55 if (rawTile != NULL)
|
|
56 {
|
|
57 // Simple transcoding
|
|
58 target_.WriteRawTile(*rawTile, source_.GetImageCompression(), level + shiftTargetLevel_, x, y);
|
|
59 }
|
|
60 else
|
|
61 {
|
|
62 // Re-encoding the file
|
|
63 target_.EncodeTile(*result, level + shiftTargetLevel_, x, y);
|
|
64 }
|
|
65 }
|
|
66 else
|
|
67 {
|
|
68 std::auto_ptr<Orthanc::ImageAccessor> mosaic(ImageToolbox::Allocate(source_.GetPixelFormat(),
|
|
69 2 * target_.GetTileWidth(),
|
|
70 2 * target_.GetTileHeight()));
|
|
71 ImageToolbox::Set(*mosaic,
|
|
72 source_.GetParameters().GetBackgroundColorRed(),
|
|
73 source_.GetParameters().GetBackgroundColorGreen(),
|
|
74 source_.GetParameters().GetBackgroundColorBlue());
|
|
75
|
|
76 {
|
|
77 std::auto_ptr<Orthanc::ImageAccessor> subTile(Explore(level - 1, 2 * offsetX, 2 * offsetY));
|
|
78 if (subTile.get() != NULL)
|
|
79 {
|
|
80 ImageToolbox::Embed(*mosaic, *subTile, 0, 0);
|
|
81 }
|
|
82 }
|
|
83
|
|
84 {
|
|
85 std::auto_ptr<Orthanc::ImageAccessor> subTile(Explore(level - 1, 2 * offsetX + 1, 2 * offsetY));
|
|
86 if (subTile.get() != NULL)
|
|
87 {
|
|
88 ImageToolbox::Embed(*mosaic, *subTile, target_.GetTileWidth(), 0);
|
|
89 }
|
|
90 }
|
|
91
|
|
92 {
|
|
93 std::auto_ptr<Orthanc::ImageAccessor> subTile(Explore(level - 1, 2 * offsetX, 2 * offsetY + 1));
|
|
94 if (subTile.get() != NULL)
|
|
95 {
|
|
96 ImageToolbox::Embed(*mosaic, *subTile, 0, target_.GetTileHeight());
|
|
97 }
|
|
98 }
|
|
99
|
|
100 {
|
|
101 std::auto_ptr<Orthanc::ImageAccessor> subTile(Explore(level - 1, 2 * offsetX + 1, 2 * offsetY + 1));
|
|
102 if (subTile.get() != NULL)
|
|
103 {
|
|
104 ImageToolbox::Embed(*mosaic, *subTile, target_.GetTileWidth(), target_.GetTileHeight());
|
|
105 }
|
|
106 }
|
|
107
|
|
108 result.reset(ImageToolbox::Halve(*mosaic, source_.GetParameters().IsSmoothEnabled()));
|
|
109
|
|
110 target_.EncodeTile(*result, level + shiftTargetLevel_, x, y);
|
|
111 }
|
|
112
|
|
113 return result.release();
|
|
114 }
|
|
115
|
|
116
|
|
117 ReconstructPyramidCommand::ReconstructPyramidCommand(IPyramidWriter& target,
|
|
118 ITiledPyramid& source,
|
|
119 unsigned int upToLevel,
|
|
120 unsigned int x,
|
|
121 unsigned int y,
|
|
122 const DicomizerParameters& parameters) :
|
|
123 target_(target),
|
|
124 source_(source, 0, target.GetTileWidth(), target.GetTileHeight(), parameters),
|
|
125 upToLevel_(upToLevel),
|
|
126 x_(x),
|
|
127 y_(y),
|
|
128 shiftTargetLevel_(0)
|
|
129 {
|
|
130 unsigned int zoom = 1 << upToLevel;
|
|
131 if (x % zoom != 0 ||
|
|
132 y % zoom != 0)
|
|
133 {
|
|
134 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
|
|
135 }
|
|
136
|
|
137 if (target.GetPixelFormat() != source.GetPixelFormat())
|
|
138 {
|
|
139 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
|
|
140 }
|
|
141 }
|
|
142
|
|
143
|
|
144 bool ReconstructPyramidCommand::Execute()
|
|
145 {
|
|
146 std::auto_ptr<Orthanc::ImageAccessor> root(Explore(upToLevel_, 0, 0));
|
|
147 return true;
|
|
148 }
|
|
149
|
|
150
|
|
151 void ReconstructPyramidCommand::PrepareBagOfTasks(Orthanc::BagOfTasks& tasks,
|
|
152 IPyramidWriter& target,
|
|
153 ITiledPyramid& source,
|
|
154 unsigned int countLevels,
|
|
155 unsigned int shiftTargetLevel,
|
|
156 const DicomizerParameters& parameters)
|
|
157 {
|
|
158 if (countLevels == 0)
|
|
159 {
|
|
160 return;
|
|
161 }
|
|
162
|
|
163 if (shiftTargetLevel + countLevels > target.GetLevelCount())
|
|
164 {
|
|
165 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
|
|
166 }
|
|
167
|
|
168 const unsigned int targetCountTilesX = target.GetCountTilesX(shiftTargetLevel);
|
|
169 const unsigned int targetCountTilesY = target.GetCountTilesY(shiftTargetLevel);
|
|
170 const unsigned int step = 1 << (countLevels - 1);
|
|
171
|
|
172 for (unsigned int y = 0; y < targetCountTilesY; y += step)
|
|
173 {
|
|
174 for (unsigned int x = 0; x < targetCountTilesX; x += step)
|
|
175 {
|
|
176 std::auto_ptr<ReconstructPyramidCommand> command;
|
|
177 command.reset(new ReconstructPyramidCommand
|
|
178 (target, source, countLevels - 1, x, y, parameters));
|
|
179 command->SetShiftTargetLevel(shiftTargetLevel);
|
|
180 tasks.Push(command.release());
|
|
181 }
|
|
182 }
|
|
183 }
|
|
184 }
|