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;
}