# HG changeset patch # User Sebastien Jodogne # Date 1507125094 -7200 # Node ID 063f7f3d9f1474f42958fdec161a1326c3b3b289 # Parent ba83e38cf3ffc0e869afe5708cedc7e107a12749 fix 3d locations of the doses diff -r ba83e38cf3ff -r 063f7f3d9f14 Applications/Samples/SingleVolumeApplication.h --- a/Applications/Samples/SingleVolumeApplication.h Mon Oct 02 22:01:41 2017 +0200 +++ b/Applications/Samples/SingleVolumeApplication.h Wed Oct 04 15:51:34 2017 +0200 @@ -54,10 +54,22 @@ if (image.FitWindowingToRange(s, slice.GetConverter())) { - //printf("ICI: %f => %f\n", s.customWindowCenter_, s.customWindowWidth_); + //printf("Windowing: %f => %f\n", s.customWindowCenter_, s.customWindowWidth_); widget_.SetLayerStyle(layer_, s); } } + + virtual void MouseOver(CairoContext& context, + WorldSceneWidget& widget, + const ViewportGeometry& view, + double x, + double y, + IStatusBar* statusBar) + { + const LayerWidget& w = dynamic_cast(widget); + Vector p = w.GetSlice().MapSliceToWorldCoordinates(x, y); + printf("%f %f %f\n", p[0], p[1], p[2]); + } public: Interactor(OrthancVolumeImage& volume, @@ -185,19 +197,21 @@ #else std::auto_ptr ct(new OrthancVolumeImage(context.GetWebService(), false)); //ct->ScheduleLoadSeries("dd069910-4f090474-7d2bba07-e5c10783-f9e4fb1d"); - //ct->ScheduleLoadSeries("3025d8df-a82f3b00-83942fa3-ee6a6be3-a8bf32e8"); - ct->ScheduleLoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); - + ct->ScheduleLoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); // IBA + //ct->ScheduleLoadSeries("03677739-1d8bca40-db1daf59-d74ff548-7f6fc9c0"); // 0522c0001 TCIA + std::auto_ptr pet(new OrthancVolumeImage(context.GetWebService(), true)); //pet->ScheduleLoadSeries("aabad2e7-80702b5d-e599d26c-4f13398e-38d58a9e"); - //pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); - //pet->ScheduleLoadInstance("337876a1-a68a9718-f15abccd-38faafa1-b99b496a"); - pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); + pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // IBA 1 + //pet->ScheduleLoadInstance("337876a1-a68a9718-f15abccd-38faafa1-b99b496a"); // IBA 2 + //pet->ScheduleLoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // IBA 3 + //pet->ScheduleLoadInstance("269f26f4-0c83eeeb-2e67abbd-5467a40f-f1bec90c"); // 0522c0001 TCIA widget->AddLayer(new VolumeImageSource(*ct)); widget->AddLayer(new VolumeImageSource(*pet)); - context.AddInteractor(new Interactor(*pet, *widget, projection, 1)); + //context.AddInteractor(new Interactor(*pet, *widget, projection, 1)); + context.AddInteractor(new VolumeImageInteractor(*ct, *widget, projection)); context.AddVolume(ct.release()); context.AddVolume(pet.release()); @@ -217,6 +231,9 @@ s.applyLut_ = true; s.lut_ = Orthanc::EmbeddedResources::COLORMAP_JET; s.interpolation_ = ImageInterpolation_Linear; + s.windowing_ = ImageWindowing_Custom; + s.customWindowCenter_ = 0; + s.customWindowWidth_ = 128; widget->SetLayerStyle(1, s); } #endif diff -r ba83e38cf3ff -r 063f7f3d9f14 Framework/Toolbox/DicomFrameConverter.cpp --- a/Framework/Toolbox/DicomFrameConverter.cpp Mon Oct 02 22:01:41 2017 +0200 +++ b/Framework/Toolbox/DicomFrameConverter.cpp Wed Oct 04 15:51:34 2017 +0200 @@ -81,6 +81,26 @@ isRTDose = true; rescaleIntercept_ = 0; rescaleSlope_ = doseGridScaling; + + if (!dicom.ParseInteger32(tmp, Orthanc::DICOM_TAG_BITS_STORED)) + { + // Type 1 tag, must be present + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + switch (tmp) + { + case 16: + expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16; + break; + + case 32: + expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale32; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } } std::string photometric; @@ -100,21 +120,20 @@ // TODO Add more checks, e.g. on the number of bytes per value // (cf. DicomImageInformation.h in Orthanc) - if (isRTDose) - { - expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale32; - } - else if (isColor_) + if (!isRTDose) { - expectedPixelFormat_ = Orthanc::PixelFormat_RGB24; - } - else if (isSigned_) - { - expectedPixelFormat_ = Orthanc::PixelFormat_SignedGrayscale16; - } - else - { - expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16; + if (isColor_) + { + expectedPixelFormat_ = Orthanc::PixelFormat_RGB24; + } + else if (isSigned_) + { + expectedPixelFormat_ = Orthanc::PixelFormat_SignedGrayscale16; + } + else + { + expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16; + } } } diff -r ba83e38cf3ff -r 063f7f3d9f14 Framework/Toolbox/OrthancSlicesLoader.cpp --- a/Framework/Toolbox/OrthancSlicesLoader.cpp Mon Oct 02 22:01:41 2017 +0200 +++ b/Framework/Toolbox/OrthancSlicesLoader.cpp Wed Oct 04 15:51:34 2017 +0200 @@ -277,6 +277,37 @@ (*this, operation.GetSliceIndex(), operation.GetSlice(), operation.GetQuality()); } + + void OrthancSlicesLoader::SortAndFinalizeSlices() + { + bool ok = false; + + if (slices_.GetSliceCount() > 0) + { + Vector normal; + if (slices_.SelectNormal(normal)) + { + slices_.FilterNormal(normal); + slices_.SetNormal(normal); + slices_.Sort(); + ok = true; + } + } + + state_ = State_GeometryReady; + + if (ok) + { + LOG(INFO) << "Loaded a series with " << slices_.GetSliceCount() << " slice(s)"; + userCallback_.NotifyGeometryReady(*this); + } + else + { + LOG(ERROR) << "This series is empty"; + userCallback_.NotifyGeometryError(*this); + } + } + void OrthancSlicesLoader::ParseSeriesGeometry(const void* answer, size_t size) @@ -320,32 +351,7 @@ } } - bool ok = false; - - if (slices_.GetSliceCount() > 0) - { - Vector normal; - if (slices_.SelectNormal(normal)) - { - slices_.FilterNormal(normal); - slices_.SetNormal(normal); - slices_.Sort(); - ok = true; - } - } - - state_ = State_GeometryReady; - - if (ok) - { - LOG(INFO) << "Loaded a series with " << slices_.GetSliceCount() << " slice(s)"; - userCallback_.NotifyGeometryReady(*this); - } - else - { - LOG(ERROR) << "This series is empty"; - userCallback_.NotifyGeometryError(*this); - } + SortAndFinalizeSlices(); } @@ -374,8 +380,6 @@ LOG(INFO) << "Instance " << instanceId << " contains " << frames << " frame(s)"; - state_ = State_GeometryReady; - for (unsigned int frame = 0; frame < frames; frame++) { std::auto_ptr slice(new Slice); @@ -391,7 +395,7 @@ } } - userCallback_.NotifyGeometryReady(*this); + SortAndFinalizeSlices(); } @@ -671,6 +675,7 @@ (new StringImage(Orthanc::PixelFormat_Grayscale32, info.GetWidth(), info.GetHeight(), raw)); + // TODO - Only for big endian for (unsigned int y = 0; y < image->GetHeight(); y++) { uint32_t *p = reinterpret_cast(image->GetRow(y)); @@ -682,6 +687,22 @@ NotifySliceImageSuccess(operation, image); } + else if (info.GetBitsAllocated() == 16 && + info.GetBitsStored() == 16 && + info.GetHighBit() == 15 && + info.GetChannelCount() == 1 && + !info.IsSigned() && + info.GetPhotometricInterpretation() == Orthanc::PhotometricInterpretation_Monochrome2 && + raw.size() == info.GetWidth() * info.GetHeight() * 2) + { + std::auto_ptr image + (new StringImage(Orthanc::PixelFormat_Grayscale16, info.GetWidth(), + info.GetHeight(), raw)); + + // TODO - Big endian ? + + NotifySliceImageSuccess(operation, image); + } else { throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); diff -r ba83e38cf3ff -r 063f7f3d9f14 Framework/Toolbox/OrthancSlicesLoader.h --- a/Framework/Toolbox/OrthancSlicesLoader.h Mon Oct 02 22:01:41 2017 +0200 +++ b/Framework/Toolbox/OrthancSlicesLoader.h Wed Oct 04 15:51:34 2017 +0200 @@ -118,6 +118,8 @@ void ScheduleSliceImageJpeg(const Slice& slice, size_t index, SliceImageQuality quality); + + void SortAndFinalizeSlices(); public: OrthancSlicesLoader(ICallback& callback, diff -r ba83e38cf3ff -r 063f7f3d9f14 Framework/Toolbox/Slice.cpp --- a/Framework/Toolbox/Slice.cpp Mon Oct 02 22:01:41 2017 +0200 +++ b/Framework/Toolbox/Slice.cpp Wed Oct 04 15:51:34 2017 +0200 @@ -69,7 +69,7 @@ std::vector offsets; Orthanc::Toolbox::TokenizeString(offsets, offsetTag, '\\'); - if (frameCount_ == 0 || + if (frameCount_ <= 1 || offsets.size() != frameCount_ || frame >= frameCount_) { @@ -77,9 +77,10 @@ return false; } - double offset0, z; + double offset0, offset1, z; if (!ParseDouble(offset0, offsets[0]) || + !ParseDouble(offset1, offsets[1]) || !ParseDouble(z, offsets[frame])) { LOG(ERROR) << "Invalid syntax"; @@ -93,8 +94,18 @@ } geometry_ = CoordinateSystem3D(geometry_.GetOrigin() + z * geometry_.GetNormal(), + //+ 650 * geometry_.GetAxisX(), geometry_.GetAxisX(), geometry_.GetAxisY()); + + thickness_ = offset1 - offset0; + if (thickness_ < 0) + { + thickness_ = -thickness_; + } + + printf("%d: %f %f %f\n", frame_, geometry_.GetOrigin()[0], geometry_.GetOrigin()[1], geometry_.GetOrigin()[2]); + //printf("%f %f %f\n", pixelSpacingX_, pixelSpacingY_, thickness_); return true; } diff -r ba83e38cf3ff -r 063f7f3d9f14 Framework/dev.h --- a/Framework/dev.h Mon Oct 02 22:01:41 2017 +0200 +++ b/Framework/dev.h Wed Oct 04 15:51:34 2017 +0200 @@ -133,7 +133,7 @@ // z-dimension for voxels spacingZ = 1; } - + for (size_t i = 1; i < loader.GetSliceCount(); i++) { if (!GeometryToolbox::IsNear(spacingZ, GetDistance(loader.GetSlice(i - 1), loader.GetSlice(i)), @@ -156,7 +156,7 @@ image_->SetVoxelDimensions(loader.GetSlice(0).GetPixelSpacingX(), loader.GetSlice(0).GetPixelSpacingY(), spacingZ); image_->Clear(); - + downloadStack_.reset(new DownloadStack(loader.GetSliceCount())); for (unsigned int i = 0; i < 4; i++) // Limit to 4 simultaneous downloads @@ -391,8 +391,6 @@ default: throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - - //sliceThickness_ = 3.0f; // TODO XXXXX } size_t GetSliceCount() const @@ -645,10 +643,10 @@ if (slices_.get() == NULL) { const OrthancVolumeImage& image = dynamic_cast(volume); - + slices_.reset(new VolumeImageGeometry(image, projection_)); SetSlice(slices_->GetSliceCount() / 2); - + widget_.SetDefaultView(); } }