comparison OrthancServer/Internals/DicomImageDecoder.cpp @ 854:ff530685e46a jpeg

fast version of image copy
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 06 Jun 2014 12:35:08 +0200
parents 839be3022203
children ebc41566f742
comparison
equal deleted inserted replaced
853:839be3022203 854:ff530685e46a
76 =========================================================================*/ 76 =========================================================================*/
77 77
78 78
79 79
80 #include "../../Core/OrthancException.h" 80 #include "../../Core/OrthancException.h"
81 #include "../../Core/ImageFormats/ImageProcessing.h"
81 #include "../../Core/DicomFormat/DicomIntegerPixelAccessor.h" 82 #include "../../Core/DicomFormat/DicomIntegerPixelAccessor.h"
82 #include "../ToDcmtkBridge.h" 83 #include "../ToDcmtkBridge.h"
83 #include "../FromDcmtkBridge.h" 84 #include "../FromDcmtkBridge.h"
84 85
85 #include <glog/logging.h> 86 #include <glog/logging.h>
178 { 179 {
179 assert(slowAccessor_.get() != NULL); 180 assert(slowAccessor_.get() != NULL);
180 return slowAccessor_->GetInformation().GetChannelCount(); 181 return slowAccessor_->GetInformation().GetChannelCount();
181 } 182 }
182 183
183 const DicomIntegerPixelAccessor GetAccessor() const 184 const DicomIntegerPixelAccessor& GetAccessor() const
184 { 185 {
185 assert(slowAccessor_.get() != NULL); 186 assert(slowAccessor_.get() != NULL);
186 return *slowAccessor_; 187 return *slowAccessor_;
187 } 188 }
188 189
311 312
312 313
313 void DicomImageDecoder::SetupImageBuffer(ImageBuffer& target, 314 void DicomImageDecoder::SetupImageBuffer(ImageBuffer& target,
314 DcmDataset& dataset) 315 DcmDataset& dataset)
315 { 316 {
316 OFString value; 317 DicomMap m;
317 318 FromDcmtkBridge::Convert(m, dataset);
318 if (!dataset.findAndGetOFString(ToDcmtkBridge::Convert(DICOM_TAG_COLUMNS), value).good()) 319
319 { 320 DicomImageInformation info(m);
320 throw OrthancException(ErrorCode_BadFileFormat); 321 PixelFormat format;
321 } 322
322 323 if (!info.ExtractPixelFormat(format))
323 unsigned int width = boost::lexical_cast<unsigned int>(value.c_str()); 324 {
324 325 LOG(WARNING) << "Unsupported DICOM image: " << info.GetBitsStored()
325 if (!dataset.findAndGetOFString(ToDcmtkBridge::Convert(DICOM_TAG_ROWS), value).good()) 326 << "bpp, " << info.GetChannelCount() << " channels, "
326 { 327 << (info.IsSigned() ? "signed" : "unsigned");
327 throw OrthancException(ErrorCode_BadFileFormat);
328 }
329
330 unsigned int height = boost::lexical_cast<unsigned int>(value.c_str());
331
332 if (!dataset.findAndGetOFString(ToDcmtkBridge::Convert(DICOM_TAG_BITS_STORED), value).good())
333 {
334 throw OrthancException(ErrorCode_BadFileFormat);
335 }
336
337 unsigned int bitsStored = boost::lexical_cast<unsigned int>(value.c_str());
338
339 if (!dataset.findAndGetOFString(ToDcmtkBridge::Convert(DICOM_TAG_PIXEL_REPRESENTATION), value).good())
340 {
341 throw OrthancException(ErrorCode_BadFileFormat);
342 }
343
344 bool isSigned = (boost::lexical_cast<unsigned int>(value.c_str()) != 0);
345
346 unsigned int samplesPerPixel = 1; // By default
347 if (dataset.findAndGetOFString(ToDcmtkBridge::Convert(DICOM_TAG_SAMPLES_PER_PIXEL), value).good())
348 {
349 samplesPerPixel = boost::lexical_cast<unsigned int>(value.c_str());
350 }
351
352 target.SetHeight(height);
353 target.SetWidth(width);
354
355 if (bitsStored == 8 && samplesPerPixel == 1 && !isSigned)
356 {
357 target.SetFormat(PixelFormat_Grayscale8);
358 }
359 else if (bitsStored == 8 && samplesPerPixel == 3 && !isSigned)
360 {
361 target.SetFormat(PixelFormat_RGB24);
362 }
363 else if (bitsStored >= 9 && bitsStored <= 16 && samplesPerPixel == 1 && !isSigned)
364 {
365 target.SetFormat(PixelFormat_Grayscale16);
366 }
367 else if (bitsStored >= 9 && bitsStored <= 16 && samplesPerPixel == 1 && isSigned)
368 {
369 target.SetFormat(PixelFormat_SignedGrayscale16);
370 }
371 else
372 {
373 LOG(WARNING) << "Unsupported DICOM image: " << bitsStored << "bpp, "
374 << samplesPerPixel << " channels, " << (isSigned ? "signed" : "unsigned");
375 throw OrthancException(ErrorCode_NotImplemented); 328 throw OrthancException(ErrorCode_NotImplemented);
376 } 329 }
330
331 target.SetHeight(info.GetHeight());
332 target.SetWidth(info.GetWidth());
333 target.SetFormat(format);
377 } 334 }
378 335
379 336
380 bool DicomImageDecoder::IsJpegLossless(const DcmDataset& dataset) 337 bool DicomImageDecoder::IsJpegLossless(const DcmDataset& dataset)
381 { 338 {
453 * Resize the target image, with some sanity checks. 410 * Resize the target image, with some sanity checks.
454 **/ 411 **/
455 412
456 SetupImageBuffer(target, dataset); 413 SetupImageBuffer(target, dataset);
457 414
458 if (target.GetWidth() != target.GetWidth() || 415 if (source.GetWidth() != target.GetWidth() ||
459 target.GetHeight() != target.GetHeight()) 416 source.GetHeight() != target.GetHeight())
460 { 417 {
461 throw OrthancException(ErrorCode_InternalError); 418 throw OrthancException(ErrorCode_InternalError);
462 } 419 }
463 420
464 bool ok; 421 bool ok;
488 throw OrthancException(ErrorCode_InternalError); 445 throw OrthancException(ErrorCode_InternalError);
489 } 446 }
490 447
491 448
492 /** 449 /**
450 * If the format of the DICOM buffer is natively supported, use a
451 * direct access to copy its values.
452 **/
453
454 ImageAccessor targetAccessor(target.GetAccessor());
455 const DicomImageInformation& info = source.GetAccessor().GetInformation();
456
457 bool fastVersionSuccess = false;
458 PixelFormat sourceFormat;
459 if (info.ExtractPixelFormat(sourceFormat))
460 {
461 try
462 {
463 ImageAccessor sourceImage;
464 sourceImage.AssignReadOnly(sourceFormat,
465 info.GetWidth(),
466 info.GetHeight(),
467 info.GetWidth() * info.GetBytesPerPixel(),
468 source.GetAccessor().GetPixelData());
469
470 ImageProcessing::Convert(targetAccessor, sourceImage);
471 ImageProcessing::ShiftRight(targetAccessor, info.GetShift());
472 fastVersionSuccess = true;
473 }
474 catch (OrthancException&)
475 {
476 // Unsupported conversion
477 }
478 }
479
480
481 /**
493 * Loop over the DICOM buffer, storing its value into the target 482 * Loop over the DICOM buffer, storing its value into the target
494 * image. 483 * image.
495 **/ 484 **/
496 485
497 ImageAccessor accessor(target.GetAccessor()); 486 if (!fastVersionSuccess)
498 487 {
499 switch (target.GetFormat()) 488 switch (target.GetFormat())
500 { 489 {
501 case PixelFormat_RGB24: 490 case PixelFormat_RGB24:
502 case PixelFormat_RGBA32: 491 case PixelFormat_RGBA32:
503 case PixelFormat_Grayscale8: 492 case PixelFormat_Grayscale8:
504 CopyPixels<uint8_t>(accessor, source.GetAccessor()); 493 CopyPixels<uint8_t>(targetAccessor, source.GetAccessor());
505 break; 494 break;
506 495
507 case PixelFormat_Grayscale16: 496 case PixelFormat_Grayscale16:
508 CopyPixels<uint16_t>(accessor, source.GetAccessor()); 497 CopyPixels<uint16_t>(targetAccessor, source.GetAccessor());
509 break; 498 break;
510 499
511 case PixelFormat_SignedGrayscale16: 500 case PixelFormat_SignedGrayscale16:
512 CopyPixels<int16_t>(accessor, source.GetAccessor()); 501 CopyPixels<int16_t>(targetAccessor, source.GetAccessor());
513 break; 502 break;
514 503
515 default: 504 default:
516 throw OrthancException(ErrorCode_InternalError); 505 throw OrthancException(ErrorCode_InternalError);
506 }
517 } 507 }
518 } 508 }
519 509
520 510
521 #if ORTHANC_JPEG_LOSSLESS_ENABLED == 1 511 #if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
542 throw OrthancException(ErrorCode_BadFileFormat); 532 throw OrthancException(ErrorCode_BadFileFormat);
543 } 533 }
544 534
545 SetupImageBuffer(target, dataset); 535 SetupImageBuffer(target, dataset);
546 536
547 ImageAccessor accessor(target.GetAccessor()); 537 ImageAccessor targetAccessor(target.GetAccessor());
548 538
549 /** 539 /**
550 * The "DJLSLosslessDecoder" and "DJLSNearLosslessDecoder" in DCMTK 540 * The "DJLSLosslessDecoder" and "DJLSNearLosslessDecoder" in DCMTK
551 * are exactly the same, except for the "supportedTransferSyntax()" 541 * are exactly the same, except for the "supportedTransferSyntax()"
552 * virtual function. 542 * virtual function.
558 548
559 Uint32 startFragment = 0; // Default 549 Uint32 startFragment = 0; // Default
560 OFString decompressedColorModel; // Out 550 OFString decompressedColorModel; // Out
561 DJ_RPLossless representationParameter; 551 DJ_RPLossless representationParameter;
562 OFCondition c = decoder.decodeFrame(&representationParameter, pixelSequence, &parameters, 552 OFCondition c = decoder.decodeFrame(&representationParameter, pixelSequence, &parameters,
563 &dataset, frame, startFragment, accessor.GetBuffer(), 553 &dataset, frame, startFragment, targetAccessor.GetBuffer(),
564 accessor.GetSize(), decompressedColorModel); 554 targetAccessor.GetSize(), decompressedColorModel);
565 555
566 if (!c.good()) 556 if (!c.good())
567 { 557 {
568 throw OrthancException(ErrorCode_InternalError); 558 throw OrthancException(ErrorCode_InternalError);
569 } 559 }