comparison Framework/Inputs/DicomPyramidInstance.cpp @ 330:c42083d50ddf

Added support for DICOM tag "Recommended Absent Pixel CIELab" (0048,0015)
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 18 Oct 2024 13:08:55 +0200
parents 0683312e21ba
children
comparison
equal deleted inserted replaced
329:ae2d769215d2 330:c42083d50ddf
22 22
23 23
24 #include "../PrecompiledHeadersWSI.h" 24 #include "../PrecompiledHeadersWSI.h"
25 #include "DicomPyramidInstance.h" 25 #include "DicomPyramidInstance.h"
26 26
27 #include "../ColorSpaces.h"
27 #include "../DicomToolbox.h" 28 #include "../DicomToolbox.h"
28 #include "../../Resources/Orthanc/Stone/DicomDatasetReader.h" 29 #include "../../Resources/Orthanc/Stone/DicomDatasetReader.h"
29 #include "../../Resources/Orthanc/Stone/FullOrthancDataset.h" 30 #include "../../Resources/Orthanc/Stone/FullOrthancDataset.h"
30 31
31 #include <Logging.h> 32 #include <Logging.h>
49 static const Orthanc::DicomTag DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE(0x0048, 0x021a); 50 static const Orthanc::DicomTag DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE(0x0048, 0x021a);
50 static const Orthanc::DicomTag DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021f); 51 static const Orthanc::DicomTag DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021f);
51 static const Orthanc::DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS(0x0048, 0x0006); 52 static const Orthanc::DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS(0x0048, 0x0006);
52 static const Orthanc::DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS(0x0048, 0x0007); 53 static const Orthanc::DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS(0x0048, 0x0007);
53 static const Orthanc::DicomTag DICOM_TAG_IMAGE_TYPE(0x0008, 0x0008); 54 static const Orthanc::DicomTag DICOM_TAG_IMAGE_TYPE(0x0008, 0x0008);
55 static const Orthanc::DicomTag DICOM_TAG_RECOMMENDED_ABSENT_PIXEL_CIELAB(0x0048, 0x0015);
54 56
55 static ImageCompression DetectImageCompression(OrthancStone::IOrthancConnection& orthanc, 57 static ImageCompression DetectImageCompression(OrthancStone::IOrthancConnection& orthanc,
56 const std::string& instanceId) 58 const std::string& instanceId)
57 { 59 {
58 using namespace OrthancStone; 60 using namespace OrthancStone;
261 { 263 {
262 frames_[i].first = i % w; 264 frames_[i].first = i % w;
263 frames_[i].second = i / w; 265 frames_[i].second = i / w;
264 } 266 }
265 } 267 }
268
269 // New in WSI 2.1
270 std::string background;
271 if (dataset.GetStringValue(background, Orthanc::DicomPath(DICOM_TAG_RECOMMENDED_ABSENT_PIXEL_CIELAB)))
272 {
273 LABColor lab;
274 if (LABColor::DecodeDicomRecommendedAbsentPixelCIELab(lab, background))
275 {
276 XYZColor xyz(lab);
277 sRGBColor srgb(xyz);
278 RGBColor rgb(srgb);
279 hasBackgroundColor_ = true;
280 backgroundRed_ = rgb.GetR();
281 backgroundGreen_ = rgb.GetG();
282 backgroundBlue_ = rgb.GetB();
283 }
284 }
266 } 285 }
267 286
268 287
269 DicomPyramidInstance::DicomPyramidInstance(OrthancStone::IOrthancConnection& orthanc, 288 DicomPyramidInstance::DicomPyramidInstance(OrthancStone::IOrthancConnection& orthanc,
270 const std::string& instanceId, 289 const std::string& instanceId,
271 bool useCache) : 290 bool useCache) :
272 instanceId_(instanceId), 291 instanceId_(instanceId),
273 hasCompression_(false), 292 hasCompression_(false),
274 compression_(ImageCompression_None) // Dummy initialization for serialization 293 compression_(ImageCompression_None), // Dummy initialization for serialization
294 hasBackgroundColor_(false),
295 backgroundRed_(0),
296 backgroundGreen_(0),
297 backgroundBlue_(0)
275 { 298 {
276 if (useCache) 299 if (useCache)
277 { 300 {
278 try 301 try
279 { 302 {
325 static const char* const TILE_HEIGHT = "TileHeight"; 348 static const char* const TILE_HEIGHT = "TileHeight";
326 static const char* const TOTAL_WIDTH = "TotalWidth"; 349 static const char* const TOTAL_WIDTH = "TotalWidth";
327 static const char* const TOTAL_HEIGHT = "TotalHeight"; 350 static const char* const TOTAL_HEIGHT = "TotalHeight";
328 static const char* const PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation"; 351 static const char* const PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation";
329 static const char* const IMAGE_TYPE = "ImageType"; 352 static const char* const IMAGE_TYPE = "ImageType";
353 static const char* const BACKGROUND_COLOR = "BackgroundColor";
330 354
331 355
332 void DicomPyramidInstance::Serialize(std::string& result) const 356 void DicomPyramidInstance::Serialize(std::string& result) const
333 { 357 {
334 Json::Value frames = Json::arrayValue; 358 Json::Value frames = Json::arrayValue;
353 content[TOTAL_WIDTH] = totalWidth_; 377 content[TOTAL_WIDTH] = totalWidth_;
354 content[TOTAL_HEIGHT] = totalHeight_; 378 content[TOTAL_HEIGHT] = totalHeight_;
355 content[PHOTOMETRIC_INTERPRETATION] = Orthanc::EnumerationToString(photometric_); 379 content[PHOTOMETRIC_INTERPRETATION] = Orthanc::EnumerationToString(photometric_);
356 content[IMAGE_TYPE] = imageType_; 380 content[IMAGE_TYPE] = imageType_;
357 381
382 if (hasBackgroundColor_)
383 {
384 Json::Value color = Json::arrayValue;
385 color.append(backgroundRed_);
386 color.append(backgroundGreen_);
387 color.append(backgroundBlue_);
388 content[BACKGROUND_COLOR] = color;
389 }
390
358 #if ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(1, 9, 0) 391 #if ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(1, 9, 0)
359 Orthanc::Toolbox::WriteFastJson(result, content); 392 Orthanc::Toolbox::WriteFastJson(result, content);
360 #else 393 #else
361 Json::FastWriter writer; 394 Json::FastWriter writer;
362 result = writer.write(content); 395 result = writer.write(content);
405 } 438 }
406 439
407 frames_[i].first = f[i][0].asInt(); 440 frames_[i].first = f[i][0].asInt();
408 frames_[i].second = f[i][1].asInt(); 441 frames_[i].second = f[i][1].asInt();
409 } 442 }
443
444 hasBackgroundColor_ = false;
445 if (content.isMember(BACKGROUND_COLOR))
446 {
447 const Json::Value& color = content[BACKGROUND_COLOR];
448 if (color.type() == Json::arrayValue &&
449 color.size() == 3u &&
450 color[0].isUInt() &&
451 color[1].isUInt() &&
452 color[2].isUInt())
453 {
454 hasBackgroundColor_ = true;
455 backgroundRed_ = color[0].asUInt();
456 backgroundGreen_ = color[1].asUInt();
457 backgroundBlue_ = color[2].asUInt();
458 }
459 }
460 }
461
462
463 uint8_t DicomPyramidInstance::GetBackgroundRed() const
464 {
465 if (hasBackgroundColor_)
466 {
467 return backgroundRed_;
468 }
469 else
470 {
471 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
472 }
473 }
474
475
476 uint8_t DicomPyramidInstance::GetBackgroundGreen() const
477 {
478 if (hasBackgroundColor_)
479 {
480 return backgroundGreen_;
481 }
482 else
483 {
484 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
485 }
486 }
487
488
489 uint8_t DicomPyramidInstance::GetBackgroundBlue() const
490 {
491 if (hasBackgroundColor_)
492 {
493 return backgroundBlue_;
494 }
495 else
496 {
497 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
498 }
410 } 499 }
411 } 500 }