Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# AGAVE : Advanced GPU Accelerated Volume Explorer

AGAVE is a desktop application for viewing multichannel volume data. Several formats are supported, including OME-ZARR 0.4 and 0.5, OME-TIFF and Zeiss .czi files.
AGAVE is a desktop application for viewing multichannel volume data. Several formats are supported, including OME-ZARR 0.4 and 0.5, OME-TIFF, Zeiss .czi, and grayscale DICOM files (.dcm, .dicom, .ima).

The DICOM reader uses DCMTK 3.7.0. It opens single 8-bit or 16-bit grayscale DICOM objects and folders of DICOM slices, including nested study/series folders. Each `SeriesInstanceUID` is a selectable scene. Slices are ordered by image position and orientation, then by instance number or filename when spatial metadata is absent; irregular stacks are rejected. Multi-frame objects become Z stacks. The reader decodes uncompressed, RLE, JPEG, and JPEG-LS transfer syntaxes supported by DCMTK and maps displayed intensity into Agave's unsigned 16-bit volume format. Color images and JPEG 2000 are not yet supported.

![screenshot](https://github.com/user-attachments/assets/b96618f2-7020-4b93-936e-9b32b795ea83)

Expand Down
2 changes: 1 addition & 1 deletion agave_app/agaveGui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ agaveGui::createActions()
m_openUrlAction->setStatusTip(tr("Open an existing volume in the cloud"));
connect(m_openUrlAction, SIGNAL(triggered()), this, SLOT(openUrl()));

m_openDirectoryAction = new QAction(tr("&Open directory (.zarr)"), this);
m_openDirectoryAction = new QAction(tr("&Open directory (.zarr, DICOM)"), this);
m_openDirectoryAction->setShortcuts(QKeySequence::Open);
m_openDirectoryAction->setStatusTip(tr("Open an existing volume from local directory"));
connect(m_openDirectoryAction, SIGNAL(triggered()), this, SLOT(openDirectory()));
Expand Down
24 changes: 23 additions & 1 deletion renderlib/io/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ target_sources(renderlib PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/FileReaderCCP4.h"
"${CMAKE_CURRENT_SOURCE_DIR}/FileReaderCzi.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/FileReaderCzi.h"
"${CMAKE_CURRENT_SOURCE_DIR}/FileReaderDicom.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/FileReaderDicom.h"
"${CMAKE_CURRENT_SOURCE_DIR}/FileReaderImageSequence.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/FileReaderImageSequence.h"
"${CMAKE_CURRENT_SOURCE_DIR}/FileReaderTIFF.cpp"
Expand All @@ -41,6 +43,26 @@ add_subdirectory(libCZI)

# end libczi dependency

# Build only the DCMTK modules needed for grayscale image decoding. The JPEG
# and JPEG-LS modules also link to dcmimage, even for grayscale images.
set(DCMTK_MODULES "ofstd;oflog;oficonv;dcmdata;dcmimgle;dcmimage;dcmjpeg;dcmjpls" CACHE STRING "DCMTK modules" FORCE)
set(DCMTK_DEFAULT_DICT builtin CACHE STRING "Embed the DCMTK dictionary for standalone Agave builds" FORCE)
set(BUILD_APPS OFF CACHE BOOL "Build DCMTK command line applications" FORCE)
set(DCMTK_WITH_OPENSSL OFF CACHE BOOL "DCMTK TLS support" FORCE)
set(DCMTK_WITH_ICONV OFF CACHE BOOL "DCMTK iconv support" FORCE)
set(DCMTK_WITH_ICU OFF CACHE BOOL "DCMTK ICU support" FORCE)
set(DCMTK_WITH_PNG OFF CACHE BOOL "DCMTK PNG support" FORCE)
set(DCMTK_WITH_TIFF OFF CACHE BOOL "DCMTK TIFF support" FORCE)
set(DCMTK_WITH_XML OFF CACHE BOOL "DCMTK XML support" FORCE)
set(DCMTK_WITH_OPENJPEG OFF CACHE BOOL "DCMTK JPEG 2000 support" FORCE)
set(DCMTK_WITH_DOXYGEN OFF CACHE BOOL "DCMTK API documentation" FORCE)
FetchContent_Declare(
dcmtk
URL "https://github.com/DCMTK/dcmtk/archive/refs/tags/DCMTK-3.7.0.tar.gz"
URL_HASH SHA256=5bb3ec8317dc465788bed2ca789e76d03ae5848c9381cce3b14c1a3f8b6aca56
)
FetchContent_MakeAvailable(dcmtk)

# Use these system/vcpkg-provided dependencies instead of tensorstore's bundled ones.
set(TENSORSTORE_USE_SYSTEM_TIFF ON)
set(TENSORSTORE_USE_SYSTEM_ZLIB ON)
Expand All @@ -56,7 +78,7 @@ FetchContent_MakeAvailable(tensorstore)

target_link_libraries(renderlib
libCZI
dcmdata dcmimgle dcmimage dcmjpeg dcmjpls

tensorstore::tensorstore tensorstore::all_drivers
)

11 changes: 9 additions & 2 deletions renderlib/io/FileReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "FileReaderCCP4.h"
#include "FileReaderCzi.h"
#include "FileReaderDicom.h"
#include "FileReaderImageSequence.h"
#include "FileReaderTIFF.h"
#include "FileReaderTestVolume.h"
Expand Down Expand Up @@ -54,16 +55,22 @@ FileReader::getReader(const std::string& filepath, bool isImageSequence)
return new FileReaderTIFF(filepath);
} else if (extstr == ".czi") {
return new FileReaderCzi(filepath);
} else if (extstr == ".dcm" || extstr == ".dicom" || extstr == ".ima") {
return new FileReaderDicom(filepath);
} else if (extstr == ".map" || extstr == ".mrc") {
return new FileReaderCCP4(filepath);
} else if (extstr == ".zarr") {
return new FileReaderZarr(filepath);
}
// if it's a directory, and contains the string zarr anywhere, we assume it's a zarr
// A directory with Zarr metadata is a Zarr store; other directories can
// contain DICOM series, including files without a DICOM extension.
else if (std::filesystem::is_directory(filepath)) {
if (filepath.find("zarr") != std::string::npos) {
const std::filesystem::path directory(filepath);
if (std::filesystem::exists(directory / "zarr.json") || std::filesystem::exists(directory / ".zgroup") ||
std::filesystem::exists(directory / ".zarray") || std::filesystem::exists(directory / ".zattrs")) {
return new FileReaderZarr(filepath);
}
return new FileReaderDicom(filepath);
}

return nullptr;
Expand Down
Loading
Loading