Mercurial > hg > orthanc-stone
comparison Samples/Sdl/Loader.cpp @ 782:b24c208fa953
VolumeImageReslicer
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 27 May 2019 14:21:04 +0200 |
parents | 2bb72826fa3f |
children | cd13a062c9bd |
comparison
equal
deleted
inserted
replaced
781:2bb72826fa3f | 782:b24c208fa953 |
---|---|
65 { | 65 { |
66 } | 66 } |
67 | 67 |
68 virtual uint64_t GetRevision() const = 0; | 68 virtual uint64_t GetRevision() const = 0; |
69 | 69 |
70 virtual ISceneLayer* CreateFromImage(const Orthanc::ImageAccessor& image) const = 0; | 70 virtual TextureBaseSceneLayer* CreateTextureFromImage(const Orthanc::ImageAccessor& image) const = 0; |
71 | 71 |
72 virtual ISceneLayer* CreateFromDicomImage(const Orthanc::ImageAccessor& frame, | 72 virtual TextureBaseSceneLayer* CreateTextureFromDicom(const Orthanc::ImageAccessor& frame, |
73 const DicomInstanceParameters& parameters) const = 0; | 73 const DicomInstanceParameters& parameters) const = 0; |
74 | 74 |
75 virtual void ApplyStyle(ISceneLayer& layer) const = 0; | 75 virtual void ApplyStyle(ISceneLayer& layer) const = 0; |
76 }; | 76 }; |
77 | 77 |
78 | 78 |
125 virtual uint64_t GetRevision() const | 125 virtual uint64_t GetRevision() const |
126 { | 126 { |
127 return revision_; | 127 return revision_; |
128 } | 128 } |
129 | 129 |
130 virtual ISceneLayer* CreateFromImage(const Orthanc::ImageAccessor& image) const | 130 virtual TextureBaseSceneLayer* CreateTextureFromImage(const Orthanc::ImageAccessor& image) const |
131 { | 131 { |
132 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | 132 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); |
133 } | 133 } |
134 | 134 |
135 virtual ISceneLayer* CreateFromDicomImage(const Orthanc::ImageAccessor& frame, | 135 virtual TextureBaseSceneLayer* CreateTextureFromDicom(const Orthanc::ImageAccessor& frame, |
136 const DicomInstanceParameters& parameters) const | 136 const DicomInstanceParameters& parameters) const |
137 { | 137 { |
138 return parameters.CreateLookupTableTexture(frame); | 138 return parameters.CreateLookupTableTexture(frame); |
139 } | 139 } |
140 | 140 |
141 virtual void ApplyStyle(ISceneLayer& layer) const | 141 virtual void ApplyStyle(ISceneLayer& layer) const |
173 virtual uint64_t GetRevision() const | 173 virtual uint64_t GetRevision() const |
174 { | 174 { |
175 return revision_; | 175 return revision_; |
176 } | 176 } |
177 | 177 |
178 virtual ISceneLayer* CreateFromImage(const Orthanc::ImageAccessor& image) const | 178 virtual TextureBaseSceneLayer* CreateTextureFromImage(const Orthanc::ImageAccessor& image) const |
179 { | 179 { |
180 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | 180 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); |
181 } | 181 } |
182 | 182 |
183 virtual ISceneLayer* CreateFromDicomImage(const Orthanc::ImageAccessor& frame, | 183 virtual TextureBaseSceneLayer* CreateTextureFromDicom(const Orthanc::ImageAccessor& frame, |
184 const DicomInstanceParameters& parameters) const | 184 const DicomInstanceParameters& parameters) const |
185 { | 185 { |
186 return parameters.CreateTexture(frame); | 186 return parameters.CreateTexture(frame); |
187 } | 187 } |
188 | 188 |
189 virtual void ApplyStyle(ISceneLayer& layer) const | 189 virtual void ApplyStyle(ISceneLayer& layer) const |
207 virtual bool HasGeometry() const = 0; | 207 virtual bool HasGeometry() const = 0; |
208 | 208 |
209 virtual const ImageBuffer3D& GetPixelData() const = 0; | 209 virtual const ImageBuffer3D& GetPixelData() const = 0; |
210 | 210 |
211 virtual const VolumeImageGeometry& GetGeometry() const = 0; | 211 virtual const VolumeImageGeometry& GetGeometry() const = 0; |
212 | |
213 virtual bool HasDicomParameters() const = 0; | |
214 | |
215 virtual const DicomInstanceParameters& GetDicomParameters() const = 0; | |
212 }; | 216 }; |
213 | 217 |
214 | 218 |
215 class IVolumeSlicer : public boost::noncopyable | 219 class IVolumeSlicer : public boost::noncopyable |
216 { | 220 { |
230 // This call can take some time | 234 // This call can take some time |
231 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator, // possibly absent | 235 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator, // possibly absent |
232 const CoordinateSystem3D& cuttingPlane) = 0; | 236 const CoordinateSystem3D& cuttingPlane) = 0; |
233 }; | 237 }; |
234 | 238 |
239 | |
240 class InvalidSlice : public IExtractedSlice | |
241 { | |
242 public: | |
243 virtual bool IsValid() | |
244 { | |
245 return false; | |
246 } | |
247 | |
248 virtual uint64_t GetRevision() | |
249 { | |
250 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
251 } | |
252 | |
253 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator, | |
254 const CoordinateSystem3D& cuttingPlane) | |
255 { | |
256 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
257 } | |
258 }; | |
259 | |
260 | |
235 virtual ~IVolumeSlicer() | 261 virtual ~IVolumeSlicer() |
236 { | 262 { |
237 } | 263 } |
238 | 264 |
239 virtual bool HasVolumeImage() const = 0; | 265 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) = 0; |
240 | |
241 virtual const IVolumeImage& GetVolumeImage() const = 0; | |
242 | |
243 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const = 0; | |
244 }; | 266 }; |
245 | 267 |
246 | 268 |
247 class InvalidExtractedSlice : public IVolumeSlicer::IExtractedSlice | |
248 { | |
249 public: | |
250 virtual bool IsValid() | |
251 { | |
252 return false; | |
253 } | |
254 | |
255 virtual uint64_t GetRevision() | |
256 { | |
257 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
258 } | |
259 | |
260 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator, | |
261 const CoordinateSystem3D& cuttingPlane) | |
262 { | |
263 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
264 } | |
265 }; | |
266 | |
267 | |
268 class DicomVolumeImageOrthogonalSlice : public IVolumeSlicer::IExtractedSlice | 269 class DicomVolumeImageOrthogonalSlice : public IVolumeSlicer::IExtractedSlice |
269 { | 270 { |
270 private: | 271 private: |
271 const ImageBuffer3D& image_; | 272 const IVolumeImage& volume_; |
272 const VolumeImageGeometry& geometry_; | 273 bool valid_; |
273 bool valid_; | 274 VolumeProjection projection_; |
274 VolumeProjection projection_; | 275 unsigned int sliceIndex_; |
275 unsigned int sliceIndex_; | |
276 | 276 |
277 void CheckValid() const | 277 void CheckValid() const |
278 { | 278 { |
279 if (!valid_) | 279 if (!valid_) |
280 { | 280 { |
284 | 284 |
285 protected: | 285 protected: |
286 virtual uint64_t GetRevisionInternal(VolumeProjection projection, | 286 virtual uint64_t GetRevisionInternal(VolumeProjection projection, |
287 unsigned int sliceIndex) const = 0; | 287 unsigned int sliceIndex) const = 0; |
288 | 288 |
289 virtual const DicomInstanceParameters& GetDicomParameters(VolumeProjection projection, | |
290 unsigned int sliceIndex) const = 0; | |
291 | |
292 public: | 289 public: |
293 DicomVolumeImageOrthogonalSlice(const ImageBuffer3D& image, | 290 DicomVolumeImageOrthogonalSlice(const IVolumeImage& volume, |
294 const VolumeImageGeometry& geometry, | |
295 const CoordinateSystem3D& cuttingPlane) : | 291 const CoordinateSystem3D& cuttingPlane) : |
296 image_(image), | 292 volume_(volume) |
297 geometry_(geometry) | 293 { |
298 { | 294 valid_ = (volume_.HasDicomParameters() && |
299 valid_ = geometry_.DetectSlice(projection_, sliceIndex_, cuttingPlane); | 295 volume_.GetGeometry().DetectSlice(projection_, sliceIndex_, cuttingPlane)); |
300 } | 296 } |
301 | 297 |
302 VolumeProjection GetProjection() const | 298 VolumeProjection GetProjection() const |
303 { | 299 { |
304 CheckValid(); | 300 CheckValid(); |
334 } | 330 } |
335 | 331 |
336 std::auto_ptr<TextureBaseSceneLayer> texture; | 332 std::auto_ptr<TextureBaseSceneLayer> texture; |
337 | 333 |
338 { | 334 { |
339 const DicomInstanceParameters& parameters = GetDicomParameters(projection_, sliceIndex_); | 335 const DicomInstanceParameters& parameters = volume_.GetDicomParameters(); |
340 ImageBuffer3D::SliceReader reader(image_, projection_, sliceIndex_); | 336 ImageBuffer3D::SliceReader reader(volume_.GetPixelData(), projection_, sliceIndex_); |
341 texture.reset(dynamic_cast<TextureBaseSceneLayer*> | 337 texture.reset(dynamic_cast<TextureBaseSceneLayer*> |
342 (configurator->CreateFromDicomImage(reader.GetAccessor(), parameters))); | 338 (configurator->CreateTextureFromDicom(reader.GetAccessor(), parameters))); |
343 } | 339 } |
344 | 340 |
345 const CoordinateSystem3D& system = geometry_.GetProjectionGeometry(projection_); | 341 const CoordinateSystem3D& system = volume_.GetGeometry().GetProjectionGeometry(projection_); |
346 | 342 |
347 double x0, y0, x1, y1; | 343 double x0, y0, x1, y1; |
348 cuttingPlane.ProjectPoint(x0, y0, system.GetOrigin()); | 344 cuttingPlane.ProjectPoint(x0, y0, system.GetOrigin()); |
349 cuttingPlane.ProjectPoint(x1, y1, system.GetOrigin() + system.GetAxisX()); | 345 cuttingPlane.ProjectPoint(x1, y1, system.GetOrigin() + system.GetAxisX()); |
350 texture->SetOrigin(x0, y0); | 346 texture->SetOrigin(x0, y0); |
355 !LinearAlgebra::IsCloseToZero(dy)) | 351 !LinearAlgebra::IsCloseToZero(dy)) |
356 { | 352 { |
357 texture->SetAngle(atan2(dy, dx)); | 353 texture->SetAngle(atan2(dy, dx)); |
358 } | 354 } |
359 | 355 |
360 Vector tmp = geometry_.GetVoxelDimensions(projection_); | 356 Vector tmp = volume_.GetGeometry().GetVoxelDimensions(projection_); |
361 texture->SetPixelSpacing(tmp[0], tmp[1]); | 357 texture->SetPixelSpacing(tmp[0], tmp[1]); |
362 | 358 |
363 return texture.release(); | 359 return texture.release(); |
364 | 360 |
365 #if 0 | 361 #if 0 |
388 | 384 |
389 | 385 |
390 class VolumeImageBase : public IVolumeImage | 386 class VolumeImageBase : public IVolumeImage |
391 { | 387 { |
392 private: | 388 private: |
393 uint64_t revision_; | 389 uint64_t revision_; |
394 std::auto_ptr<VolumeImageGeometry> geometry_; | 390 std::auto_ptr<VolumeImageGeometry> geometry_; |
395 std::auto_ptr<ImageBuffer3D> image_; | 391 std::auto_ptr<ImageBuffer3D> image_; |
392 std::auto_ptr<DicomInstanceParameters> parameters_; | |
396 | 393 |
397 protected: | 394 protected: |
398 void Finalize() | 395 void Finalize() |
399 { | 396 { |
400 geometry_.reset(); | 397 geometry_.reset(); |
415 image_.reset(new ImageBuffer3D(format, geometry_->GetWidth(), geometry_->GetHeight(), | 412 image_.reset(new ImageBuffer3D(format, geometry_->GetWidth(), geometry_->GetHeight(), |
416 geometry_->GetDepth(), false /* don't compute range */)); | 413 geometry_->GetDepth(), false /* don't compute range */)); |
417 | 414 |
418 revision_ ++; | 415 revision_ ++; |
419 } | 416 } |
417 | |
418 void SetDicomParameters(const DicomInstanceParameters& parameters) | |
419 { | |
420 parameters_.reset(parameters.Clone()); | |
421 revision_ ++; | |
422 } | |
420 | 423 |
421 ImageBuffer3D& GetPixelData() | 424 ImageBuffer3D& GetPixelData() |
422 { | 425 { |
423 return *image_; | 426 return *image_; |
424 } | 427 } |
466 else | 469 else |
467 { | 470 { |
468 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 471 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
469 } | 472 } |
470 } | 473 } |
474 | |
475 virtual bool HasDicomParameters() const | |
476 { | |
477 return parameters_.get() != NULL; | |
478 } | |
479 | |
480 virtual const DicomInstanceParameters& GetDicomParameters() const | |
481 { | |
482 if (HasDicomParameters()) | |
483 { | |
484 return *parameters_; | |
485 } | |
486 else | |
487 { | |
488 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
489 } | |
490 } | |
471 }; | 491 }; |
472 | 492 |
473 | 493 |
474 | 494 |
475 | 495 |
497 // revision of the volume | 517 // revision of the volume |
498 return that_.GetRevision(); | 518 return that_.GetRevision(); |
499 } | 519 } |
500 } | 520 } |
501 | 521 |
502 virtual const DicomInstanceParameters& GetDicomParameters(VolumeProjection projection, | |
503 unsigned int sliceIndex) const | |
504 { | |
505 return that_.GetSliceParameters(projection == VolumeProjection_Axial ? sliceIndex : 0); | |
506 } | |
507 | |
508 public: | 522 public: |
509 ExtractedOrthogonalSlice(const DicomSeriesVolumeImage& that, | 523 ExtractedOrthogonalSlice(const DicomSeriesVolumeImage& that, |
510 const CoordinateSystem3D& plane) : | 524 const CoordinateSystem3D& plane) : |
511 DicomVolumeImageOrthogonalSlice(that.GetPixelData(), that.GetGeometry(), plane), | 525 DicomVolumeImageOrthogonalSlice(that, plane), |
512 that_(that) | 526 that_(that) |
513 { | 527 { |
514 } | 528 } |
515 }; | 529 }; |
516 | 530 |
660 geometry->SetAxialGeometry(slices.GetSliceGeometry(0)); | 674 geometry->SetAxialGeometry(slices.GetSliceGeometry(0)); |
661 geometry->SetVoxelDimensions(parameters.GetPixelSpacingX(), | 675 geometry->SetVoxelDimensions(parameters.GetPixelSpacingX(), |
662 parameters.GetPixelSpacingY(), spacingZ); | 676 parameters.GetPixelSpacingY(), spacingZ); |
663 | 677 |
664 VolumeImageBase::Initialize(geometry.release(), parameters.GetExpectedPixelFormat()); | 678 VolumeImageBase::Initialize(geometry.release(), parameters.GetExpectedPixelFormat()); |
679 VolumeImageBase::SetDicomParameters(parameters); | |
665 } | 680 } |
666 | 681 |
667 GetPixelData().Clear(); | 682 GetPixelData().Clear(); |
668 } | 683 } |
669 | 684 |
808 } | 823 } |
809 | 824 |
810 if (volume_.GetSlicesCount() != 0) | 825 if (volume_.GetSlicesCount() != 0) |
811 { | 826 { |
812 strategy_.reset(new BasicFetchingStrategy(sorter_->CreateSorter( | 827 strategy_.reset(new BasicFetchingStrategy(sorter_->CreateSorter( |
813 static_cast<unsigned int>(volume_.GetSlicesCount())), BEST_QUALITY)); | 828 static_cast<unsigned int>(volume_.GetSlicesCount())), BEST_QUALITY)); |
814 | 829 |
815 assert(simultaneousDownloads_ != 0); | 830 assert(simultaneousDownloads_ != 0); |
816 for (unsigned int i = 0; i < simultaneousDownloads_; i++) | 831 for (unsigned int i = 0; i < simultaneousDownloads_; i++) |
817 { | 832 { |
818 ScheduleNextSliceDownload(); | 833 ScheduleNextSliceDownload(); |
924 oracle_.Schedule(*this, command.release()); | 939 oracle_.Schedule(*this, command.release()); |
925 } | 940 } |
926 } | 941 } |
927 | 942 |
928 | 943 |
929 virtual bool HasVolumeImage() const | 944 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) |
930 { | |
931 return true; | |
932 } | |
933 | |
934 | |
935 virtual const IVolumeImage& GetVolumeImage() const | |
936 { | |
937 return volume_; | |
938 } | |
939 | |
940 | |
941 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const | |
942 { | 945 { |
943 if (volume_.HasGeometry() && | 946 if (volume_.HasGeometry() && |
944 volume_.GetSlicesCount() != 0) | 947 volume_.GetSlicesCount() != 0) |
945 { | 948 { |
946 std::auto_ptr<DicomVolumeImageOrthogonalSlice> slice | 949 std::auto_ptr<DicomVolumeImageOrthogonalSlice> slice |
957 | 960 |
958 return slice.release(); | 961 return slice.release(); |
959 } | 962 } |
960 else | 963 else |
961 { | 964 { |
962 return new InvalidExtractedSlice; | 965 return new IVolumeSlicer::InvalidSlice; |
963 } | 966 } |
964 } | 967 } |
965 }; | 968 }; |
966 | 969 |
967 | 970 |
1123 IOracle& oracle_; | 1126 IOracle& oracle_; |
1124 bool active_; | 1127 bool active_; |
1125 std::string instanceId_; | 1128 std::string instanceId_; |
1126 std::string transferSyntaxUid_; | 1129 std::string transferSyntaxUid_; |
1127 | 1130 |
1128 std::auto_ptr<DicomInstanceParameters> dicom_; | |
1129 | |
1130 | 1131 |
1131 const std::string& GetInstanceId() const | 1132 const std::string& GetInstanceId() const |
1132 { | 1133 { |
1133 if (active_) | 1134 if (active_) |
1134 { | 1135 { |
1176 } | 1177 } |
1177 | 1178 |
1178 | 1179 |
1179 void SetGeometry(const Orthanc::DicomMap& dicom) | 1180 void SetGeometry(const Orthanc::DicomMap& dicom) |
1180 { | 1181 { |
1181 dicom_.reset(new DicomInstanceParameters(dicom)); | 1182 DicomInstanceParameters parameters(dicom); |
1182 | 1183 VolumeImageBase::SetDicomParameters(parameters); |
1184 | |
1183 Orthanc::PixelFormat format; | 1185 Orthanc::PixelFormat format; |
1184 if (!dicom_->GetImageInformation().ExtractPixelFormat(format, true)) | 1186 if (!parameters.GetImageInformation().ExtractPixelFormat(format, true)) |
1185 { | 1187 { |
1186 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | 1188 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); |
1187 } | 1189 } |
1188 | 1190 |
1189 double spacingZ; | 1191 double spacingZ; |
1190 switch (dicom_->GetSopClassUid()) | 1192 switch (parameters.GetSopClassUid()) |
1191 { | 1193 { |
1192 case SopClassUid_RTDose: | 1194 case SopClassUid_RTDose: |
1193 spacingZ = dicom_->GetThickness(); | 1195 spacingZ = parameters.GetThickness(); |
1194 break; | 1196 break; |
1195 | 1197 |
1196 default: | 1198 default: |
1197 throw Orthanc::OrthancException( | 1199 throw Orthanc::OrthancException( |
1198 Orthanc::ErrorCode_NotImplemented, | 1200 Orthanc::ErrorCode_NotImplemented, |
1199 "No support for multiframe instances with SOP class UID: " + GetSopClassUid(dicom)); | 1201 "No support for multiframe instances with SOP class UID: " + GetSopClassUid(dicom)); |
1200 } | 1202 } |
1201 | 1203 |
1202 const unsigned int width = dicom_->GetImageInformation().GetWidth(); | 1204 const unsigned int width = parameters.GetImageInformation().GetWidth(); |
1203 const unsigned int height = dicom_->GetImageInformation().GetHeight(); | 1205 const unsigned int height = parameters.GetImageInformation().GetHeight(); |
1204 const unsigned int depth = dicom_->GetImageInformation().GetNumberOfFrames(); | 1206 const unsigned int depth = parameters.GetImageInformation().GetNumberOfFrames(); |
1205 | 1207 |
1206 { | 1208 { |
1207 std::auto_ptr<VolumeImageGeometry> geometry(new VolumeImageGeometry); | 1209 std::auto_ptr<VolumeImageGeometry> geometry(new VolumeImageGeometry); |
1208 geometry->SetSize(width, height, depth); | 1210 geometry->SetSize(width, height, depth); |
1209 geometry->SetAxialGeometry(dicom_->GetGeometry()); | 1211 geometry->SetAxialGeometry(parameters.GetGeometry()); |
1210 geometry->SetVoxelDimensions(dicom_->GetPixelSpacingX(), | 1212 geometry->SetVoxelDimensions(parameters.GetPixelSpacingX(), |
1211 dicom_->GetPixelSpacingY(), | 1213 parameters.GetPixelSpacingY(), |
1212 spacingZ); | 1214 spacingZ); |
1213 VolumeImageBase::Initialize(geometry.release(), format); | 1215 VolumeImageBase::Initialize(geometry.release(), format); |
1214 } | 1216 } |
1215 | 1217 |
1216 GetPixelData().Clear(); | 1218 GetPixelData().Clear(); |
1306 unsigned int sliceIndex) const | 1308 unsigned int sliceIndex) const |
1307 { | 1309 { |
1308 return that_.GetRevision(); | 1310 return that_.GetRevision(); |
1309 } | 1311 } |
1310 | 1312 |
1311 virtual const DicomInstanceParameters& GetDicomParameters(VolumeProjection projection, | |
1312 unsigned int sliceIndex) const | |
1313 { | |
1314 return that_.GetDicomParameters(); | |
1315 } | |
1316 | |
1317 public: | 1313 public: |
1318 ExtractedOrthogonalSlice(const OrthancMultiframeVolumeLoader& that, | 1314 ExtractedOrthogonalSlice(const OrthancMultiframeVolumeLoader& that, |
1319 const CoordinateSystem3D& plane) : | 1315 const CoordinateSystem3D& plane) : |
1320 DicomVolumeImageOrthogonalSlice(that.GetPixelData(), that.GetGeometry(), plane), | 1316 DicomVolumeImageOrthogonalSlice(that, plane), |
1321 that_(that) | 1317 that_(that) |
1322 { | 1318 { |
1323 } | 1319 } |
1324 }; | 1320 }; |
1325 | 1321 |
1336 new Callable<OrthancMultiframeVolumeLoader, OrthancRestApiCommand::SuccessMessage> | 1332 new Callable<OrthancMultiframeVolumeLoader, OrthancRestApiCommand::SuccessMessage> |
1337 (*this, &OrthancMultiframeVolumeLoader::Handle)); | 1333 (*this, &OrthancMultiframeVolumeLoader::Handle)); |
1338 } | 1334 } |
1339 | 1335 |
1340 | 1336 |
1341 virtual bool HasVolumeImage() const | |
1342 { | |
1343 return true; | |
1344 } | |
1345 | |
1346 | |
1347 virtual const IVolumeImage& GetVolumeImage() const | |
1348 { | |
1349 return *this; | |
1350 } | |
1351 | |
1352 | |
1353 const DicomInstanceParameters& GetDicomParameters() const | |
1354 { | |
1355 if (!HasGeometry()) | |
1356 { | |
1357 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
1358 } | |
1359 else | |
1360 { | |
1361 return *dicom_; | |
1362 } | |
1363 } | |
1364 | |
1365 | |
1366 void LoadInstance(const std::string& instanceId) | 1337 void LoadInstance(const std::string& instanceId) |
1367 { | 1338 { |
1368 if (active_) | 1339 if (active_) |
1369 { | 1340 { |
1370 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 1341 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
1390 } | 1361 } |
1391 } | 1362 } |
1392 } | 1363 } |
1393 | 1364 |
1394 | 1365 |
1395 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const | 1366 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) |
1396 { | 1367 { |
1397 if (HasGeometry()) | 1368 if (HasGeometry()) |
1398 { | 1369 { |
1399 return new ExtractedOrthogonalSlice(*this, cuttingPlane); | 1370 return new ExtractedOrthogonalSlice(*this, cuttingPlane); |
1400 } | 1371 } |
1401 else | 1372 else |
1402 { | 1373 { |
1403 return new InvalidExtractedSlice; | 1374 return new IVolumeSlicer::InvalidSlice; |
1404 } | 1375 } |
1405 } | 1376 } |
1406 }; | 1377 }; |
1407 | 1378 |
1408 | 1379 |
1409 | 1380 |
1410 class DicomSeriesVolumeImageReslicer : public IVolumeSlicer | 1381 class VolumeImageReslicer : public IVolumeSlicer |
1411 { | 1382 { |
1412 private: | 1383 private: |
1413 class Slice : public IExtractedSlice | 1384 class Slice : public IExtractedSlice |
1414 { | 1385 { |
1386 private: | |
1387 VolumeImageReslicer& that_; | |
1388 CoordinateSystem3D cuttingPlane_; | |
1389 | |
1415 public: | 1390 public: |
1391 Slice(VolumeImageReslicer& that, | |
1392 const CoordinateSystem3D& cuttingPlane) : | |
1393 that_(that), | |
1394 cuttingPlane_(cuttingPlane) | |
1395 { | |
1396 } | |
1397 | |
1416 virtual bool IsValid() | 1398 virtual bool IsValid() |
1417 { | 1399 { |
1400 return true; | |
1418 } | 1401 } |
1419 | 1402 |
1420 virtual uint64_t GetRevision() | 1403 virtual uint64_t GetRevision() |
1421 { | 1404 { |
1405 return that_.volume_->GetRevision(); | |
1422 } | 1406 } |
1423 | 1407 |
1424 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator, // possibly absent | 1408 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator, // possibly absent |
1425 const CoordinateSystem3D& cuttingPlane) | 1409 const CoordinateSystem3D& cuttingPlane) |
1426 { | 1410 { |
1411 if (configurator == NULL) | |
1412 { | |
1413 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, | |
1414 "Must provide a layer style configurator"); | |
1415 } | |
1416 | |
1417 that_.reslicer_.SetOutputFormat(that_.volume_->GetPixelData().GetFormat()); | |
1418 | |
1419 if (that_.reslicer_.IsSuccess()) | |
1420 { | |
1421 std::auto_ptr<TextureBaseSceneLayer> layer | |
1422 (configurator->CreateTextureFromDicom(that_.reslicer_.GetOutputSlice(), | |
1423 that_.volume_->GetDicomParameters())); | |
1424 if (layer.get() == NULL) | |
1425 { | |
1426 return NULL; | |
1427 } | |
1428 | |
1429 return layer.release(); | |
1430 } | |
1431 else | |
1432 { | |
1433 return NULL; | |
1434 } | |
1427 } | 1435 } |
1428 }; | 1436 }; |
1429 | 1437 |
1430 VolumeReslicer reslicer_; | 1438 boost::shared_ptr<IVolumeImage> volume_; |
1431 boost::shared_ptr<DicomSeriesVolumeImage> image_; | 1439 VolumeReslicer reslicer_; |
1432 | 1440 |
1433 public: | 1441 public: |
1434 DicomSeriesVolumeImageReslicer(const boost::shared_ptr<DicomSeriesVolumeImage>& image) : | 1442 VolumeImageReslicer(const boost::shared_ptr<IVolumeImage>& volume) : |
1435 image_(image) | 1443 volume_(volume) |
1436 { | 1444 { |
1437 } | 1445 if (volume.get() == NULL) |
1438 | 1446 { |
1439 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const | 1447 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
1440 { | 1448 } |
1449 } | |
1450 | |
1451 ImageInterpolation GetInterpolation() const | |
1452 { | |
1453 return reslicer_.GetInterpolation(); | |
1454 } | |
1455 | |
1456 void SetInterpolation(ImageInterpolation interpolation) | |
1457 { | |
1458 reslicer_.SetInterpolation(interpolation); | |
1459 } | |
1460 | |
1461 bool IsFastMode() const | |
1462 { | |
1463 return reslicer_.IsFastMode(); | |
1464 } | |
1465 | |
1466 void SetFastMode(bool fast) | |
1467 { | |
1468 reslicer_.EnableFastMode(fast); | |
1469 } | |
1470 | |
1471 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) | |
1472 { | |
1473 if (volume_->HasGeometry()) | |
1474 { | |
1475 return new Slice(*this, cuttingPlane); | |
1476 } | |
1477 else | |
1478 { | |
1479 return new IVolumeSlicer::InvalidSlice; | |
1480 } | |
1441 } | 1481 } |
1442 }; | 1482 }; |
1443 | 1483 |
1444 | 1484 |
1445 | 1485 |
1608 NativeApplicationContext& that_; | 1648 NativeApplicationContext& that_; |
1609 boost::shared_lock<boost::shared_mutex> lock_; | 1649 boost::shared_lock<boost::shared_mutex> lock_; |
1610 | 1650 |
1611 public: | 1651 public: |
1612 ReaderLock(NativeApplicationContext& that) : | 1652 ReaderLock(NativeApplicationContext& that) : |
1613 that_(that), | 1653 that_(that), |
1614 lock_(that.mutex_) | 1654 lock_(that.mutex_) |
1615 { | 1655 { |
1616 } | 1656 } |
1617 }; | 1657 }; |
1618 | 1658 |
1619 | 1659 |
1623 NativeApplicationContext& that_; | 1663 NativeApplicationContext& that_; |
1624 boost::unique_lock<boost::shared_mutex> lock_; | 1664 boost::unique_lock<boost::shared_mutex> lock_; |
1625 | 1665 |
1626 public: | 1666 public: |
1627 WriterLock(NativeApplicationContext& that) : | 1667 WriterLock(NativeApplicationContext& that) : |
1628 that_(that), | 1668 that_(that), |
1629 lock_(that.mutex_) | 1669 lock_(that.mutex_) |
1630 { | 1670 { |
1631 } | 1671 } |
1632 | 1672 |
1633 MessageBroker& GetBroker() | 1673 MessageBroker& GetBroker() |
1634 { | 1674 { |
1690 | 1730 |
1691 void Handle(const OrthancStone::IVolumeImage::GeometryReadyMessage& message) | 1731 void Handle(const OrthancStone::IVolumeImage::GeometryReadyMessage& message) |
1692 { | 1732 { |
1693 printf("Geometry ready\n"); | 1733 printf("Geometry ready\n"); |
1694 | 1734 |
1695 if (source2_->GetSlicer().HasVolumeImage() && | 1735 //plane_ = message.GetOrigin().GetGeometry().GetSagittalGeometry(); |
1696 &source2_->GetSlicer().GetVolumeImage() == &message.GetOrigin()) | 1736 //plane_ = message.GetOrigin().GetGeometry().GetAxialGeometry(); |
1697 { | 1737 plane_ = message.GetOrigin().GetGeometry().GetCoronalGeometry(); |
1698 //plane_ = message.GetOrigin().GetGeometry().GetSagittalGeometry(); | 1738 plane_.SetOrigin(message.GetOrigin().GetGeometry().GetCoordinates(0.5f, 0.5f, 0.5f)); |
1699 //plane_ = message.GetOrigin().GetGeometry().GetAxialGeometry(); | |
1700 plane_ = message.GetOrigin().GetGeometry().GetCoronalGeometry(); | |
1701 plane_.SetOrigin(message.GetOrigin().GetGeometry().GetCoordinates(0.5f, 0.5f, 0.5f)); | |
1702 } | |
1703 | 1739 |
1704 Refresh(); | 1740 Refresh(); |
1705 } | 1741 } |
1706 | 1742 |
1707 | 1743 |
1807 | 1843 |
1808 void SetVolume2(int depth, | 1844 void SetVolume2(int depth, |
1809 const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume, | 1845 const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume, |
1810 OrthancStone::ILayerStyleConfigurator* style) | 1846 OrthancStone::ILayerStyleConfigurator* style) |
1811 { | 1847 { |
1812 dynamic_cast<OrthancStone::IObservable&>(*volume).RegisterObserverCallback | |
1813 (new OrthancStone::Callable | |
1814 <Toto, OrthancStone::IVolumeImage::GeometryReadyMessage>(*this, &Toto::Handle)); | |
1815 | |
1816 source2_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume)); | 1848 source2_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume)); |
1817 | 1849 |
1818 if (style != NULL) | 1850 if (style != NULL) |
1819 { | 1851 { |
1820 source2_->SetConfigurator(style); | 1852 source2_->SetConfigurator(style); |
1836 loader1.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(oracle, lock.GetOracleObservable())); | 1868 loader1.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(oracle, lock.GetOracleObservable())); |
1837 loader2.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(oracle, lock.GetOracleObservable())); | 1869 loader2.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(oracle, lock.GetOracleObservable())); |
1838 loader3.reset(new OrthancStone::OrthancMultiframeVolumeLoader(oracle, lock.GetOracleObservable())); | 1870 loader3.reset(new OrthancStone::OrthancMultiframeVolumeLoader(oracle, lock.GetOracleObservable())); |
1839 } | 1871 } |
1840 | 1872 |
1873 | |
1874 #if 1 | |
1841 toto->SetVolume1(0, loader1, new OrthancStone::GrayscaleStyleConfigurator); | 1875 toto->SetVolume1(0, loader1, new OrthancStone::GrayscaleStyleConfigurator); |
1876 #else | |
1877 { | |
1878 boost::shared_ptr<OrthancStone::IVolumeSlicer> reslicer(new OrthancStone::VolumeImageReslicer(loader1)); | |
1879 toto->SetVolume1(0, reslicer, new OrthancStone::GrayscaleStyleConfigurator); | |
1880 } | |
1881 #endif | |
1882 | |
1842 | 1883 |
1843 { | 1884 { |
1844 std::auto_ptr<OrthancStone::LookupTableStyleConfigurator> config(new OrthancStone::LookupTableStyleConfigurator); | 1885 std::auto_ptr<OrthancStone::LookupTableStyleConfigurator> config(new OrthancStone::LookupTableStyleConfigurator); |
1845 config->SetLookupTable(Orthanc::EmbeddedResources::COLORMAP_HOT); | 1886 config->SetLookupTable(Orthanc::EmbeddedResources::COLORMAP_HOT); |
1846 toto->SetVolume2(1, loader3, config.release()); | 1887 toto->SetVolume2(1, loader3, config.release()); |