comparison UnitTestsSources/UnitTestsMain.cpp @ 102:fcec0ab44054 wasm

display volumes
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 31 May 2017 17:01:18 +0200
parents 5945e81734a3
children 2eca030792aa
comparison
equal deleted inserted replaced
101:af312ce4fe59 102:fcec0ab44054
17 * You should have received a copy of the GNU Affero General Public License 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/>. 18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/ 19 **/
20 20
21 21
22 #include "../Framework/dev.h"
22 #include "gtest/gtest.h" 23 #include "gtest/gtest.h"
23 24
24 #include "../Platforms/Generic/OracleWebService.h" 25 #include "../Platforms/Generic/OracleWebService.h"
25 #include "../Framework/Toolbox/OrthancSlicesLoader.h" 26 #include "../Framework/Toolbox/OrthancSlicesLoader.h"
26 #include "../Resources/Orthanc/Core/HttpClient.h" 27 #include "../Resources/Orthanc/Core/HttpClient.h"
29 #include "../Resources/Orthanc/Core/OrthancException.h" 30 #include "../Resources/Orthanc/Core/OrthancException.h"
30 31
31 #include "../Framework/Volumes/ImageBuffer3D.h" 32 #include "../Framework/Volumes/ImageBuffer3D.h"
32 #include "../Framework/Volumes/SlicedVolumeBase.h" 33 #include "../Framework/Volumes/SlicedVolumeBase.h"
33 #include "../Framework/Toolbox/DownloadStack.h" 34 #include "../Framework/Toolbox/DownloadStack.h"
35 #include "../Framework/Layers/LayerSourceBase.h"
36 #include "../Framework/Layers/FrameRenderer.h"
34 #include "../Resources/Orthanc/Core/Images/ImageProcessing.h" 37 #include "../Resources/Orthanc/Core/Images/ImageProcessing.h"
35 38
36 #include <boost/lexical_cast.hpp> 39 #include <boost/lexical_cast.hpp>
37 #include <boost/date_time/posix_time/posix_time.hpp> 40 #include <boost/date_time/posix_time/posix_time.hpp>
38 #include <boost/thread/thread.hpp> 41 #include <boost/thread/thread.hpp>
42 #include <boost/math/special_functions/round.hpp>
43
39 44
40 namespace OrthancStone 45 namespace OrthancStone
41 { 46 {
42 class Tata : public OrthancSlicesLoader::ICallback 47 class Tata : public OrthancSlicesLoader::ICallback
43 { 48 {
58 } 63 }
59 64
60 virtual void NotifySliceImageReady(const OrthancSlicesLoader& loader, 65 virtual void NotifySliceImageReady(const OrthancSlicesLoader& loader,
61 unsigned int sliceIndex, 66 unsigned int sliceIndex,
62 const Slice& slice, 67 const Slice& slice,
63 Orthanc::ImageAccessor* image, 68 std::auto_ptr<Orthanc::ImageAccessor>& image,
64 SliceImageQuality quality) 69 SliceImageQuality quality)
65 { 70 {
66 std::auto_ptr<Orthanc::ImageAccessor> tmp(image); 71 std::auto_ptr<Orthanc::ImageAccessor> tmp(image);
67 printf("Slice OK %dx%d\n", tmp->GetWidth(), tmp->GetHeight()); 72 printf("Slice OK %dx%d\n", tmp->GetWidth(), tmp->GetHeight());
68 } 73 }
71 unsigned int sliceIndex, 76 unsigned int sliceIndex,
72 const Slice& slice, 77 const Slice& slice,
73 SliceImageQuality quality) 78 SliceImageQuality quality)
74 { 79 {
75 printf("ERROR 2\n"); 80 printf("ERROR 2\n");
76 }
77 };
78
79
80 class OrthancVolumeImage :
81 public SlicedVolumeBase,
82 private OrthancSlicesLoader::ICallback
83 {
84 private:
85 OrthancSlicesLoader loader_;
86 std::auto_ptr<ImageBuffer3D> image_;
87 std::auto_ptr<DownloadStack> downloadStack_;
88
89
90 void ScheduleSliceDownload()
91 {
92 assert(downloadStack_.get() != NULL);
93
94 unsigned int slice;
95 if (downloadStack_->Pop(slice))
96 {
97 loader_.ScheduleLoadSliceImage(slice, SliceImageQuality_Full);
98 }
99 }
100
101
102 static bool IsCompatible(const Slice& a,
103 const Slice& b)
104 {
105 if (!GeometryToolbox::IsParallel(a.GetGeometry().GetNormal(),
106 b.GetGeometry().GetNormal()))
107 {
108 LOG(ERROR) << "Some slice in the volume image is not parallel to the others";
109 return false;
110 }
111
112 if (a.GetConverter().GetExpectedPixelFormat() != b.GetConverter().GetExpectedPixelFormat())
113 {
114 LOG(ERROR) << "The pixel format changes across the slices of the volume image";
115 return false;
116 }
117
118 if (a.GetWidth() != b.GetWidth() ||
119 a.GetHeight() != b.GetHeight())
120 {
121 LOG(ERROR) << "The width/height of the slices change across the volume image";
122 return false;
123 }
124
125 if (!GeometryToolbox::IsNear(a.GetPixelSpacingX(), b.GetPixelSpacingX()) ||
126 !GeometryToolbox::IsNear(a.GetPixelSpacingY(), b.GetPixelSpacingY()))
127 {
128 LOG(ERROR) << "The pixel spacing of the slices change across the volume image";
129 return false;
130 }
131
132 return true;
133 }
134
135
136 static double GetDistance(const Slice& a,
137 const Slice& b)
138 {
139 return fabs(a.GetGeometry().ProjectAlongNormal(a.GetGeometry().GetOrigin()) -
140 a.GetGeometry().ProjectAlongNormal(b.GetGeometry().GetOrigin()));
141 }
142
143
144 virtual void NotifyGeometryReady(const OrthancSlicesLoader& loader)
145 {
146 if (loader.GetSliceCount() == 0)
147 {
148 LOG(ERROR) << "Empty volume image";
149 SlicedVolumeBase::NotifyGeometryError();
150 return;
151 }
152
153 for (size_t i = 1; i < loader.GetSliceCount(); i++)
154 {
155 if (!IsCompatible(loader.GetSlice(0), loader.GetSlice(i)))
156 {
157 SlicedVolumeBase::NotifyGeometryError();
158 return;
159 }
160 }
161
162 double spacingZ;
163
164 if (loader.GetSliceCount() > 1)
165 {
166 spacingZ = GetDistance(loader.GetSlice(0), loader.GetSlice(1));
167 }
168 else
169 {
170 // This is a volume with one single slice: Choose a dummy
171 // z-dimension for voxels
172 spacingZ = 1;
173 }
174
175 for (size_t i = 1; i < loader.GetSliceCount(); i++)
176 {
177 printf("%d %s %f\n", i, loader.GetSlice(i).GetOrthancInstanceId().c_str(),
178 GetDistance(loader.GetSlice(i - 1), loader.GetSlice(i)));
179
180 if (!GeometryToolbox::IsNear(spacingZ, GetDistance(loader.GetSlice(i - 1), loader.GetSlice(i)),
181 0.001 /* this is expressed in mm */))
182 {
183 LOG(ERROR) << "The distance between successive slices is not constant in a volume image";
184 SlicedVolumeBase::NotifyGeometryError();
185 return;
186 }
187 }
188
189 unsigned int width = loader.GetSlice(0).GetWidth();
190 unsigned int height = loader.GetSlice(0).GetHeight();
191 Orthanc::PixelFormat format = loader.GetSlice(0).GetConverter().GetExpectedPixelFormat();
192 LOG(INFO) << "Creating a volume image of size " << width << "x" << height
193 << "x" << loader.GetSliceCount() << " in " << Orthanc::EnumerationToString(format);
194
195 image_.reset(new ImageBuffer3D(format, width, height, loader.GetSliceCount()));
196 image_->SetAxialGeometry(loader.GetSlice(0).GetGeometry());
197 image_->SetVoxelDimensions(loader.GetSlice(0).GetPixelSpacingX(),
198 loader.GetSlice(0).GetPixelSpacingY(), spacingZ);
199 image_->Clear();
200
201 downloadStack_.reset(new DownloadStack(loader.GetSliceCount()));
202
203 SlicedVolumeBase::NotifyGeometryReady();
204
205 for (unsigned int i = 0; i < 4; i++) // Limit to 4 simultaneous downloads
206 {
207 ScheduleSliceDownload();
208 }
209 }
210
211 virtual void NotifyGeometryError(const OrthancSlicesLoader& loader)
212 {
213 LOG(ERROR) << "Unable to download a volume image";
214 }
215
216 virtual void NotifySliceImageReady(const OrthancSlicesLoader& loader,
217 unsigned int sliceIndex,
218 const Slice& slice,
219 Orthanc::ImageAccessor* image,
220 SliceImageQuality quality)
221 {
222 std::auto_ptr<Orthanc::ImageAccessor> protection(image);
223
224 {
225 ImageBuffer3D::SliceWriter writer(*image_, VolumeProjection_Axial, sliceIndex);
226 Orthanc::ImageProcessing::Copy(writer.GetAccessor(), *protection);
227 }
228
229 SlicedVolumeBase::NotifySliceChange(sliceIndex, slice);
230
231 ScheduleSliceDownload();
232 }
233
234 virtual void NotifySliceImageError(const OrthancSlicesLoader& loader,
235 unsigned int sliceIndex,
236 const Slice& slice,
237 SliceImageQuality quality)
238 {
239 LOG(ERROR) << "Cannot download slice " << sliceIndex << " in a volume image";
240 ScheduleSliceDownload();
241 }
242
243 public:
244 OrthancVolumeImage(IWebService& orthanc) :
245 loader_(*this, orthanc)
246 {
247 }
248
249 void ScheduleLoadSeries(const std::string& seriesId)
250 {
251 loader_.ScheduleLoadSeries(seriesId);
252 }
253
254 void ScheduleLoadInstance(const std::string& instanceId,
255 unsigned int frame)
256 {
257 loader_.ScheduleLoadInstance(instanceId, frame);
258 }
259
260 virtual size_t GetSliceCount() const
261 {
262 return loader_.GetSliceCount();
263 }
264
265 virtual const Slice& GetSlice(size_t index) const
266 {
267 return loader_.GetSlice(index);
268 }
269
270 ImageBuffer3D& GetImage()
271 {
272 if (image_.get() == NULL)
273 {
274 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
275 }
276 else
277 {
278 return *image_;
279 }
280 } 81 }
281 }; 82 };
282 } 83 }
283 84
284 85