comparison Framework/Volumes/VolumeImageProgressivePolicy.cpp @ 0:351ab0da0150

initial commit
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 14 Oct 2016 15:34:11 +0200
parents
children ff1e935768e7
comparison
equal deleted inserted replaced
-1:000000000000 0:351ab0da0150
1 /**
2 * Stone of Orthanc
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 General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * In addition, as a special exception, the copyright holders of this
12 * program give permission to link the code of its release with the
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it
14 * that use the same license as the "OpenSSL" library), and distribute
15 * the linked executables. You must obey the GNU General Public License
16 * in all respects for all of the code used other than "OpenSSL". If you
17 * modify file(s) with this exception, you may extend this exception to
18 * your version of the file(s), but you are not obligated to do so. If
19 * you do not wish to do so, delete this exception statement from your
20 * version. If you delete this exception statement from all source files
21 * in the program, then also delete it here.
22 *
23 * This program is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 **/
31
32
33 #include "VolumeImageProgressivePolicy.h"
34
35 #include "../Toolbox/DownloadStack.h"
36 #include "../Orthanc/Core/Images/ImageProcessing.h"
37
38 namespace OrthancStone
39 {
40 class VolumeImageProgressivePolicy::AxialSlicesScheduler
41 {
42 private:
43 size_t depth_;
44 DownloadStack stack_;
45
46 public:
47 AxialSlicesScheduler(size_t depth) :
48 depth_(depth),
49 stack_(3 * depth) // "3" stands for the number of quality levels
50 {
51 assert(depth > 0);
52 }
53
54 void TagFullPriority(int z,
55 int neighborhood)
56 {
57 DownloadStack::Writer writer(stack_);
58
59 // Also schedule the neighboring slices for download in medium quality
60 for (int offset = neighborhood; offset >= 1; offset--)
61 {
62 writer.SetTopNodePermissive((z + offset) + depth_ * Quality_Medium);
63 writer.SetTopNodePermissive((z - offset) + depth_ * Quality_Medium);
64 }
65
66 writer.SetTopNodePermissive(z + depth_ * Quality_Full);
67 }
68
69 bool LookupSlice(unsigned int& z,
70 Quality& quality)
71 {
72 unsigned int value;
73 if (stack_.Pop(value))
74 {
75 z = value % depth_;
76
77 switch (value / depth_)
78 {
79 case 0:
80 quality = Quality_Low;
81 break;
82
83 case 1:
84 quality = Quality_Medium;
85 break;
86
87 case 2:
88 quality = Quality_Full;
89 break;
90
91 default:
92 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
93 }
94
95 return true;
96 }
97 else
98 {
99 return false;
100 }
101 }
102 };
103
104
105 bool VolumeImageProgressivePolicy::IsComplete()
106 {
107 boost::mutex::scoped_lock lock(qualityMutex_);
108
109 for (size_t i = 0; i < axialSlicesQuality_.size(); i++)
110 {
111 if (axialSlicesQuality_[i] != Quality_Full)
112 {
113 return false;
114 }
115 }
116
117 return true;
118 }
119
120
121 void VolumeImageProgressivePolicy::InitializeInternal(ImageBuffer3D& buffer,
122 ISeriesLoader& loader)
123 {
124 const size_t depth = loader.GetGeometry().GetSliceCount();
125
126 isJpegAvailable_ = loader.IsJpegAvailable();
127
128 axialSlicesQuality_.clear();
129 axialSlicesQuality_.resize(depth, Quality_None);
130 scheduler_.reset(new AxialSlicesScheduler(depth));
131 }
132
133
134 bool VolumeImageProgressivePolicy::DownloadStepInternal(bool& complete,
135 ImageBuffer3D& buffer,
136 ISeriesLoader& loader)
137 {
138 unsigned int z;
139 Quality quality;
140
141 if (!scheduler_->LookupSlice(z, quality))
142 {
143 // There is no more frame to be downloaded. Before stopping,
144 // each loader thread checks whether all the frames have been
145 // downloaded at maximum quality.
146 complete = IsComplete();
147 return true;
148 }
149
150 if (quality != Quality_Full &&
151 !isJpegAvailable_)
152 {
153 // Cannot fulfill this command, as progressive JPEG download
154 // is unavailable (i.e. the Web viewer plugin is unavailable)
155 return false;
156 }
157
158 std::auto_ptr<Orthanc::ImageAccessor> frame;
159
160 try
161 {
162 switch (quality)
163 {
164 case Quality_Low:
165 frame.reset(loader.DownloadJpegFrame(z, 10));
166 break;
167
168 case Quality_Medium:
169 frame.reset(loader.DownloadJpegFrame(z, 90));
170 break;
171
172 case Quality_Full:
173 frame.reset(loader.DownloadFrame(z));
174 break;
175
176 default:
177 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
178 }
179 }
180 catch (Orthanc::OrthancException&)
181 {
182 // The Orthanc server cannot decode this instance
183 return false;
184 }
185
186 if (frame.get() != NULL)
187 {
188 boost::mutex::scoped_lock lock(qualityMutex_);
189
190 if (axialSlicesQuality_[z] == Quality_None ||
191 axialSlicesQuality_[z] < quality)
192 {
193 axialSlicesQuality_[z] = quality;
194
195 ImageBuffer3D::SliceWriter writer(buffer, VolumeProjection_Axial, z);
196 Orthanc::ImageProcessing::Convert(writer.GetAccessor(), *frame);
197 }
198 }
199
200 return false;
201 }
202
203
204 bool VolumeImageProgressivePolicy::IsFullQualityAxial(size_t slice)
205 {
206 scheduler_->TagFullPriority(slice, 3);
207
208 {
209 boost::mutex::scoped_lock lock(qualityMutex_);
210 return (axialSlicesQuality_[slice] == Quality_Full);
211 }
212 }
213 }