int WsiToDcm::dicomizeTiff()

in src/wsiToDcm.cpp [716:1021]


int WsiToDcm::dicomizeTiff() {
  std::unique_ptr<DcmTags> tags = std::make_unique<DcmTags>();
  if (wsiRequest_->jsonFile.size() > 0) {
    tags->readJsonFile(wsiRequest_->jsonFile);
  }

  int8_t threadsForPool = boost::thread::hardware_concurrency();
  if (wsiRequest_->threads > 0) {
    threadsForPool = std::min(wsiRequest_->threads, threadsForPool);
  }
  std::unique_ptr<SlideLevelDim> slideLevelDim = nullptr;
  std::unique_ptr<AbstractDcmFile> abstractDicomFile = nullptr;
  double levelWidthMM, levelHeightMM;
  if (wsiRequest_->genPyramidFromUntiledImage) {
    BOOST_LOG_TRIVIAL(info) << "Reading untiled image.";
    std::string description = "Image frames generated from "
      " values extracted from un-tiled image (" +
      wsiRequest_->inputFile + ") and ";
    abstractDicomFile = std::move(initUntiledImageIngest());
    slideLevelDim = std::move(initAbstractDicomFileSourceLevelDim(
                                                         description.c_str()));
    // Initalize height and width dimensions directly from file measures
    levelWidthMM = abstractDicomDimensionMM(abstractDicomFile->imageWidthMM(),
                                            largestSlideLevelWidth_,
                                            initialX_);
    levelHeightMM = abstractDicomDimensionMM(abstractDicomFile->imageHeightMM(),
                                            largestSlideLevelHeight_,
                                            initialY_);
  } else {
    // Initalize openslide
    if (initOpenSlide() == "dicom") {
       // DICOM will be read with openslide. Do not init for reading
       // with DCMTK. Perform minor validation and init dimensions, and uid.
       // from DICOM provided.
       std::unique_ptr<AbstractDcmFile> dicom_file =
                                        std::move(initDicomIngest(false));
       levelWidthMM = abstractDicomDimensionMM(dicom_file->imageWidthMM(),
                                            largestSlideLevelWidth_,
                                            initialX_);
       levelHeightMM = abstractDicomDimensionMM(dicom_file->imageHeightMM(),
                                            largestSlideLevelHeight_,
                                            initialY_);
    } else {
      double openslideMPP_X = getOpenSlideDimensionMM("openslide.mpp-x");
      double openslideMPP_Y = getOpenSlideDimensionMM("openslide.mpp-y");
      levelWidthMM = getDimensionMM(largestSlideLevelWidth_ - initialX_,
                                  openslideMPP_X);
      levelHeightMM = getDimensionMM(largestSlideLevelHeight_ - initialY_,
                                   openslideMPP_Y);
    }
  }
  if (largestSlideLevelWidth_ <= initialX_ ||
      largestSlideLevelHeight_ <= initialY_) {
    BOOST_LOG_TRIVIAL(error) << "Input image dimensions are to small.";
    return 1;
  }
  if (wsiRequest_->studyId.size() < 1) {
    char studyIdGenerated[100];
    dcmGenerateUniqueIdentifier(studyIdGenerated, SITE_STUDY_UID_ROOT);
    wsiRequest_->studyId = studyIdGenerated;
  }
  if (wsiRequest_->seriesId.size() < 1) {
    char seriesIdGenerated[100];
    dcmGenerateUniqueIdentifier(seriesIdGenerated, SITE_SERIES_UID_ROOT);
    wsiRequest_->seriesId = seriesIdGenerated;
  }
  std::vector<DownsamplingSlideState> downsampleSlide;
  getSlideDownSamplingLevels(&downsampleSlide,
                             slideLevelDim.get());
  DICOMFileFrameRegionReader higherMagnifcationDicomFiles;
  std::vector<std::unique_ptr<AbstractDcmFile>> generatedDicomFiles;
  if (abstractDicomFile != nullptr) {
    generatedDicomFiles.push_back(std::move(abstractDicomFile));
    higherMagnifcationDicomFiles.setDicomFiles(std::move(generatedDicomFiles),
                                               nullptr);
  }
  clearOpenSlidePtr();
  for (size_t levelIndex = 0;
       levelIndex < downsampleSlide.size();
       ++levelIndex) {
    const bool save_dicom_instance_to_disk = downsampleSlide[levelIndex
                                                      ].saveDicom;
    const bool saveCompressedRaw = downsampleSlide[levelIndex
                                                      ].generateCompressedRaw;
    const int32_t instanceNumber = downsampleSlide[levelIndex].instanceNumber;

    SlideLevelDim *priorSlideLevel;
    if (higherMagnifcationDicomFiles.dicomFileCount() > 0) {
      priorSlideLevel = slideLevelDim.get();
    } else {
      priorSlideLevel = nullptr;
    }
    const int64_t downsample = downsampleSlide[levelIndex].downsample;
    slideLevelDim = std::move(getSlideLevelDim(downsample, priorSlideLevel));
    const int32_t levelToGet  = slideLevelDim->levelToGet;
    const double multiplicator = slideLevelDim->multiplicator;
    const double downsampleOfLevel = slideLevelDim->downsampleOfLevel;
    const int64_t sourceLevelWidth = slideLevelDim->sourceLevelWidth;
    const int64_t sourceLevelHeight = slideLevelDim->sourceLevelHeight;
    const int64_t downsampledLevelWidth = slideLevelDim->downsampledLevelWidth;
    const int64_t downsampledLevelHeight =
                    slideLevelDim->downsampledLevelHeight;
    const int64_t downsampledLevelFrameWidth =
                    slideLevelDim->downsampledLevelFrameWidth;
    const int64_t downsampledLevelFrameHeight =
                    slideLevelDim->downsampledLevelFrameHeight;
    const std::string sourceDerivationDescription =
                                    slideLevelDim->sourceDerivationDescription;

    DCM_Compression levelCompression = slideLevelDim->levelCompression;
    if (downsampledLevelWidth == 0 || downsampledLevelHeight == 0) {
      // frame is being downsampled to nothing skip image generation.
      BOOST_LOG_TRIVIAL(debug) << "Layer has a 0 length dimension. Skipping "
                                  "dcm generation for layer.";
      break;
    }
    //  BOOST_LOG_TRIVIAL(debug) << "Starting Instance Number " <<
    //    instanceNumber << "\n level size: " <<
    //    sourceLevelWidth << ", " << sourceLevelHeight << "\n"
    //    "multiplicator: " << multiplicator << "\n"
    //    "levelToGet: " << levelToGet << "\n"
    //    "downsample: " << downsample << "\n"
    //    "downsampleOfLevel: " << downsampleOfLevel << "\n";
    const int frameX = std::ceil(
                         static_cast<double>(downsampledLevelWidth) /
                         static_cast<double>(downsampledLevelFrameWidth));
    const int frameY = std::ceil(
                         static_cast<double>(downsampledLevelHeight) /
                         static_cast<double>(downsampledLevelFrameHeight));

    if (slideLevelDim->readOpenslide || slideLevelDim->readFromTiff) {
      // If slide level was initalized from openslide or tiff
      // clear higherMagnifcationDicomFiles so
      // level is downsampled from openslide and not
      // prior level if progressiveDownsample is enabled.
      higherMagnifcationDicomFiles.clearDicomFiles();
    }
    BOOST_LOG_TRIVIAL(debug) << "higherMagnifcationDicomFiles " <<
                          higherMagnifcationDicomFiles.dicomFileCount();
    std::vector<std::unique_ptr<Frame>> framesInitalizationData;
    // Preallocate vector space for frames
    framesInitalizationData.reserve(frameX * frameY);
    //  Walk through all frames in selected best layer. Extract frames from
    //  layer FrameDim = (frameWidthDownsampled, frameHeightDownsampled)
    //  which are dim of frame scaled up to the dimension of the layer being
    //  sampled from
    //
    //  Frame objects are processed via a thread pool.
    //  Method in Frame::sliceFrame () downsamples the imaging.
    //
    //  DcmFileDraft Joins threads and combines results and writes dcm file.

    std::unique_ptr<TiffFile> tiffFrameFilePtr = nullptr;
    if (slideLevelDim->readFromTiff) {
      tiffFrameFilePtr = std::make_unique<TiffFile>(*tiffFile_.get(),
                                                    levelToGet);
      if (tiffFrameFilePtr->fileDirectory()->isJpegCompressed()) {
        levelCompression = JPEG;
      } else if (tiffFrameFilePtr->fileDirectory()->isJpeg2kCompressed()) {
        levelCompression = JPEG2000;
      } else {
        BOOST_LOG_TRIVIAL(error) << "Tiff file is not jpeg or jpeg2000 "
                                    "encoded.";
        return 1;
      }
    }
    // Step across destination imaging height.
    for (int64_t downsampledLevelYCoord = 0;
        downsampledLevelYCoord < downsampledLevelHeight;
        downsampledLevelYCoord += downsampledLevelFrameHeight) {
      // back project from destination to source.

      const int64_t sourceLevelYCoord = sourceLevelPixelCoord(
                                          sourceLevelHeight,
                                          downsampledLevelHeight,
                                          downsampledLevelYCoord,
                                          initialY_);
      int64_t sourceHeight;
      if (frameY == 1) {
        // if imaging fits in one frame then sampling dimensions = source dim
        sourceHeight = sourceLevelHeight;
      } else {
        // Differences between start of next frame and current frame
        sourceHeight = sourceLevelPixelCoord(
                         sourceLevelHeight,
                         downsampledLevelHeight,
                         downsampledLevelYCoord + downsampledLevelFrameHeight,
                         initialY_) - sourceLevelYCoord;
      }
      // Step across destination imaging with.
      for (int64_t downsampledLevelXCoord = 0;
          downsampledLevelXCoord < downsampledLevelWidth;
          downsampledLevelXCoord += downsampledLevelFrameWidth) {
        // back project from destination to source.
        const int64_t sourceLevelXCoord = sourceLevelPixelCoord(
                                            sourceLevelWidth,
                                            downsampledLevelWidth,
                                            downsampledLevelXCoord,
                                            initialX_);
        int64_t sourceWidth;
        if (frameX == 1) {
          // if imaging fits in one frame then sampling dimensions = source dim
          sourceWidth = sourceLevelWidth;
        } else {
          // Differences between start of next frame and current frame
          sourceWidth = sourceLevelPixelCoord(
                          sourceLevelWidth,
                          downsampledLevelWidth,
                          downsampledLevelXCoord + downsampledLevelFrameWidth,
                          initialX_) - sourceLevelXCoord;
        }
        // BOOST_LOG_TRIVIAL(debug) << "Sample: " << sourceLevelXCoord <<
        //   ", " << sourceLevelYCoord << " [" << sourceWidth << ", " <<
        //   sourceHeight << "]";
        std::unique_ptr<Frame> frameData;
        if (slideLevelDim->readFromTiff) {
          frameData = std::make_unique<TiffFrame>(tiffFrameFilePtr.get(),
              frameIndexFromLocation(tiffFrameFilePtr.get(), levelToGet,
              sourceLevelXCoord, sourceLevelYCoord), saveCompressedRaw);
        } else if (wsiRequest_->useOpenCVDownsampling) {
          frameData = std::make_unique<OpenCVInterpolationFrame>(
              osptr_.get(), sourceLevelXCoord, sourceLevelYCoord, levelToGet,
              sourceWidth, sourceHeight, downsampledLevelFrameWidth,
              downsampledLevelFrameHeight, levelCompression,
              wsiRequest_->quality, wsiRequest_->jpegSubsampling,
              sourceLevelWidth, sourceLevelHeight, largestSlideLevelWidth_,
              largestSlideLevelHeight_, saveCompressedRaw,
              &higherMagnifcationDicomFiles,
              wsiRequest_->openCVInterpolationMethod);
        } else {
          frameData = std::make_unique<NearestNeighborFrame>(
              osptr_.get(), sourceLevelXCoord, sourceLevelYCoord, levelToGet,
              sourceWidth, sourceHeight, multiplicator,
              downsampledLevelFrameWidth, downsampledLevelFrameHeight,
              levelCompression, wsiRequest_->quality,
              wsiRequest_->jpegSubsampling, saveCompressedRaw,
              &higherMagnifcationDicomFiles);
        }
        if (higherMagnifcationDicomFiles.dicomFileCount() != 0) {
          frameData->incSourceFrameReadCounter();
        }
        framesInitalizationData.push_back(std::move(frameData));
      }
    }
    BOOST_LOG_TRIVIAL(debug) << "Level Frame Count: " <<
                          framesInitalizationData.size();
    boost::asio::thread_pool pool(threadsForPool);
    std::vector<std::unique_ptr<Frame>> framesData;
    if (wsiRequest_->batchLimit == 0) {
      framesData.reserve(frameX * frameY);
    } else {
      framesData.reserve(std::min(frameX * frameY, wsiRequest_->batchLimit));
    }

    const size_t total_frame_count = framesInitalizationData.size();
    for (std::vector<std::unique_ptr<Frame>>::iterator frameData =
                                             framesInitalizationData.begin();
                    frameData != framesInitalizationData.end(); ++frameData) {
      boost::asio::post(
          pool, [frameData = frameData->get()]() { frameData->sliceFrame(); });
      framesData.push_back(std::move(*frameData));
      if (wsiRequest_->batchLimit > 0 &&
          framesData.size() >= wsiRequest_->batchLimit) {
        std::unique_ptr<DcmFileDraft> filedraft =
            std::make_unique<DcmFileDraft>(
                std::move(framesData), wsiRequest_->outputFileMask,
                downsampledLevelWidth, downsampledLevelHeight, instanceNumber,
                wsiRequest_->studyId, wsiRequest_->seriesId,
                wsiRequest_->imageName, levelCompression, wsiRequest_->tiled,
                tags.get(), levelWidthMM, levelHeightMM, downsample,
                &generatedDicomFiles, sourceDerivationDescription,
                save_dicom_instance_to_disk);
        boost::asio::post(pool, [th_filedraft = filedraft.get()]() {
          th_filedraft->saveFile();
        });
        generatedDicomFiles.push_back(std::move(filedraft));
      }
    }
    if (framesData.size() > 0) {
      std::unique_ptr<DcmFileDraft> filedraft = std::make_unique<DcmFileDraft>(
          std::move(framesData), wsiRequest_->outputFileMask,
          downsampledLevelWidth, downsampledLevelHeight, instanceNumber,
          wsiRequest_->studyId, wsiRequest_->seriesId,
          wsiRequest_->imageName, levelCompression,
          wsiRequest_->tiled, tags.get(), levelWidthMM, levelHeightMM,
          downsample, &generatedDicomFiles, sourceDerivationDescription,
          save_dicom_instance_to_disk);
      boost::asio::post(pool, [th_filedraft = filedraft.get()]() {
        th_filedraft->saveFile();
      });
      generatedDicomFiles.push_back(std::move(filedraft));
    }
    pool.join();
    clearOpenSlidePtr();
    if  (!saveCompressedRaw) {
      generatedDicomFiles.clear();
    }
    higherMagnifcationDicomFiles.setDicomFiles(std::move(generatedDicomFiles),
                                               std::move(tiffFrameFilePtr));
    if (wsiRequest_->stopDownsamplingAtSingleFrame && total_frame_count <= 1) {
      break;
    }
  }
  BOOST_LOG_TRIVIAL(info) << "dicomization is done";
  return 0;
}