Mercurial > hg > orthanc-stone
comparison OrthancStone/Sources/Toolbox/DicomInstanceParameters.cpp @ 2174:2410a171ebfb
refactoring using DicomWebDataset and OrthancNativeDataset
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 22 Oct 2024 21:52:34 +0200 |
parents | 8e3c403cc643 |
children | 43ef60388fa2 |
comparison
equal
deleted
inserted
replaced
2172:239fb2c893c1 | 2174:2410a171ebfb |
---|---|
25 | 25 |
26 #include "../Scene2D/ColorTextureSceneLayer.h" | 26 #include "../Scene2D/ColorTextureSceneLayer.h" |
27 #include "../Scene2D/FloatTextureSceneLayer.h" | 27 #include "../Scene2D/FloatTextureSceneLayer.h" |
28 #include "GeometryToolbox.h" | 28 #include "GeometryToolbox.h" |
29 #include "ImageToolbox.h" | 29 #include "ImageToolbox.h" |
30 #include "OrthancDatasets/DicomDatasetReader.h" | |
31 #include "OrthancDatasets/DicomWebDataset.h" | |
32 #include "OrthancDatasets/OrthancNativeDataset.h" | |
30 | 33 |
31 #include <Images/Image.h> | 34 #include <Images/Image.h> |
32 #include <Images/ImageProcessing.h> | 35 #include <Images/ImageProcessing.h> |
33 #include <Logging.h> | 36 #include <Logging.h> |
34 #include <OrthancException.h> | 37 #include <OrthancException.h> |
229 if (!dicom.HasTag(Orthanc::DICOM_TAG_INSTANCE_NUMBER) || | 232 if (!dicom.HasTag(Orthanc::DICOM_TAG_INSTANCE_NUMBER) || |
230 !dicom.GetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER).ParseInteger32(instanceNumber_)) | 233 !dicom.GetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER).ParseInteger32(instanceNumber_)) |
231 { | 234 { |
232 instanceNumber_ = 0; | 235 instanceNumber_ = 0; |
233 } | 236 } |
234 | 237 } |
238 | |
239 | |
240 void DicomInstanceParameters::InjectSequenceTags(const IDicomDataset& dataset) | |
241 { | |
242 /** | |
243 * Use DICOM tag "SequenceOfUltrasoundRegions" (0018,6011) in | |
244 * order to derive the pixel spacing on ultrasound (US) images | |
245 **/ | |
246 | |
247 static const Orthanc::DicomTag DICOM_TAG_SEQUENCE_OF_ULTRASOUND_REGIONS(0x0018, 0x6011); | |
248 static const Orthanc::DicomTag DICOM_TAG_PHYSICAL_UNITS_X_DIRECTION(0x0018, 0x6024); | |
249 static const Orthanc::DicomTag DICOM_TAG_PHYSICAL_UNITS_Y_DIRECTION(0x0018, 0x6026); | |
250 static const Orthanc::DicomTag DICOM_TAG_PHYSICAL_DELTA_X(0x0018, 0x602c); | |
251 static const Orthanc::DicomTag DICOM_TAG_PHYSICAL_DELTA_Y(0x0018, 0x602e); | |
252 | |
253 DicomDatasetReader reader(dataset); | |
254 | |
255 size_t size; | |
256 | |
257 if (!data_.hasPixelSpacing_ && | |
258 dataset.GetSequenceSize(size, Orthanc::DicomPath(DICOM_TAG_SEQUENCE_OF_ULTRASOUND_REGIONS)) && | |
259 size == 1) | |
260 { | |
261 int directionX, directionY; | |
262 double deltaX, deltaY; | |
263 | |
264 if (reader.GetIntegerValue(directionX, Orthanc::DicomPath(DICOM_TAG_SEQUENCE_OF_ULTRASOUND_REGIONS, | |
265 0, DICOM_TAG_PHYSICAL_UNITS_X_DIRECTION)) && | |
266 reader.GetIntegerValue(directionY, Orthanc::DicomPath(DICOM_TAG_SEQUENCE_OF_ULTRASOUND_REGIONS, | |
267 0, DICOM_TAG_PHYSICAL_UNITS_Y_DIRECTION)) && | |
268 reader.GetDoubleValue(deltaX, Orthanc::DicomPath(DICOM_TAG_SEQUENCE_OF_ULTRASOUND_REGIONS, | |
269 0, DICOM_TAG_PHYSICAL_DELTA_X)) && | |
270 reader.GetDoubleValue(deltaY, Orthanc::DicomPath(DICOM_TAG_SEQUENCE_OF_ULTRASOUND_REGIONS, | |
271 0, DICOM_TAG_PHYSICAL_DELTA_Y)) && | |
272 directionX == 0x0003 && // Centimeters | |
273 directionY == 0x0003) // Centimeters | |
274 { | |
275 // Scene coordinates are expressed in millimeters => multiplication by 10 | |
276 SetPixelSpacing(10.0 * deltaX, 10.0 * deltaY); | |
277 } | |
278 } | |
279 | |
280 | |
281 /** | |
282 * New in Stone Web viewer 2.2: Deal with Philips multiframe | |
283 * (cf. mail from Tomas Kenda on 2021-08-17). This cannot be done | |
284 * in LoadSeriesDetailsFromInstance, as the "Per Frame Functional | |
285 * Groups Sequence" is not available at that point. | |
286 **/ | |
235 | 287 |
236 static const Orthanc::DicomTag DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE(0x5200, 0x9230); | 288 static const Orthanc::DicomTag DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE(0x5200, 0x9230); |
237 static const Orthanc::DicomTag DICOM_TAG_FRAME_VOI_LUT_SEQUENCE_ATTRIBUTE(0x0028, 0x9132); | 289 static const Orthanc::DicomTag DICOM_TAG_FRAME_VOI_LUT_SEQUENCE_ATTRIBUTE(0x0028, 0x9132); |
238 | 290 |
239 const Orthanc::DicomValue* frames = dicom.TestAndGetValue(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE); | 291 if (dataset.GetSequenceSize(size, Orthanc::DicomPath(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE))) |
240 if (frames != NULL && | 292 { |
241 hasNumberOfFrames_ && | 293 data_.perFrameWindowing_.resize(data_.numberOfFrames_); |
242 frames->IsSequence()) | |
243 { | |
244 /** | |
245 * New in Stone Web viewer 2.2: Deal with Philips multiframe | |
246 * (cf. mail from Tomas Kenda on 2021-08-17). This cannot be done | |
247 * in LoadSeriesDetailsFromInstance, as the "Per Frame Functional Groups Sequence" | |
248 * is not available at that point. | |
249 **/ | |
250 | |
251 const Json::Value& sequence = frames->GetSequenceContent(); | |
252 | |
253 perFrameWindowing_.resize(numberOfFrames_); | |
254 | 294 |
255 // This corresponds to "ParsedDicomFile::GetDefaultWindowing()" | 295 // This corresponds to "ParsedDicomFile::GetDefaultWindowing()" |
256 for (Json::ArrayIndex i = 0; i < sequence.size(); i++) | 296 for (size_t i = 0; i < size; i++) |
257 { | 297 { |
258 if (i < numberOfFrames_ && | 298 size_t tmp; |
259 sequence[i].isMember(DICOM_TAG_FRAME_VOI_LUT_SEQUENCE_ATTRIBUTE.Format())) | 299 double center, width; |
300 | |
301 if (dataset.GetSequenceSize(tmp, Orthanc::DicomPath(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE, i, | |
302 DICOM_TAG_FRAME_VOI_LUT_SEQUENCE_ATTRIBUTE)) && | |
303 tmp == 1 && | |
304 reader.GetDoubleValue(center, Orthanc::DicomPath(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE, i, | |
305 DICOM_TAG_FRAME_VOI_LUT_SEQUENCE_ATTRIBUTE, 0, | |
306 Orthanc::DICOM_TAG_WINDOW_CENTER)) && | |
307 reader.GetDoubleValue(width, Orthanc::DicomPath(DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE, i, | |
308 DICOM_TAG_FRAME_VOI_LUT_SEQUENCE_ATTRIBUTE, 0, | |
309 Orthanc::DICOM_TAG_WINDOW_WIDTH))) | |
260 { | 310 { |
261 const Json::Value& v = sequence[i][DICOM_TAG_FRAME_VOI_LUT_SEQUENCE_ATTRIBUTE.Format()]; | 311 data_.perFrameWindowing_[i] = Windowing(center, width); |
262 | |
263 static const char* KEY_VALUE = "Value"; | |
264 | |
265 if (v.isMember(KEY_VALUE) && | |
266 v[KEY_VALUE].type() == Json::arrayValue && | |
267 v[KEY_VALUE].size() >= 1 && | |
268 v[KEY_VALUE][0].isMember(Orthanc::DICOM_TAG_WINDOW_CENTER.Format()) && | |
269 v[KEY_VALUE][0].isMember(Orthanc::DICOM_TAG_WINDOW_WIDTH.Format()) && | |
270 v[KEY_VALUE][0][Orthanc::DICOM_TAG_WINDOW_CENTER.Format()].isMember(KEY_VALUE) && | |
271 v[KEY_VALUE][0][Orthanc::DICOM_TAG_WINDOW_WIDTH.Format()].isMember(KEY_VALUE)) | |
272 { | |
273 const Json::Value& scenter = v[KEY_VALUE][0][Orthanc::DICOM_TAG_WINDOW_CENTER.Format()][KEY_VALUE]; | |
274 const Json::Value& swidth = v[KEY_VALUE][0][Orthanc::DICOM_TAG_WINDOW_WIDTH.Format()][KEY_VALUE]; | |
275 | |
276 double center, width; | |
277 if (scenter.isString() && | |
278 swidth.isString() && | |
279 Orthanc::SerializationToolbox::ParseDouble(center, scenter.asString()) && | |
280 Orthanc::SerializationToolbox::ParseDouble(width, swidth.asString())) | |
281 { | |
282 perFrameWindowing_[i] = Windowing(center, width); | |
283 } | |
284 else if (scenter.isNumeric() && | |
285 swidth.isNumeric()) | |
286 { | |
287 perFrameWindowing_[i] = Windowing(scenter.asDouble(), swidth.asDouble()); | |
288 } | |
289 } | |
290 } | 312 } |
291 } | 313 } |
292 } | 314 } |
315 } | |
316 | |
317 | |
318 DicomInstanceParameters::DicomInstanceParameters(const DicomInstanceParameters& other) : | |
319 data_(other.data_), | |
320 tags_(other.tags_->Clone()) | |
321 { | |
322 } | |
323 | |
324 | |
325 DicomInstanceParameters::DicomInstanceParameters(const Orthanc::DicomMap& dicom) : | |
326 data_(dicom), | |
327 tags_(dicom.Clone()) | |
328 { | |
329 OrthancNativeDataset dataset(dicom); | |
330 InjectSequenceTags(dataset); | |
293 } | 331 } |
294 | 332 |
295 | 333 |
296 double DicomInstanceParameters::GetSliceThickness() const | 334 double DicomInstanceParameters::GetSliceThickness() const |
297 { | 335 { |
812 } | 850 } |
813 | 851 |
814 | 852 |
815 void DicomInstanceParameters::EnrichUsingDicomWeb(const Json::Value& dicomweb) | 853 void DicomInstanceParameters::EnrichUsingDicomWeb(const Json::Value& dicomweb) |
816 { | 854 { |
817 /** | 855 DicomWebDataset dataset(dicomweb); |
818 * Use DICOM tag "SequenceOfUltrasoundRegions" (0018,6011) in | 856 InjectSequenceTags(dataset); |
819 * order to derive the pixel spacing on ultrasound (US) images | |
820 **/ | |
821 | |
822 if (!data_.hasPixelSpacing_) | |
823 { | |
824 const Json::Value* region = LookupDicomWebSingleValue(dicomweb, "00186011", "SQ"); | |
825 if (region != NULL) | |
826 { | |
827 const Json::Value* physicalUnitsXDirection = LookupDicomWebSingleValue(*region, "00186024", "US"); | |
828 const Json::Value* physicalUnitsYDirection = LookupDicomWebSingleValue(*region, "00186026", "US"); | |
829 const Json::Value* physicalDeltaX = LookupDicomWebSingleValue(*region, "0018602C", "FD"); | |
830 const Json::Value* physicalDeltaY = LookupDicomWebSingleValue(*region, "0018602E", "FD"); | |
831 | |
832 if (physicalUnitsXDirection != NULL && | |
833 physicalUnitsYDirection != NULL && | |
834 physicalDeltaX != NULL && | |
835 physicalDeltaY != NULL && | |
836 physicalUnitsXDirection->type() == Json::intValue && | |
837 physicalUnitsYDirection->type() == Json::intValue && | |
838 physicalUnitsXDirection->asInt() == 0x0003 && // Centimeters | |
839 physicalUnitsYDirection->asInt() == 0x0003 && // Centimeters | |
840 physicalDeltaX->isNumeric() && | |
841 physicalDeltaY->isNumeric()) | |
842 { | |
843 // Scene coordinates are expressed in millimeters => multiplication by 10 | |
844 SetPixelSpacing(10.0 * physicalDeltaX->asDouble(), | |
845 10.0 * physicalDeltaY->asDouble()); | |
846 } | |
847 } | |
848 } | |
849 } | 857 } |
850 | 858 |
851 | 859 |
852 CoordinateSystem3D DicomInstanceParameters::GetMultiFrameGeometry() const | 860 CoordinateSystem3D DicomInstanceParameters::GetMultiFrameGeometry() const |
853 { | 861 { |